1import smartpy as sp
2
3
4@sp.module
5def main():
6 class Bls12_381(sp.Contract):
7 def __init__(self, g1, g2, fr):
8 sp.cast(g1, sp.bls12_381_g1)
9 sp.cast(g2, sp.bls12_381_g2)
10 sp.cast(fr, sp.bls12_381_fr)
11 self.data.g1 = g1
12 self.data.g2 = g2
13 self.data.fr = fr
14 self.data.toIntResult = None
15 self.data.checkResult = None
16
17 @sp.entrypoint
18 def add(self, g1, g2, fr):
19 """ADD: Add two curve points or field elements.
20
21 :: bls12_381_g1 : bls12_381_g1 : 'S -> bls12_381_g1 : 'S
22 :: bls12_381_g2 : bls12_381_g2 : 'S -> bls12_381_g2 : 'S
23 :: bls12_381_fr : bls12_381_fr : 'S -> bls12_381_fr : 'S
24 """
25 self.data.g1 += g1
26 self.data.g2 += g2
27 self.data.fr += fr
28
29 @sp.entrypoint
30 def negate(self):
31 """NEG: Negate a curve point or field element.
32
33 :: bls12_381_g1 : 'S -> bls12_381_g1 : 'S
34 :: bls12_381_g2 : 'S -> bls12_381_g2 : 'S
35 :: bls12_381_fr : 'S -> bls12_381_fr : 'S
36 """
37 self.data.g1 = -self.data.g1
38 self.data.g2 = -self.data.g2
39 self.data.fr = -self.data.fr
40
41 @sp.entrypoint
42 def toInt(self):
43 """Convert a field (the bls12_381_fr element) to type int.
44
45 The returned value is always between 0 (inclusive) and the order of Fr (exclusive).
46
47 :: bls12_381_fr : 'S -> int : 'S
48 """
49 self.data.toIntResult = sp.Some(sp.to_int(self.data.fr))
50
51 @sp.entrypoint
52 def mul(self, fr, i, n):
53 """MUL: Multiply a curve point or field element by a scalar field element.
54
55 Fr elements can be built from naturals by multiplying by the unit of Fr
56 using PUSH bls12_381_fr 1; MUL. Note that the multiplication will be
57 computed using the natural modulo the order of Fr.
58
59 :: bls12_381_g1 : bls12_381_fr : 'S -> bls12_381_g1 : 'S
60 :: bls12_381_g2 : bls12_381_fr : 'S -> bls12_381_g2 : 'S
61 :: bls12_381_fr : bls12_381_fr : 'S -> bls12_381_fr : 'S
62 :: nat : bls12_381_fr : 'S -> bls12_381_fr : 'S
63 :: int : bls12_381_fr : 'S -> bls12_381_fr : 'S
64 :: bls12_381_fr : nat : 'S -> bls12_381_fr : 'S
65 :: bls12_381_fr : int : 'S -> bls12_381_fr : 'S
66 """
67 sp.cast(fr, sp.bls12_381_fr)
68 sp.cast(i, sp.int)
69 sp.cast(n, sp.nat)
70 self.data.g1 = sp.mul(self.data.g1, fr)
71 self.data.g2 = sp.mul(self.data.g2, fr)
72 self.data.fr = sp.mul(self.data.fr, fr)
73 self.data.fr = sp.mul(self.data.fr, i)
74 self.data.fr = sp.mul(self.data.fr, n)
75
76 @sp.entrypoint
77 def pairing_check(self, listOfPairs):
78 """PAIRING_CHECK: Verify that the product of pairings of the given list
79 of points is equal to 1 in Fq12.
80
81 Returns true if the list is empty.
82 Can be used to verify if two pairings P1 and P2 are equal by verifying
83 P1 * P2^(-1) = 1.
84
85 :: list (pair bls12_381_g1 bls12_381_g2) : 'S -> bool : 'S
86 """
87 self.data.checkResult = sp.Some(sp.pairing_check(listOfPairs))
88
89 @sp.entrypoint
90 def conv(self, params):
91 """Non trivial combined operations
92
93 This tests that compiler rewriting doesn't break it.
94 """
95 sp.cast(params, sp.mutez)
96 self.data.fr = sp.mul(
97 sp.fst(sp.ediv(params, sp.mutez(1)).unwrap_some()),
98 sp.bls12_381_fr("0x01"),
99 )
100
101
102@sp.add_test()
103def test():
104 g1 = sp.bls12_381_g1(
105 "0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1"
106 )
107 g2 = sp.bls12_381_g2(
108 "0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801"
109 )
110 fr = sp.bls12_381_fr(
111 "0x2ef123703093cbbbd124e15f2054fa5781ed0b8d092ec3c6e5d76b4ca918a221"
112 )
113
114 sc = sp.test_scenario("BLS12-381", main)
115 c1 = main.Bls12_381(g1=g1, g2=g2, fr=fr)
116
117 sc += c1
118 sc.h2("Basic maths")
119
120 c1.add(g1=g1, g2=g2, fr=fr)
121
122 sc.verify_equal(sp.add(g1, g1), g1 + g1)
123 sc.verify_equal(sp.add(g2, g2), g2 + g2)
124 sc.verify_equal(sp.add(fr, fr), fr + fr)
125
126 c1.negate()
127 c1.toInt()
128
129 sc.verify(
130 c1.data.toIntResult
131 == sp.Some(
132 22010428307259596184589026230464379215728696454789911939124470486372749680037
133 )
134 )
135
136 c1.mul(fr=fr, i=sp.int(5), n=sp.nat(1))
137
138 sc.verify_equal(
139 c1.data.g1,
140 sp.bls12_381_g1(
141 "0x07e3cf9affb773e08cda3f38f9b2b33f1aa234178c17fe4a234b80ec8622861ffb925c4b49595d7e06b7317d377bb89102b3ca77a64fe03fb281212382950e94ad03303e8cead0bfaab99ec00e4741076d7162a1e6b7e273269fc3e6a1b9f0f1"
142 ),
143 )
144 sc.verify_equal(
145 c1.data.g2,
146 sp.bls12_381_g2(
147 "0x1097f5e2e3bffa9f555ffdc44f556f363bb1b5cee17c95c8c834740843c84bbd7d2072cb91c86e55b78749dba3b8a8400b20d78f6ec32e931d0f6202b2bc31af0f38acc3aad291b2cc15c625f26bdcd8ebd09559e723855a00ce308f3cd28c040512aa4787618c0c79bcf95abd570f3debc94ece2a77ab66f332c7440372ccd3648037ba7e814d555f85498d74b3a42e009613a78c1c6ab3c6adf8c1f9c9b51a1c3399ec736526a98c888cb147eb86e49e22d9703571a096bce1a93d152f405c"
148 ),
149 )
150 sc.verify_equal(
151 c1.data.fr,
152 sp.bls12_381_fr(
153 "0xc1255b074cd1d8fb783ef0b09e62886a82747c03e9dd5f9f3f7b2be9e2054834"
154 ),
155 )
156
157 sc.h2("Pairing check")
158
159 # From https://gitlab.com/metastatedev/tezos/-/commit/f10c39e0030e6b4fdd416a62de7b80b6ffdfeacf
160
161 # The verifying key, proof, and inputs are generated from
162 # ZoKrates, modified to use BLS12-381.
163 # The circuit proves knowledge of a square root of 113569.
164
165 input_x = sp.bls12_381_fr(
166 "0xa1bb010000000000000000000000000000000000000000000000000000000000"
167 )
168 input_y = sp.bls12_381_fr(
169 "0x0100000000000000000000000000000000000000000000000000000000000000"
170 )
171 proof_a = sp.bls12_381_g1(
172 "0x0a2841423326ab08f5f406409775e43fa0f9a0b97631fa85d2dd9242507d25059e9cf48b8b98f99a0008671423a148ec106d70637056972ef49fb6f62de2e89ba3682b9972292b6bb4e6f53799a75d2f8001ccfde280d8ac05fc209352236cbd"
173 )
174 proof_b = sp.bls12_381_g2(
175 "0x0fced939fb1ad733f99669f50a383ef632f6d41dfbde434a6715afd5c7dfbb7bc5835e058ad8b590c7b38dd137d0bd0f0e1540f1b45d8aa626c360e2ea484a116243f7c802034de915db6b18d5303946f676e423cbd6046d37a82208d500625a11c7250ccb953a7ee49d704ad14de4b727733cff7cf06875d8b6444f3c0a8cbf0bd980e539c74bd5b37bb15fe816f23407d269193105fda71adf35fae9309d9d46729fcd4685699097a86f0460a2bc8b16293940cabfdcfe0f27e4107e74e90c"
176 )
177 proof_c = sp.bls12_381_g1(
178 "0x0a1fb5a144ca3bdfe4ad0f183cf71dd7fdd28cbef4fcd47b5b419f65186703f62ecaaa1255fa21a6ebdd917ab1f9bd9707de7066865e2ff3875e22088619125a0d4088a622ab42224425ef89a5a149ce2db9c8292b62c7e7aaa7e87f3535304b"
179 )
180
181 vk_gamma_c = sp.bls12_381_g1(
182 "0x063bd6e11e2fcaac1dd8cf68c6b1925a73c3c583e298ed37c41c3715115cf96358a42dbe85a0228cbfd8a6c8a8c54cd015b5ae2860d1cc47f84698d951f14d9448d03f04df2ca0ffe609a2067d6f1a892163a5e05e541279134cae52b1f23c6b"
183 )
184 vk_gamma_b = sp.bls12_381_g1(
185 "0x11f5b5db1da7f1f26217edcce2219d016003af6e5b4d1ca3ad0ff477e354717e658bf16beddc4f4fb76ce39d3327811e0601709dc7ed98c70463cfa1ba33f99851b52b51d1a042d7425bec6277287441c399973632445ce61e7fdd63a70f0f60"
186 )
187 vk_gamma_a = sp.bls12_381_g1(
188 "0x03535a322edd23c55b0ca025e54d450d95df49cc9ee873dcd500e8219f4771264bf159b3b105954d85c7bea8ffe1ea0400c767fe58989366c2837fba76f1b4f46644f19be8ad01e22d894b649e427e0d7e04677ee3919d982f0f96bb0a2f0c34"
189 )
190 vk_delta = sp.bls12_381_g2(
191 "0x10c6d5cdca84fc3c7f33061add256f48e0ab03a697832b338901898b650419eb6f334b28153fb73ad2ecd1cd2ac67053161e9f46cfbdaf7b1132a4654a55162850249650f9b873ac3113fa8c02ef1cd1df481480a4457f351d28f4da89d19fa405c3d77f686dc9a24d2681c9184bf2b091f62e6b24df651a3da8bd7067e14e7908fb02f8955b84af5081614cb5bc49b416d9edf914fc608c441b3f2eb8b6043736ddb9d4e4d62334a23b5625c14ef3e1a7e99258386310221b22d83a5eac035c"
192 )
193 vk_gamma = sp.bls12_381_g2(
194 "0x16dcbd28bff336c2649c7dd1d8391ac7ce6f7ef0124a9db7a4a485a124199eded7ce963c1c18aee1eca9994fe06f192c00e0fb653e1fc737d8d0e2f2f91424ca01f6e6e7c5c04f1c43db03a2900cf6b942aaed6ae77daea6200e094b78c38d770028d531a9d1a118ec23d5a39be7aa6dc28f778da1988856d2235c4a35e81fa48380f050d4baf7ebd7b5e058bf294da916afc34562f097c02a8fcbcf62a00de44f8ae6cfa7acb8ad254e3aeea8b2af12f65b7ee0f54855cb9bd432f3436f238f"
195 )
196 vk_b = sp.bls12_381_g2(
197 "0x0e9383f98df2c6e8b5b45f3876c3384596a0cdbc41349f83c4380bf463a050cdbd1d5057aa483a642e66486d1ed7362a1869e423c3877095e215c17282b11108601166f928043254bbce603bf86f4cec9f2e97e9660e98e4f5bce9b2b3bbacb40946b702ccfcc9a31e0bfc1543a2128edcc95807740a2310ae25eb47b935648e392c58dfae5b5e899d3b970d64e4e9e209741ea8bfedcfcc16b3fd890ff02c788ec0943feaaf01bbb354317acb85fcfd611133e4e563d53ca4e0f50e21cf2e7e"
198 )
199 vk_a = sp.bls12_381_g1(
200 "0x1040577c7d349e332735fc947c868c24a665f812f5dc1e7f60e65e2df80be2267a4b7341ed2287285fccd517acd96d910abba947235c364553aa6445f2f2b3a1a728225a330286ba5197ab87f0edc560d89fc7b623812f7d0d633341726e597a"
201 )
202
203 vk_x = sc.compute(
204 sp.mul(vk_gamma_b, input_x) + sp.mul(vk_gamma_c, input_y) + vk_gamma_a
205 )
206
207 c1.pairing_check(
208 sp.list(
209 [(proof_a, proof_b), (-vk_x, vk_gamma), (-proof_c, vk_delta), (-vk_a, vk_b)]
210 )
211 )
212
213 sc.verify(c1.data.checkResult == sp.Some(True))
214
215 c1.pairing_check([(g1, g2), (g1, g2)])
216
217 sc.verify(c1.data.checkResult == sp.Some(False))
218
219 c1.pairing_check([])
220
221 sc.verify(c1.data.checkResult == sp.Some(True))
222
223 c1.conv(sp.mutez(5))
224
225 sc.verify_equal(
226 c1.data.fr,
227 sp.bls12_381_fr(
228 "0x0500000000000000000000000000000000000000000000000000000000000000"
229 ),
230 )