Skip to content

Commit 392948f

Browse files
committed
fixup! Add initial zig bindings.
1 parent fb166da commit 392948f

File tree

4 files changed

+193
-30
lines changed

4 files changed

+193
-30
lines changed

bindings/zig/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# blst for [Zig](https://ziglang.org/)
22

3-
The object-oriented interface is modeled after [C++ interface](../blst.hpp), but for the moment of this writing is a subset of it, sufficient to produce and verify individual signatures.
3+
The object-oriented interface is modeled after [C++ interface](../blst.hpp), but for the moment of this writing is a subset of it, sufficient to produce and verify individual and aggregated signatures.
44

55
## Adding dependency to your project
66

bindings/zig/blst.zig

Lines changed: 94 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,86 @@ pub const SecretKey = struct {
5656
}
5757
};
5858

59+
pub const PT = c.blst_fp12;
60+
61+
pub const Pairing = struct {
62+
ctx: []u64 = &[_]u64{},
63+
allocator: std.mem.Allocator,
64+
65+
pub fn init(hash_or_encode: bool, DST: []const u8,
66+
allocator: std.mem.Allocator) !Pairing {
67+
const nlimbs = (c.blst_pairing_sizeof() + @sizeOf(u64) - 1) / @sizeOf(u64);
68+
const buffer = try allocator.alloc(u64, nlimbs);
69+
70+
c.blst_pairing_init(@ptrCast(buffer), hash_or_encode, &DST[0], DST.len);
71+
72+
return Pairing{
73+
.ctx = buffer,
74+
.allocator = allocator,
75+
};
76+
}
77+
78+
pub fn deinit(self: *Pairing) void {
79+
self.allocator.free(self.ctx);
80+
self.ctx = &[_]u64{};
81+
}
82+
83+
pub fn aggregate(self: *Pairing, pk: anytype, sig: anytype,
84+
msg: []const u8, aug: ?[]const u8) ERROR {
85+
const opt = aug orelse &[_]u8{};
86+
var err: c.BLST_ERROR = undefined;
87+
88+
switch(@TypeOf(pk)) {
89+
*const P1_Affine, *P1_Affine => {
90+
const sigp : [*c]const c.blst_p2_affine = switch(@TypeOf(sig)) {
91+
@TypeOf(null) => null,
92+
else => &sig.point,
93+
};
94+
err = c.blst_pairing_aggregate_pk_in_g1(@ptrCast(self.ctx),
95+
&pk.point, sigp,
96+
@ptrCast(msg), msg.len,
97+
@ptrCast(opt), opt.len);
98+
},
99+
*const P2_Affine, *P2_Affine => {
100+
const sigp : [*c]const c.blst_p1_affine = switch(@TypeOf(sig)) {
101+
@TypeOf(null) => null,
102+
else => &sig.point,
103+
};
104+
err = c.blst_pairing_aggregate_pk_in_g2(@ptrCast(self.ctx),
105+
&pk.point, sigp,
106+
@ptrCast(msg), msg.len,
107+
@ptrCast(opt), opt.len);
108+
},
109+
else => |T| @compileError("expected type '*const blst.P1_Affine' "
110+
++ "or '*const blst.P2_Affine', found '"
111+
++ @typeName(T) ++ "'"),
112+
}
113+
114+
return @as(ERROR, @enumFromInt(err));
115+
}
116+
117+
pub fn commit(self: *Pairing) void {
118+
c.blst_pairing_commit(@ptrCast(self.ctx));
119+
}
120+
121+
pub fn merge(self: *Pairing, second: *const Pairing) ERROR {
122+
return c.blst_pairing_merge(@ptrCast(self.ctx), @ptrCast(second.ctx));
123+
}
124+
125+
pub fn finalverify(self: *Pairing, optional: ?*const PT) bool {
126+
return c.blst_pairing_finalverify(@ptrCast(self.ctx), optional);
127+
}
128+
129+
pub fn raw_aggregate(self: *Pairing, q: *const P2_Affine,
130+
p: *const P1_Affine) void {
131+
c.blst_pairing_raw_aggregate(@ptrCast(self.ctx), q, p);
132+
}
133+
134+
pub fn as_fp12(self: *Pairing) *const PT {
135+
return c.blst_pairing_as_fp12(@ptrCast(self.ctx));
136+
}
137+
};
138+
59139
const FP_BYTES = 384/8;
60140
pub const P1_COMPRESS_BYTES = FP_BYTES;
61141
pub const P1_SERIALIZE_BYTES = FP_BYTES*2;
@@ -79,20 +159,20 @@ pub const P1_Affine = struct {
79159

80160
var ret : P1_Affine = undefined;
81161
const err = ret.deserialize(in);
82-
return if (err == ERROR.SUCCESS) ret else err.as_error();
162+
return if (err == .SUCCESS) ret else err.as_error();
83163
},
84164
}
85165
unreachable;
86166
}
87167

88168
pub fn deserialize(self: *P1_Affine, in: []const u8) ERROR {
89169
if (in.len == 0) {
90-
return ERROR.BAD_ENCODING;
170+
return .BAD_ENCODING;
91171
}
92172
const expected = @as(usize, if (in[0]&0x80 != 0) P1_COMPRESS_BYTES
93173
else P1_SERIALIZE_BYTES);
94174
if (in.len != expected) {
95-
return ERROR.BAD_ENCODING;
175+
return .BAD_ENCODING;
96176
}
97177
const err = c.blst_p1_deserialize(&self.point, &in[0]);
98178
return @as(ERROR, @enumFromInt(err));
@@ -176,20 +256,20 @@ pub const P1 = struct {
176256

177257
var ret : P1 = undefined;
178258
const err = ret.deserialize(in);
179-
return if (err == ERROR.SUCCESS) ret else err.as_error();
259+
return if (err == .SUCCESS) ret else err.as_error();
180260
},
181261
}
182262
unreachable;
183263
}
184264

185265
pub fn deserialize(self: *P1, in: []const u8) ERROR {
186266
if (in.len == 0) {
187-
return ERROR.BAD_ENCODING;
267+
return .BAD_ENCODING;
188268
}
189269
const expected = @as(usize, if (in[0]&0x80 != 0) P1_COMPRESS_BYTES
190270
else P1_SERIALIZE_BYTES);
191271
if (in.len != expected) {
192-
return ERROR.BAD_ENCODING;
272+
return .BAD_ENCODING;
193273
}
194274
const err = c.blst_p1_deserialize(@ptrCast(&self.point), &in[0]);
195275
if (err == c.BLST_SUCCESS) {
@@ -217,9 +297,7 @@ pub const P1 = struct {
217297
}
218298

219299
pub fn dup(self: *const P1) P1 {
220-
return P1 {
221-
.point = self.point,
222-
};
300+
return self.*;
223301
}
224302

225303
pub fn on_curve(self: *const P1) bool {
@@ -300,20 +378,20 @@ pub const P2_Affine = struct {
300378

301379
var ret : P2_Affine = undefined;
302380
const err = ret.deserialize(in);
303-
return if (err == ERROR.SUCCESS) ret else err.as_error();
381+
return if (err == .SUCCESS) ret else err.as_error();
304382
},
305383
}
306384
unreachable;
307385
}
308386

309387
pub fn deserialize(self: *P2_Affine, in: []const u8) ERROR {
310388
if (in.len == 0) {
311-
return ERROR.BAD_ENCODING;
389+
return .BAD_ENCODING;
312390
}
313391
const expected = @as(usize, if (in[0]&0x80 != 0) P2_COMPRESS_BYTES
314392
else P2_SERIALIZE_BYTES);
315393
if (in.len != expected) {
316-
return ERROR.BAD_ENCODING;
394+
return .BAD_ENCODING;
317395
}
318396
const err = c.blst_p2_deserialize(&self.point, &in[0]);
319397
return @as(ERROR, @enumFromInt(err));
@@ -397,20 +475,20 @@ pub const P2 = struct {
397475

398476
var ret : P2 = undefined;
399477
const err = ret.deserialize(in);
400-
return if (err == ERROR.SUCCESS) ret else err.as_error();
478+
return if (err == .SUCCESS) ret else err.as_error();
401479
},
402480
}
403481
unreachable;
404482
}
405483

406484
pub fn deserialize(self: *P2, in: []const u8) ERROR {
407485
if (in.len == 0) {
408-
return ERROR.BAD_ENCODING;
486+
return .BAD_ENCODING;
409487
}
410488
const expected = @as(usize, if (in[0]&0x80 != 0) P2_COMPRESS_BYTES
411489
else P2_SERIALIZE_BYTES);
412490
if (in.len != expected) {
413-
return ERROR.BAD_ENCODING;
491+
return .BAD_ENCODING;
414492
}
415493
const err = c.blst_p2_deserialize(@ptrCast(&self.point), &in[0]);
416494
if (err == c.BLST_SUCCESS) {
@@ -438,9 +516,7 @@ pub const P2 = struct {
438516
}
439517

440518
pub fn dup(self: *const P2) P2 {
441-
return P2 {
442-
.point = self.point,
443-
};
519+
return self.*;
444520
}
445521

446522
pub fn on_curve(self: *const P2) bool {

bindings/zig/generate.py

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,86 @@ def newer(*files):
8888
}
8989
};
9090
91+
pub const PT = c.blst_fp12;
92+
93+
pub const Pairing = struct {
94+
ctx: []u64 = &[_]u64{},
95+
allocator: std.mem.Allocator,
96+
97+
pub fn init(hash_or_encode: bool, DST: []const u8,
98+
allocator: std.mem.Allocator) !Pairing {
99+
const nlimbs = (c.blst_pairing_sizeof() + @sizeOf(u64) - 1) / @sizeOf(u64);
100+
const buffer = try allocator.alloc(u64, nlimbs);
101+
102+
c.blst_pairing_init(@ptrCast(buffer), hash_or_encode, &DST[0], DST.len);
103+
104+
return Pairing{
105+
.ctx = buffer,
106+
.allocator = allocator,
107+
};
108+
}
109+
110+
pub fn deinit(self: *Pairing) void {
111+
self.allocator.free(self.ctx);
112+
self.ctx = &[_]u64{};
113+
}
114+
115+
pub fn aggregate(self: *Pairing, pk: anytype, sig: anytype,
116+
msg: []const u8, aug: ?[]const u8) ERROR {
117+
const opt = aug orelse &[_]u8{};
118+
var err: c.BLST_ERROR = undefined;
119+
120+
switch(@TypeOf(pk)) {
121+
*const P1_Affine, *P1_Affine => {
122+
const sigp : [*c]const c.blst_p2_affine = switch(@TypeOf(sig)) {
123+
@TypeOf(null) => null,
124+
else => &sig.point,
125+
};
126+
err = c.blst_pairing_aggregate_pk_in_g1(@ptrCast(self.ctx),
127+
&pk.point, sigp,
128+
@ptrCast(msg), msg.len,
129+
@ptrCast(opt), opt.len);
130+
},
131+
*const P2_Affine, *P2_Affine => {
132+
const sigp : [*c]const c.blst_p1_affine = switch(@TypeOf(sig)) {
133+
@TypeOf(null) => null,
134+
else => &sig.point,
135+
};
136+
err = c.blst_pairing_aggregate_pk_in_g2(@ptrCast(self.ctx),
137+
&pk.point, sigp,
138+
@ptrCast(msg), msg.len,
139+
@ptrCast(opt), opt.len);
140+
},
141+
else => |T| @compileError("expected type '*const blst.P1_Affine' "
142+
++ "or '*const blst.P2_Affine', found '"
143+
++ @typeName(T) ++ "'"),
144+
}
145+
146+
return @as(ERROR, @enumFromInt(err));
147+
}
148+
149+
pub fn commit(self: *Pairing) void {
150+
c.blst_pairing_commit(@ptrCast(self.ctx));
151+
}
152+
153+
pub fn merge(self: *Pairing, second: *const Pairing) ERROR {
154+
return c.blst_pairing_merge(@ptrCast(self.ctx), @ptrCast(second.ctx));
155+
}
156+
157+
pub fn finalverify(self: *Pairing, optional: ?*const PT) bool {
158+
return c.blst_pairing_finalverify(@ptrCast(self.ctx), optional);
159+
}
160+
161+
pub fn raw_aggregate(self: *Pairing, q: *const P2_Affine,
162+
p: *const P1_Affine) void {
163+
c.blst_pairing_raw_aggregate(@ptrCast(self.ctx), q, p);
164+
}
165+
166+
pub fn as_fp12(self: *Pairing) *const PT {
167+
return c.blst_pairing_as_fp12(@ptrCast(self.ctx));
168+
}
169+
};
170+
91171
const FP_BYTES = 384/8;
92172
pub const P1_COMPRESS_BYTES = FP_BYTES;
93173
pub const P1_SERIALIZE_BYTES = FP_BYTES*2;
@@ -111,20 +191,20 @@ def newer(*files):
111191
112192
var ret : P1_Affine = undefined;
113193
const err = ret.deserialize(in);
114-
return if (err == ERROR.SUCCESS) ret else err.as_error();
194+
return if (err == .SUCCESS) ret else err.as_error();
115195
},
116196
}
117197
unreachable;
118198
}
119199
120200
pub fn deserialize(self: *P1_Affine, in: []const u8) ERROR {
121201
if (in.len == 0) {
122-
return ERROR.BAD_ENCODING;
202+
return .BAD_ENCODING;
123203
}
124204
const expected = @as(usize, if (in[0]&0x80 != 0) P1_COMPRESS_BYTES
125205
else P1_SERIALIZE_BYTES);
126206
if (in.len != expected) {
127-
return ERROR.BAD_ENCODING;
207+
return .BAD_ENCODING;
128208
}
129209
const err = c.blst_p1_deserialize(&self.point, &in[0]);
130210
return @as(ERROR, @enumFromInt(err));
@@ -208,20 +288,20 @@ def newer(*files):
208288
209289
var ret : P1 = undefined;
210290
const err = ret.deserialize(in);
211-
return if (err == ERROR.SUCCESS) ret else err.as_error();
291+
return if (err == .SUCCESS) ret else err.as_error();
212292
},
213293
}
214294
unreachable;
215295
}
216296
217297
pub fn deserialize(self: *P1, in: []const u8) ERROR {
218298
if (in.len == 0) {
219-
return ERROR.BAD_ENCODING;
299+
return .BAD_ENCODING;
220300
}
221301
const expected = @as(usize, if (in[0]&0x80 != 0) P1_COMPRESS_BYTES
222302
else P1_SERIALIZE_BYTES);
223303
if (in.len != expected) {
224-
return ERROR.BAD_ENCODING;
304+
return .BAD_ENCODING;
225305
}
226306
const err = c.blst_p1_deserialize(@ptrCast(&self.point), &in[0]);
227307
if (err == c.BLST_SUCCESS) {
@@ -249,9 +329,7 @@ def newer(*files):
249329
}
250330
251331
pub fn dup(self: *const P1) P1 {
252-
return P1 {
253-
.point = self.point,
254-
};
332+
return self.*;
255333
}
256334
257335
pub fn on_curve(self: *const P1) bool {

bindings/zig/tests.zig

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ test "sign/verify" {
1313

1414
// on the "sender" side...
1515

16-
const pk_for_wire = blst.P1.public_key(&SK).serialize();
16+
const pk_for_wire = (try blst.P1.from(&SK)).serialize();
1717
const sig_for_wire = blst.P2.hash_to(msg, DST, &pk_for_wire).sign_with(&SK).serialize();
1818

1919
// ... and now on the "receiver" side...
@@ -23,7 +23,16 @@ test "sign/verify" {
2323

2424
const ret = sig.core_verify(&pk, true, msg, DST, &pk_for_wire);
2525

26-
try std.testing.expectEqual(ret, blst.ERROR.SUCCESS);
26+
try std.testing.expectEqual(ret, .SUCCESS);
27+
28+
// ... the same thing through Pairing interface.
29+
30+
var ctx = try blst.Pairing.init(true, DST, std.testing.allocator);
31+
defer ctx.deinit();
32+
33+
try std.testing.expectEqual(ctx.aggregate(&pk, &sig, msg, &pk_for_wire), .SUCCESS);
34+
ctx.commit();
35+
try std.testing.expectEqual(ctx.finalverify(null), true);
2736

2837
std.debug.print("OK\n", .{});
2938
}

0 commit comments

Comments
 (0)