|
| 1 | +const std = @import("std"); |
| 2 | +const Allocator = std.mem.Allocator; |
| 3 | +const util = @import("util.zig"); |
| 4 | +const BLST_ERROR = util.BLST_ERROR; |
| 5 | +const toBlstError = util.toBlstError; |
| 6 | + |
| 7 | +const c = @cImport({ |
| 8 | + @cInclude("blst.h"); |
| 9 | +}); |
| 10 | + |
| 11 | +const PairingError = error{ BufferTooSmall, DstTooSmall }; |
| 12 | + |
| 13 | +const PTag = enum { |
| 14 | + p1, |
| 15 | + p2, |
| 16 | +}; |
| 17 | + |
| 18 | +const PairingPk = union(PTag) { |
| 19 | + p1: c.blst_p1_affine, |
| 20 | + p2: c.blst_p2_affine, |
| 21 | +}; |
| 22 | + |
| 23 | +const Pairing = struct { |
| 24 | + v: []u8, |
| 25 | + |
| 26 | + /// Rust always use a heap allocation here, but adding an allocator is too complex |
| 27 | + /// instead of that zig provide a buffer that's big enough for the struct to operate on so that: |
| 28 | + /// - it does not have allocator in its api |
| 29 | + /// - can use stack allocation at consumer side |
| 30 | + /// - can reuse memory if it makes sense at consumer side |
| 31 | + pub fn new(buffer: []u8, hash_or_encode: bool, dst: []u8) PairingError!Pairing { |
| 32 | + if (buffer.len < c.blst_pairing_sizeof()) { |
| 33 | + return PairingError.BufferTooSmall; |
| 34 | + } |
| 35 | + |
| 36 | + if (dst.len == 0) { |
| 37 | + return PairingError.DstTooSmall; |
| 38 | + } |
| 39 | + |
| 40 | + const obj = Pairing{ |
| 41 | + .v = buffer[0..c.blst_pairing_sizeof()], |
| 42 | + }; |
| 43 | + obj.init(hash_or_encode, &dst[0]); |
| 44 | + |
| 45 | + return obj; |
| 46 | + } |
| 47 | + |
| 48 | + // Javascript can leverage this api to allocate a Pairing buffer on its own |
| 49 | + pub fn sizeOf() usize { |
| 50 | + return c.blst_pairing_sizeof(); |
| 51 | + } |
| 52 | + |
| 53 | + pub fn init(self: *Pairing, hash_or_encode: bool, dst: []u8) void { |
| 54 | + c.blst_pairing_init(self.ctx(), hash_or_encode, &dst[0], dst.len); |
| 55 | + } |
| 56 | + |
| 57 | + fn ctx(self: *Pairing) *c.blst_pairing { |
| 58 | + const ptr: *c.blst_pairing = @ptrCast(&self.v[0]); |
| 59 | + return ptr; |
| 60 | + } |
| 61 | + |
| 62 | + fn constCtx(self: *const Pairing) *const c.blst_pairing { |
| 63 | + const ptr: *const c.blst_pairing = @ptrCast(&self.v[0]); |
| 64 | + return ptr; |
| 65 | + } |
| 66 | + |
| 67 | + pub fn aggregateG1(self: *Pairing, pk: *const c.blst_p1_affine, pk_validate: bool, sig: *const c.blst_p2_affine, sig_groupcheck: bool, msg: []u8, aug: ?[]u8) BLST_ERROR!void { |
| 68 | + const aug_ptr = if (aug != null and aug.len > 0) &aug[0] else null; |
| 69 | + const aug_len = if (aug != null) aug.len else null; |
| 70 | + |
| 71 | + const res = c.blst_pairing_chk_n_aggr_pk_in_g1(self.ctx, pk, pk_validate, sig, sig_groupcheck, &msg[0], msg.len, aug_ptr, aug_len); |
| 72 | + |
| 73 | + const err = toBlstError(res); |
| 74 | + if (err != null) { |
| 75 | + return err; |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + pub fn aggregateG2(self: *Pairing, pk: *const c.blst_p2_affine, pk_validate: bool, sig: *const c.blst_p1_affine, sig_groupcheck: bool, msg: []u8, aug: ?[]u8) BLST_ERROR!void { |
| 80 | + const aug_ptr = if (aug != null and aug.len > 0) &aug[0] else null; |
| 81 | + const aug_len = if (aug != null) aug.len else null; |
| 82 | + |
| 83 | + const res = c.blst_pairing_chk_n_aggr_pk_in_g2(self.ctx, pk, pk_validate, sig, sig_groupcheck, &msg[0], msg.len, aug_ptr, aug_len); |
| 84 | + |
| 85 | + const err = toBlstError(res); |
| 86 | + if (err != null) { |
| 87 | + return err; |
| 88 | + } |
| 89 | + } |
| 90 | + |
| 91 | + pub fn mulAndAggregateG1(self: *Pairing, pk: *const c.blst_p1_affine, pk_validate: bool, sig: *const c.blst_p2_affine, sig_groupcheck: bool, scalar: []u8, nbits: usize, msg: []u8, aug: ?[]u8) BLST_ERROR!void { |
| 92 | + const aug_ptr = if (aug != null and aug.len > 0) &aug[0] else null; |
| 93 | + const aug_len = if (aug != null) aug.len else null; |
| 94 | + |
| 95 | + const res = c.blst_pairing_chk_n_mul_n_aggr_pk_in_g1(self.ctx, pk, pk_validate, sig, sig_groupcheck, &scalar[0], nbits, &msg[0], msg.len, aug_ptr, aug_len); |
| 96 | + |
| 97 | + const err = toBlstError(res); |
| 98 | + if (err != null) { |
| 99 | + return err; |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + pub fn mulAndAggregateG2(self: *Pairing, pk: *const c.blst_p2_affine, pk_validate: bool, sig: *const c.blst_p1_affine, sig_groupcheck: bool, scalar: []u8, nbits: usize, msg: []u8, aug: ?[]u8) BLST_ERROR!void { |
| 104 | + const aug_ptr = if (aug != null and aug.len > 0) &aug[0] else null; |
| 105 | + const aug_len = if (aug != null) aug.len else null; |
| 106 | + |
| 107 | + const res = c.blst_pairing_chk_n_mul_n_aggr_pk_in_g2(self.ctx, pk, pk_validate, sig, sig_groupcheck, &scalar[0], nbits, &msg[0], msg.len, aug_ptr, aug_len); |
| 108 | + |
| 109 | + const err = toBlstError(res); |
| 110 | + if (err != null) { |
| 111 | + return err; |
| 112 | + } |
| 113 | + } |
| 114 | + |
| 115 | + pub fn aggregatedG1(gtsig: *c.blst_fp12, sig: *const c.blst_p1_affine) void { |
| 116 | + c.blst_aggregated_in_g1(gtsig, sig); |
| 117 | + } |
| 118 | + |
| 119 | + pub fn aggregatedG2(gtsig: *c.blst_fp12, sig: *const c.blst_p2_affine) void { |
| 120 | + c.blst_aggregated_in_g2(gtsig, sig); |
| 121 | + } |
| 122 | + |
| 123 | + pub fn commit(self: *Pairing) void { |
| 124 | + c.blst_pairing_commit(self.ctx()); |
| 125 | + } |
| 126 | + |
| 127 | + pub fn merge(self: *Pairing, ctx1: *const Pairing) BLST_ERROR!void { |
| 128 | + const res = c.blst_pairing_merge(self.ctx(), ctx1.constCtx()); |
| 129 | + |
| 130 | + const err = toBlstError(res); |
| 131 | + if (err != null) { |
| 132 | + return err; |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + pub fn finalVerify(self: *const Pairing, gtsig: ?*const c.blst_fp12) bool { |
| 137 | + const gtsig_ptr = if (gtsig != null) gtsig.? else null; |
| 138 | + return c.blst_pairing_finalverify(self.constCtx(), gtsig_ptr); |
| 139 | + } |
| 140 | + |
| 141 | + pub fn rawAggregate(self: *Pairing, q: *c.blst_p2_affine, p: *c.blst_p1_affine) void { |
| 142 | + c.blst_pairing_raw_aggregate(self.ctx(), q, p); |
| 143 | + } |
| 144 | + |
| 145 | + pub fn asFp12(self: *Pairing) *c.blst_fp12 { |
| 146 | + return c.blst_pairing_as_fp12(self.ctx()); |
| 147 | + } |
| 148 | +}; |
| 149 | + |
| 150 | +test "init Pairing" { |
| 151 | + const allocator = std.testing.allocator; |
| 152 | + const buffer = allocator.alloc(u8, Pairing.sizeOf()); |
| 153 | + defer allocator.free(buffer); |
| 154 | + |
| 155 | + _ = try Pairing.new(buffer, true, "destination"); |
| 156 | +} |
| 157 | + |
| 158 | +test "sizeOf Pairing" { |
| 159 | + // this works on MacOS, adding this test to understand more about the size of Pairing |
| 160 | + std.debug.print("Size of Pairing: {}", .{Pairing.sizeOf()}); |
| 161 | + std.testing.expectEqual(3192, Pairing.sizeOf()); |
| 162 | +} |
0 commit comments