Skip to content

Commit 5a62f90

Browse files
committed
zksdk: add type safety to domain seperation
1 parent fd38889 commit 5a62f90

File tree

10 files changed

+171
-125
lines changed

10 files changed

+171
-125
lines changed

src/zksdk/merlin.zig

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! https://merlin.cool/use/protocol.html
44

55
const std = @import("std");
6+
const builtin = @import("builtin");
67
const sig = @import("../sig.zig");
78
const Keccak1600 = std.crypto.core.keccak.KeccakF(1600);
89
const Ed25519 = std.crypto.ecc.Edwards25519;
@@ -186,17 +187,47 @@ pub const Strobe128 = struct {
186187
pub const Transcript = struct {
187188
strobe: Strobe128,
188189

189-
pub fn init(comptime label: []const u8) Transcript {
190-
var transcript: Transcript = .{
191-
.strobe = Strobe128.init("Merlin v1.0"),
192-
};
193-
transcript.appendMessage("dom-sep", label);
190+
const DomainSeperator = enum {
191+
@"zero-ciphertext-instruction",
192+
@"zero-ciphertext-proof",
193+
@"pubkey-validity-instruction",
194+
@"pubkey-proof",
195+
@"percentage-with-cap-proof",
196+
@"percentage-with-cap-instruction",
197+
@"ciphertext-commitment-equality-proof",
198+
@"ciphertext-commitment-equality-instruction",
199+
@"ciphertext-ciphertext-equality-proof",
200+
@"ciphertext-ciphertext-equality-instruction",
201+
202+
@"inner-product",
203+
@"range-proof",
204+
@"batched-range-proof-instruction",
205+
206+
@"validity-proof",
207+
@"batched-validity-proof",
208+
209+
@"grouped-ciphertext-validity-2-handles-instruction",
210+
@"batched-grouped-ciphertext-validity-2-handles-instruction",
211+
212+
@"grouped-ciphertext-validity-3-handles-instruction",
213+
@"batched-grouped-ciphertext-validity-3-handles-instruction",
214+
};
215+
216+
pub fn init(comptime seperator: DomainSeperator) Transcript {
217+
var transcript: Transcript = .{ .strobe = Strobe128.init("Merlin v1.0") };
218+
transcript.appendDomSep(seperator);
219+
return transcript;
220+
}
194221

222+
pub fn initTest(label: []const u8) Transcript {
223+
comptime if (!builtin.is_test) @compileError("should only be used during tests");
224+
var transcript: Transcript = .{ .strobe = Strobe128.init("Merlin v1.0") };
225+
transcript.appendMessage("dom-sep", label);
195226
return transcript;
196227
}
197228

198229
/// NOTE: be very careful with this function, there are only a specific few
199-
/// usages of it. generally speaking, use the a helper function if it exists.
230+
/// usages of it. always use helper functions if possible.
200231
pub fn appendMessage(
201232
self: *Transcript,
202233
comptime label: []const u8,
@@ -209,8 +240,8 @@ pub const Transcript = struct {
209240
self.strobe.ad(message, false);
210241
}
211242

212-
pub fn appendDomSep(self: *Transcript, comptime label: []const u8) void {
213-
self.appendMessage("dom-sep", label);
243+
pub fn appendDomSep(self: *Transcript, comptime seperator: DomainSeperator) void {
244+
self.appendMessage("dom-sep", @tagName(seperator));
214245
}
215246

216247
pub fn challengeBytes(
@@ -289,10 +320,37 @@ pub const Transcript = struct {
289320
std.mem.writeInt(u64, &buffer, x, .little);
290321
self.appendMessage(label, &buffer);
291322
}
323+
324+
pub fn appendHandleDomSep(
325+
self: *Transcript,
326+
comptime mode: enum { batched, unbatched },
327+
comptime handles: enum { two, three },
328+
) void {
329+
self.appendDomSep(switch (mode) {
330+
.batched => .@"batched-validity-proof",
331+
.unbatched => .@"validity-proof",
332+
});
333+
self.appendU64("handles", switch (handles) {
334+
.two => 2,
335+
.three => 3,
336+
});
337+
}
338+
339+
pub fn appendRangeProof(
340+
self: *Transcript,
341+
comptime mode: enum { range, inner },
342+
n: comptime_int,
343+
) void {
344+
self.appendDomSep(switch (mode) {
345+
.range => .@"range-proof",
346+
.inner => .@"inner-product",
347+
});
348+
self.appendU64("n", n);
349+
}
292350
};
293351

294352
test "equivalence" {
295-
var transcript = Transcript.init("test protocol");
353+
var transcript = Transcript.initTest("test protocol");
296354

297355
transcript.appendMessage("some label", "some data");
298356

src/zksdk/range_proof/bulletproofs.zig

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,7 @@ pub fn Proof(bit_size: comptime_int) type {
123123
}
124124
std.debug.assert(nm == bit_size);
125125

126-
transcript.appendDomSep("range-proof");
127-
transcript.appendU64("n", bit_size);
126+
transcript.appendRangeProof(.range, bit_size);
128127

129128
// bit-decompose values and generate their Pedersen vector commitment
130129
const a_blinding: Scalar = .random();
@@ -269,8 +268,7 @@ pub fn Proof(bit_size: comptime_int) type {
269268
) !void {
270269
std.debug.assert(commitments.len == bit_lengths.len);
271270

272-
transcript.appendDomSep("range-proof");
273-
transcript.appendU64("n", bit_size);
271+
transcript.appendRangeProof(.range, bit_size);
274272

275273
try transcript.validateAndAppendPoint("A", self.A);
276274
try transcript.validateAndAppendPoint("S", self.S);
@@ -659,7 +657,7 @@ pub fn Data(bit_size: comptime_int) type {
659657
}
660658

661659
fn newTranscript(self: Context) Transcript {
662-
var transcript = Transcript.init("batched-range-proof-instruction");
660+
var transcript = Transcript.init(.@"batched-range-proof-instruction");
663661
transcript.appendMessage(
664662
"commitments",
665663
std.mem.sliceAsBytes(&self.commitments),
@@ -699,8 +697,8 @@ pub fn genPowers(comptime n: usize, x: Scalar) [n]Scalar {
699697
test "single rangeproof" {
700698
const commitment, const opening = pedersen.initValue(u64, 55);
701699

702-
var creation_transcript = Transcript.init("Test");
703-
var verification_transcript = Transcript.init("Test");
700+
var creation_transcript = Transcript.initTest("Test");
701+
var verification_transcript = Transcript.initTest("Test");
704702

705703
const proof = try Proof(32).init(
706704
&.{55},
@@ -721,8 +719,8 @@ test "aggregated rangeproof" {
721719
const comm2, const opening2 = pedersen.initValue(u64, 77);
722720
const comm3, const opening3 = pedersen.initValue(u64, 99);
723721

724-
var creation_transcript = Transcript.init("Test");
725-
var verification_transcript = Transcript.init("Test");
722+
var creation_transcript = Transcript.initTest("Test");
723+
var verification_transcript = Transcript.initTest("Test");
726724

727725
const proof = try Proof(128).init(
728726
&.{ 55, 77, 99 },
@@ -753,7 +751,7 @@ test "proof string" {
753751
const proof = try Proof(128).fromBase64(proof_string);
754752
// zig fmt: on
755753

756-
var verification_transcript = Transcript.init("Test");
754+
var verification_transcript = Transcript.initTest("Test");
757755
try proof.verify(
758756
&.{ commitment_1, commitment_2, commitment_3 },
759757
&.{ 64, 32, 32 },

src/zksdk/range_proof/ipp.zig

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ pub fn Proof(bit_size: comptime_int) type {
7070
var a: []Scalar = a_vec;
7171
var b: []Scalar = b_vec;
7272

73-
transcript.appendDomSep("inner-product");
74-
transcript.appendU64("n", bit_size);
73+
transcript.appendRangeProof(.inner, bit_size);
7574

7675
var L_vec: std.BoundedArray(Ristretto255, logn) = .{};
7776
var R_vec: std.BoundedArray(Ristretto255, logn) = .{};
@@ -264,8 +263,7 @@ pub fn Proof(bit_size: comptime_int) type {
264263
[logn]Scalar, // u_inv_sq
265264
[bit_size]Scalar, // s
266265
} {
267-
transcript.appendDomSep("inner-product");
268-
transcript.appendU64("n", bit_size);
266+
transcript.appendRangeProof(.inner, bit_size);
269267

270268
// 1. Recompute x_k,...,x_1 based on the proof transcript
271269
var challenges: [logn]Scalar = undefined;
@@ -397,8 +395,8 @@ test "basic correctness" {
397395
scalars.buffer,
398396
) };
399397

400-
var prover_transcript = Transcript.init("innerproducttest");
401-
var verifier_transcript = Transcript.init("innerproducttest");
398+
var prover_transcript = Transcript.initTest("Test");
399+
var verifier_transcript = Transcript.initTest("Test");
402400

403401
const proof = Proof(32).init(
404402
Q,

src/zksdk/sigma_proofs/ciphertext_ciphertext.zig

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub const Proof = struct {
3333
amount: u64,
3434
transcript: *Transcript,
3535
) Proof {
36-
transcript.appendDomSep("ciphertext-ciphertext-equality-proof");
36+
transcript.appendDomSep(.@"ciphertext-ciphertext-equality-proof");
3737

3838
const P_first = first_kp.public.point;
3939
const D_first = first_ciphertext.handle.point;
@@ -97,7 +97,7 @@ pub const Proof = struct {
9797
second_ciphertext: *const ElGamalCiphertext,
9898
transcript: *Transcript,
9999
) !void {
100-
transcript.appendDomSep("ciphertext-ciphertext-equality-proof");
100+
transcript.appendDomSep(.@"ciphertext-ciphertext-equality-proof");
101101

102102
const P_first = first_pubkey.point;
103103
const C_first = first_ciphertext.commitment.point;
@@ -256,7 +256,7 @@ pub const Data = struct {
256256
}
257257

258258
fn newTranscript(self: Context) Transcript {
259-
var transcript = Transcript.init("ciphertext-ciphertext-equality-instruction");
259+
var transcript = Transcript.init(.@"ciphertext-ciphertext-equality-instruction");
260260
transcript.appendPubkey("first-pubkey", self.first_pubkey);
261261
transcript.appendPubkey("second-pubkey", self.second_pubkey);
262262
transcript.appendCiphertext("first-ciphertext", self.first_ciphertext);
@@ -403,8 +403,8 @@ test "correctness" {
403403
&second_opening,
404404
);
405405

406-
var prover_transcript = Transcript.init("test");
407-
var verifier_transcript = Transcript.init("test");
406+
var prover_transcript = Transcript.initTest("Test");
407+
var verifier_transcript = Transcript.initTest("Test");
408408

409409
const proof = Proof.init(
410410
&first_kp,
@@ -439,8 +439,8 @@ test "different messages" {
439439
&second_opening,
440440
);
441441

442-
var prover_transcript = Transcript.init("test");
443-
var verifier_transcript = Transcript.init("test");
442+
var prover_transcript = Transcript.initTest("Test");
443+
var verifier_transcript = Transcript.initTest("Test");
444444

445445
const proof = Proof.init(
446446
&first_kp,
@@ -480,7 +480,7 @@ test "proof string" {
480480
const proof = try Proof.fromBase64(proof_string);
481481
// zig fmt: on
482482

483-
var verifier_transcript = Transcript.init("Test");
483+
var verifier_transcript = Transcript.initTest("Test");
484484

485485
try proof.verify(
486486
&first_pubkey,

src/zksdk/sigma_proofs/ciphertext_commitment.zig

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub const Proof = struct {
3131
amount: u64,
3232
transcript: *Transcript,
3333
) Proof {
34-
transcript.appendDomSep("ciphertext-commitment-equality-proof");
34+
transcript.appendDomSep(.@"ciphertext-commitment-equality-proof");
3535

3636
const P = kp.public;
3737
const D = ciphertext.handle.point;
@@ -90,7 +90,7 @@ pub const Proof = struct {
9090
commitment: *const pedersen.Commitment,
9191
transcript: *Transcript,
9292
) !void {
93-
transcript.appendDomSep("ciphertext-commitment-equality-proof");
93+
transcript.appendDomSep(.@"ciphertext-commitment-equality-proof");
9494

9595
const P = pubkey.point;
9696
const C_ciphertext = ciphertext.commitment.point;
@@ -217,7 +217,7 @@ pub const Data = struct {
217217
}
218218

219219
fn newTranscript(self: Context) Transcript {
220-
var transcript = Transcript.init("ciphertext-commitment-equality-instruction");
220+
var transcript = Transcript.init(.@"ciphertext-commitment-equality-instruction");
221221
transcript.appendPubkey("pubkey", self.pubkey);
222222
transcript.appendCiphertext("ciphertext", self.ciphertext);
223223
transcript.appendCommitment("commitment", self.commitment);
@@ -295,8 +295,8 @@ test "success case" {
295295
const ciphertext = el_gamal.encrypt(u64, message, &kp.public);
296296
const commitment, const opening = pedersen.initValue(u64, message);
297297

298-
var prover_transcript = Transcript.init("Test");
299-
var verifier_transcript = Transcript.init("Test");
298+
var prover_transcript = Transcript.initTest("Test");
299+
var verifier_transcript = Transcript.initTest("Test");
300300

301301
const proof = Proof.init(
302302
&kp,
@@ -321,8 +321,8 @@ test "fail case" {
321321
const ciphertext = el_gamal.encrypt(u64, encrypted_message, &kp.public);
322322
const commitment, const opening = pedersen.initValue(u64, committed_message);
323323

324-
var prover_transcript = Transcript.init("test");
325-
var verifier_transcript = Transcript.init("test");
324+
var prover_transcript = Transcript.initTest("Test");
325+
var verifier_transcript = Transcript.initTest("Test");
326326

327327
const proof = Proof.init(
328328
&kp,
@@ -353,8 +353,8 @@ test "public key zeroed" {
353353
const ciphertext = el_gamal.encrypt(u64, message, &kp.public);
354354
const commitment, const opening = pedersen.initValue(u64, message);
355355

356-
var prover_transcript = Transcript.init("test");
357-
var verifier_transcript = Transcript.init("test");
356+
var prover_transcript = Transcript.initTest("Test");
357+
var verifier_transcript = Transcript.initTest("Test");
358358

359359
const proof = Proof.init(
360360
&kp,
@@ -385,8 +385,8 @@ test "all zoered" {
385385
const commitment = try pedersen.Commitment.fromBytes(.{0} ** 32);
386386
const opening = try pedersen.Opening.fromBytes(.{0} ** 32);
387387

388-
var prover_transcript = Transcript.init("test");
389-
var verifier_transcript = Transcript.init("test");
388+
var prover_transcript = Transcript.initTest("Test");
389+
var verifier_transcript = Transcript.initTest("Test");
390390

391391
const proof = Proof.init(
392392
&kp,
@@ -414,8 +414,8 @@ test "commitment zeroed" {
414414
const commitment = try pedersen.Commitment.fromBytes(.{0} ** 32);
415415
const opening = try pedersen.Opening.fromBytes(.{0} ** 32);
416416

417-
var prover_transcript = Transcript.init("test");
418-
var verifier_transcript = Transcript.init("test");
417+
var prover_transcript = Transcript.initTest("Test");
418+
var verifier_transcript = Transcript.initTest("Test");
419419

420420
const proof = Proof.init(
421421
&kp,
@@ -442,8 +442,8 @@ test "ciphertext zeroed" {
442442
const ciphertext = try ElGamalCiphertext.fromBytes(.{0} ** 64);
443443
const commitment, const opening = pedersen.initValue(u64, message);
444444

445-
var prover_transcript = Transcript.init("test");
446-
var verifier_transcript = Transcript.init("test");
445+
var prover_transcript = Transcript.initTest("Test");
446+
var verifier_transcript = Transcript.initTest("Test");
447447

448448
const proof = Proof.init(
449449
&kp,
@@ -476,7 +476,7 @@ test "proof strings" {
476476
const proof = try Proof.fromBase64(proof_string);
477477
// zig fmt: on
478478

479-
var verifier_transcript = Transcript.init("Test");
479+
var verifier_transcript = Transcript.initTest("Test");
480480
try proof.verify(
481481
&pubkey,
482482
&ciphertext,

0 commit comments

Comments
 (0)