|
| 1 | +// git clone -b release https://github.com/herumi/bls-eth-go-binary |
| 2 | +// cd bls-eth-go-binary |
| 3 | +// copy this file into bls |
| 4 | +// zig build-exe main.zig -I bls/include/ -L bls/lib/linux/amd64/ -l bls384_256 -l stdc++ -femit-bin=bls.exe && ./bls.exe |
| 5 | + |
| 6 | +const std = @import("std"); |
| 7 | +const bls = @cImport({ |
| 8 | + @cDefine("BLS_ETH", ""); |
| 9 | + // MCLBN_COMPILED_TIME_VAR should be determined by the definition of BLS_ETH, |
| 10 | + // but since this is not working as intended, we explicitly provide a magic number. |
| 11 | + @cDefine("MCLBN_COMPILED_TIME_VAR", "246"); |
| 12 | + @cInclude("bls/bls384_256.h"); |
| 13 | +}); |
| 14 | + |
| 15 | +pub const MSG_SIZE = 32; |
| 16 | +pub const Message = [MSG_SIZE]u8; |
| 17 | + |
| 18 | +pub const Error = error{ |
| 19 | + CantInit, |
| 20 | + BufferTooSmall, // serialize, getStr |
| 21 | + BufferTooLarge, // setLittleEndianMod, setBigEndianMod |
| 22 | + InvalidFormat, // deserialize, setStr |
| 23 | + InvalidLength, |
| 24 | +}; |
| 25 | + |
| 26 | +pub fn init() !void { |
| 27 | + const res = bls.blsInit(bls.MCL_BLS12_381, bls.MCLBN_COMPILED_TIME_VAR); |
| 28 | + if (res != 0) return Error.CantInit; |
| 29 | +} |
| 30 | + |
| 31 | +pub const SecretKey = struct { |
| 32 | + v_: bls.blsSecretKey, |
| 33 | + pub fn setByCSPRNG(self: *SecretKey) void { |
| 34 | + const ret = bls.mclBnFr_setByCSPRNG(&self.v_.v); |
| 35 | + if (ret != 0) @panic("mclBnFr_setByCSPRNG"); |
| 36 | + } |
| 37 | + pub fn serialize(self: *const SecretKey, buf: []u8) ![]u8 { |
| 38 | + const len: usize = @intCast(bls.blsSecretKeySerialize(buf.ptr, buf.len, &self.v_)); |
| 39 | + if (len == 0) return Error.BufferTooSmall; |
| 40 | + return buf[0..len]; |
| 41 | + } |
| 42 | + pub fn deserialize(self: *SecretKey, buf: []const u8) !void { |
| 43 | + const len: usize = @intCast(bls.blsSecretKeyDeserialize(&self.v_, buf.ptr, buf.len)); |
| 44 | + if (len == 0 or len != buf.len) return Error.InvalidFormat; |
| 45 | + } |
| 46 | + // set (buf[] as littleEndian) % r |
| 47 | + pub fn setLittleEndianMod(self: *SecretKey, buf: []const u8) !void { |
| 48 | + const r = bls.mclBnFr_setLittleEndianMod(&self.v_.v, buf.ptr, buf.len); |
| 49 | + if (r < 0) return Error.BufferTooLarge; |
| 50 | + } |
| 51 | + // set (buf[] as bigEndian) % r |
| 52 | + pub fn setBigEndianMod(self: *SecretKey, buf: []const u8) !void { |
| 53 | + const r = bls.mclBnFr_setBigEndianMod(&self.v_.v, buf.ptr, buf.len); |
| 54 | + if (r < 0) return Error.BufferTooLarge; |
| 55 | + } |
| 56 | + pub fn setStr(self: *SecretKey, s: []const u8, base: i32) !void { |
| 57 | + const r = bls.mclBnFr_setStr(&self.v_.v, s.ptr, s.len, base); |
| 58 | + if (r != 0) return Error.InvalidFormat; |
| 59 | + } |
| 60 | + pub fn getStr(self: *const SecretKey, s: []u8, base: i32) ![]u8 { |
| 61 | + const len: usize = @intCast(bls.mclBnFr_getStr(s.ptr, s.len, &self.v_.v, base)); |
| 62 | + if (len == 0) return Error.BufferTooSmall; |
| 63 | + return s[0..len]; |
| 64 | + } |
| 65 | + pub fn getPublicKey(self: *const SecretKey, pk: *PublicKey) void { |
| 66 | + bls.blsGetPublicKey(&pk.v_, &self.v_); |
| 67 | + } |
| 68 | + pub fn sign(self: *const SecretKey, sig: *Signature, msg: []const u8) void { |
| 69 | + bls.blsSign(&sig.v_, &self.v_, msg.ptr, msg.len); |
| 70 | + } |
| 71 | + pub fn add(self: *SecretKey, rhs: *const SecretKey) void { |
| 72 | + bls.blsSecretKeyAdd(&self.v_, &rhs.v_); |
| 73 | + } |
| 74 | +}; |
| 75 | + |
| 76 | +pub const PublicKey = struct { |
| 77 | + v_: bls.blsPublicKey, |
| 78 | + pub fn serialize(self: *const PublicKey, buf: []u8) ![]u8 { |
| 79 | + const len: usize = @intCast(bls.blsPublicKeySerialize(buf.ptr, buf.len, &self.v_)); |
| 80 | + if (len == 0) return Error.BufferTooSmall; |
| 81 | + return buf[0..len]; |
| 82 | + } |
| 83 | + pub fn deserialize(self: *PublicKey, buf: []const u8) !void { |
| 84 | + const len: usize = @intCast(bls.blsPublicKeyDeserialize(&self.v_, buf.ptr, buf.len)); |
| 85 | + if (len == 0 or len != buf.len) return Error.InvalidFormat; |
| 86 | + } |
| 87 | + pub fn verify(self: *const PublicKey, sig: *const Signature, msg: []const u8) bool { |
| 88 | + return bls.blsVerify(&sig.v_, &self.v_, msg.ptr, msg.len) == 1; |
| 89 | + } |
| 90 | + pub fn add(self: *PublicKey, rhs: *const PublicKey) void { |
| 91 | + bls.blsPublicKeyAdd(&self.v_, &rhs.v_); |
| 92 | + } |
| 93 | +}; |
| 94 | + |
| 95 | +pub const Signature = struct { |
| 96 | + v_: bls.blsSignature, |
| 97 | + // Returns a zero-length slice if the function fails. |
| 98 | + pub fn serialize(self: *const Signature, buf: []u8) ![]u8 { |
| 99 | + const len: usize = @intCast(bls.blsSignatureSerialize(buf.ptr, buf.len, &self.v_)); |
| 100 | + if (len == 0) return Error.BufferTooSmall; |
| 101 | + return buf[0..len]; |
| 102 | + } |
| 103 | + pub fn deserialize(self: *Signature, buf: []const u8) !void { |
| 104 | + const len: usize = @intCast(bls.blsSignatureDeserialize(&self.v_, buf.ptr, buf.len)); |
| 105 | + if (len == 0 or len != buf.len) return Error.InvalidFormat; |
| 106 | + } |
| 107 | + pub fn add(self: *Signature, rhs: *const Signature) void { |
| 108 | + bls.blsSignatureAdd(&self.v_, &rhs.v_); |
| 109 | + } |
| 110 | + pub fn fastAggregateVerify(self: *const Signature, pubVec: []const PublicKey, msg: []const u8) !bool { |
| 111 | + if (pubVec.len == 0) return Error.InvalidLength; |
| 112 | + return bls.blsFastAggregateVerify(&self.v_, &pubVec[0].v_, pubVec.len, msg.ptr, msg.len) == 1; |
| 113 | + } |
| 114 | + pub fn aggregate(self: *Signature, sigVec: []const Signature) !void { |
| 115 | + if (sigVec.len == 0) return Error.InvalidLength; |
| 116 | + bls.blsAggregateSignature(&self.v_, &sigVec[0].v_, sigVec.len); |
| 117 | + } |
| 118 | + // Assume that all msgVec are different.. |
| 119 | + pub fn aggregateVerifyNocheck(self: *const Signature, pubVec: []const PublicKey, msgVec: []const Message) bool { |
| 120 | + const n = pubVec.len; |
| 121 | + if (n == 0 or n != msgVec.len) return Error.InvalidLength; |
| 122 | + return bls.blsAggregateVerifyNoCheck(&self.v_, &pubVec[0].v_, &msgVec[0][0], MSG_SIZE, n) == 1; |
| 123 | + } |
| 124 | + // Check whether all msgVec are different.. |
| 125 | + pub fn aggregateVerify(self: *const Signature, pubVec: []const PublicKey, msgVec: []const Message) !bool { |
| 126 | + const n = pubVec.len; |
| 127 | + if (n == 0 or n != msgVec.len) return Error.InvalidLength; |
| 128 | + if (!try areAllMessageDifferent(msgVec)) return false; |
| 129 | + return bls.blsAggregateVerifyNoCheck(&self.v_, &pubVec[0].v_, &msgVec[0][0], MSG_SIZE, n) == 1; |
| 130 | + } |
| 131 | +}; |
| 132 | + |
| 133 | +const MessageComp = struct { |
| 134 | + pub fn hash(self: @This(), key: Message) u64 { |
| 135 | + _ = self; |
| 136 | + return std.hash.Wyhash.hash(0, &key); |
| 137 | + } |
| 138 | + |
| 139 | + pub fn eql(self: @This(), lhs: Message, rhs: Message) bool { |
| 140 | + _ = self; |
| 141 | + return std.mem.eql(u8, &lhs, &rhs); |
| 142 | + } |
| 143 | +}; |
| 144 | +// Returns true if all msgVec are different. |
| 145 | +pub fn areAllMessageDifferent(msgVec: []const Message) !bool { |
| 146 | + if (msgVec.len <= 1) return true; |
| 147 | + const gpa_allocator = std.heap.page_allocator; |
| 148 | + var set = std.HashMap(Message, void, MessageComp, std.hash_map.default_max_load_percentage).init(gpa_allocator); |
| 149 | + |
| 150 | + defer set.deinit(); |
| 151 | + |
| 152 | + for (msgVec) |msg| { |
| 153 | + const ret = try set.getOrPut(msg); |
| 154 | + if (ret.found_existing) return false; |
| 155 | + } |
| 156 | + return true; |
| 157 | +} |
0 commit comments