From 3e115fb43435d534741799bfa57b2673ebf08bb9 Mon Sep 17 00:00:00 2001 From: Ignacio Hagopian Date: Tue, 26 Sep 2023 14:52:40 -0300 Subject: [PATCH] many improvements Signed-off-by: Ignacio Hagopian --- src/bench.zig | 49 +++++++++++++++++------------------ src/crs/crs.zig | 33 ++++++++++++++++------- src/ipa/ipa.zig | 5 ++-- src/main.zig | 4 +++ src/{crs => msm}/msm.zig | 28 ++++++++++++-------- src/multiproof/multiproof.zig | 17 +++++++----- 6 files changed, 81 insertions(+), 55 deletions(-) rename src/{crs => msm}/msm.zig (87%) diff --git a/src/bench.zig b/src/bench.zig index 45a8817..185e4a7 100644 --- a/src/bench.zig +++ b/src/bench.zig @@ -8,7 +8,6 @@ const multiproof = @import("multiproof/multiproof.zig"); const polynomials = @import("polynomial/lagrange_basis.zig"); const ipa = @import("ipa/ipa.zig"); const Transcript = @import("ipa/transcript.zig"); -const precomp = @import("crs/msm.zig"); pub fn main() !void { try benchFields(); @@ -72,7 +71,6 @@ fn benchFields() !void { fn benchPedersenHash() !void { std.debug.print("Benchmarking Pedersen hashing...\n", .{}); - const xcrs = crs.CRS.init(); const N = 5000; var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -82,8 +80,8 @@ fn benchPedersenHash() !void { } var allocator = gpa.allocator(); - var precomp_msm = try precomp.PrecompMSM(2, 8, crs.DomainSize).init(allocator, xcrs.Gs); - defer precomp_msm.deinit(); + const xcrs = try crs.CRS.init(allocator); + defer xcrs.deinit(); var vec_len: usize = 1; while (vec_len <= 256) : (vec_len <<= 1) { @@ -102,7 +100,7 @@ fn benchPedersenHash() !void { var start = std.time.microTimestamp(); for (0..N) |i| { - _ = try precomp_msm.msm(vecs[i][0..vec_len]); + _ = try xcrs.commit(vecs[i][0..vec_len]); } std.debug.print("takes {}µs\n", .{@divTrunc((std.time.microTimestamp() - start), (N))}); } @@ -110,14 +108,9 @@ fn benchPedersenHash() !void { fn benchIPAs() !void { const PrecomputedWeights = @import("polynomial/precomputed_weights.zig").PrecomputedWeights(crs.DomainSize, crs.Domain); - - std.debug.print("Setting up IPA benchmark...\n", .{}); const N = 100; - var weights = try PrecomputedWeights.init(); - const xcrs = crs.CRS.init(); - const IPA = ipa.IPA(crs.DomainSize); - + std.debug.print("Setting up IPA benchmark...\n", .{}); var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer { const deinit_status = gpa.deinit(); @@ -125,6 +118,11 @@ fn benchIPAs() !void { } var allocator = gpa.allocator(); + var weights = try PrecomputedWeights.init(); + const xcrs = try crs.CRS.init(allocator); + defer xcrs.deinit(); + const IPA = ipa.IPA(crs.DomainSize); + var prover_queries: []IPA.ProverQuery = try allocator.alloc(IPA.ProverQuery, 16); defer allocator.free(prover_queries); const z256 = Fr.fromInteger(256); @@ -132,7 +130,7 @@ fn benchIPAs() !void { for (0..prover_queries[i].A.len) |j| { prover_queries[i].A[j] = Fr.fromInteger(i + j + 0x424242); } - prover_queries[i].commitment = xcrs.commit(prover_queries[i].A); + prover_queries[i].commitment = try xcrs.commit(&prover_queries[i].A); prover_queries[i].eval_point = Fr.fromInteger(i + 0x414039).add(z256); prover_queries[i].B = try weights.barycentricFormulaConstants(prover_queries[i].eval_point); } @@ -177,14 +175,6 @@ fn benchMultiproofs() !void { const N = 25; const openings = [_]u16{ 1, 10, 100, 1_000 }; - const vkt_crs = crs.CRS.init(); - - const PolyOpeningSetup = struct { - poly_evaluations: [crs.DomainSize]Fr, - C: banderwagon.Element, - z: Fr, - }; - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer { const deinit_status = gpa.deinit(); @@ -192,6 +182,15 @@ fn benchMultiproofs() !void { } var allocator = gpa.allocator(); + const xcrs = try crs.CRS.init(allocator); + defer xcrs.deinit(); + + const PolyOpeningSetup = struct { + poly_evaluations: [crs.DomainSize]Fr, + C: banderwagon.Element, + z: u8, + }; + var vec_openings = try allocator.alloc(PolyOpeningSetup, openings[openings.len - 1]); defer allocator.free(vec_openings); @@ -199,11 +198,11 @@ fn benchMultiproofs() !void { for (0..vec_openings[i].poly_evaluations.len) |j| { vec_openings[i].poly_evaluations[j] = Fr.fromInteger(i + j + 0x424242); } - vec_openings[i].z = Fr.fromInteger((i + 0x414039) % 256); - vec_openings[i].C = crs.CRS.commit(vkt_crs, vec_openings[i].poly_evaluations); + vec_openings[i].z = @truncate(i +% 0x414039); + vec_openings[i].C = try crs.CRS.commit(xcrs, &vec_openings[i].poly_evaluations); } - const mproof = try multiproof.MultiProof.init(vkt_crs); + const mproof = try multiproof.MultiProof.init(xcrs); for (openings) |num_openings| { std.debug.print("\tBenchmarking {} openings...", .{num_openings}); @@ -218,7 +217,7 @@ fn benchMultiproofs() !void { .f = LagrangeBasis.init(vec_openings[i].poly_evaluations), .C = vec_openings[i].C, .z = vec_openings[i].z, - .y = vec_openings[i].poly_evaluations[@as(usize, @intCast(vec_openings[i].z.toInteger()))], + .y = vec_openings[i].poly_evaluations[vec_openings[i].z], }; } @@ -235,7 +234,7 @@ fn benchMultiproofs() !void { verifier_queries[i] = multiproof.VerifierQuery{ .C = vec_openings[i].C, .z = vec_openings[i].z, - .y = vec_openings[i].poly_evaluations[@as(usize, @intCast(vec_openings[i].z.toInteger()))], + .y = vec_openings[i].poly_evaluations[vec_openings[i].z], }; } start = std.time.milliTimestamp(); diff --git a/src/crs/crs.zig b/src/crs/crs.zig index 1f46e2f..3dba372 100644 --- a/src/crs/crs.zig +++ b/src/crs/crs.zig @@ -1,6 +1,8 @@ const std = @import("std"); +const Allocator = std.mem.Allocator; const sha256 = std.crypto.hash.sha2.Sha256; const banderwagon = @import("../banderwagon/banderwagon.zig"); +const msm = @import("../msm/msm.zig"); const Element = banderwagon.Element; const Fr = banderwagon.Fr; @@ -20,18 +22,31 @@ pub const Domain: [DomainSize]Fr = domain_elements: { // CRS contains the base pof points for Pedersen Commitments. pub const CRS = struct { + const PrecompMSM = msm.PrecompMSM(2, 8); + Gs: [DomainSize]Element, Q: Element, + precomp: PrecompMSM, - pub fn init() CRS { + pub fn init(allocator: Allocator) !CRS { + const points = deserialize_vkt_points(); return CRS{ - .Gs = deserialize_vkt_points(), + .Gs = points, .Q = Element.generator(), + .precomp = try PrecompMSM.init(allocator, &points), }; } - pub fn commit(crs: CRS, values: [DomainSize]Fr) Element { - return banderwagon.msm(&crs.Gs, &values); + pub fn deinit(self: CRS) void { + self.precomp.deinit(); + } + + pub fn commit(self: CRS, values: []const Fr) !Element { + return try self.precomp.msm(values); + } + + pub fn commitSlow(self: CRS, values: [DomainSize]Fr) Element { + return banderwagon.msm(&self.Gs, &values); } }; @@ -46,7 +61,8 @@ fn deserialize_vkt_points() [DomainSize]Element { } test "crs is consistent" { - const crs = CRS.init(); + const crs = try CRS.init(std.testing.allocator); + defer crs.deinit(); try std.testing.expect(crs.Gs.len == vkt_crs_points.len); // Reserialize Gs points and check they match with the original representation. @@ -67,7 +83,8 @@ test "crs is consistent" { } test "Gs cannot contain the generator" { - const crs = CRS.init(); + const crs = try CRS.init(std.testing.allocator); + defer crs.deinit(); const generator = Element.generator(); for (crs.Gs) |point| { try std.testing.expect(!generator.equal(point)); @@ -332,7 +349,3 @@ const vkt_crs_points = [_][]const u8{ "3102a5884d3dce8d94a8cf6d5ab2d3a4c76ec8b00f4554caa68c028aedf5970f", "3de2be346b539395b0c0de56a5ccca54a317f1b5c80107b0802af9a62276a4d8", }; - -test "msm" { - _ = @import("msm.zig"); -} diff --git a/src/ipa/ipa.zig b/src/ipa/ipa.zig index 93caaf9..a00f3bd 100644 --- a/src/ipa/ipa.zig +++ b/src/ipa/ipa.zig @@ -244,8 +244,9 @@ test "basic proof" { } // Commit to the polynomial in lagrange basis - const xcrs = crs.CRS.init(); - const commitment = xcrs.commit(lagrange_poly); + const xcrs = try crs.CRS.init(std.testing.allocator); + defer xcrs.deinit(); + const commitment = try xcrs.commit(&lagrange_poly); const expected_comm = std.fmt.bytesToHex(commitment.toBytes(), std.fmt.Case.lower); try std.testing.expectEqualStrings("1b9dff8f5ebbac250d291dfe90e36283a227c64b113c37f1bfb9e7a743cdb128", &expected_comm); diff --git a/src/main.zig b/src/main.zig index f9e6dcf..e728d87 100644 --- a/src/main.zig +++ b/src/main.zig @@ -15,6 +15,10 @@ test "crs" { _ = @import("crs/crs.zig"); } +test "msm" { + _ = @import("msm/msm.zig"); +} + test "fields" { _ = @import("fields/fields.zig"); } diff --git a/src/crs/msm.zig b/src/msm/msm.zig similarity index 87% rename from src/crs/msm.zig rename to src/msm/msm.zig index 60c449e..1b9d687 100644 --- a/src/crs/msm.zig +++ b/src/msm/msm.zig @@ -10,7 +10,6 @@ const ExtendedPointNormalized = bandersnatch.ExtendedPointNormalized; pub fn PrecompMSM( comptime _t: comptime_int, comptime _b: comptime_int, - comptime basis_len: comptime_int, ) type { return struct { const Self = @This(); @@ -19,16 +18,19 @@ pub fn PrecompMSM( const t = _t; const window_size = 1 << b; const points_per_column = (Fr.BitSize + t - 1) / t; - const num_windows = (points_per_column * basis_len + b - 1) / b; allocator: Allocator, table: []const ExtendedPointNormalized, - pub fn init(allocator: Allocator, basis: [basis_len]Element) !Self { - var table_basis = try allocator.alloc(ExtendedPoint, num_windows * basis_len); + num_windows: usize, + basis_len: usize, + + pub fn init(allocator: Allocator, basis: []const Element) !Self { + const num_windows = (points_per_column * basis.len + b - 1) / b; + var table_basis = try allocator.alloc(ExtendedPoint, points_per_column * basis.len); defer allocator.free(table_basis); var idx: usize = 0; - for (0..basis_len) |hi| { + for (0..basis.len) |hi| { table_basis[idx] = basis[hi].point; idx += 1; for (1..points_per_column) |_| { @@ -58,6 +60,8 @@ pub fn PrecompMSM( return Self{ .allocator = allocator, .table = table, + .num_windows = num_windows, + .basis_len = basis.len, }; } @@ -66,7 +70,9 @@ pub fn PrecompMSM( } pub fn msm(self: Self, mont_scalars: []const Fr) !Element { - std.debug.assert(mont_scalars.len <= basis_len); + if (mont_scalars.len > self.basis_len) { + return error.ScalarLengthBiggerThanBasis; + } var scalars = try self.allocator.alloc(u256, mont_scalars.len); defer self.allocator.free(scalars); @@ -122,11 +128,11 @@ pub fn PrecompMSM( } test "correctness" { - const crs = @import("crs.zig"); - const CRS = crs.CRS.init(); - var test_allocator = std.testing.allocator; + const crs = @import("../crs/crs.zig"); + const xcrs = try crs.CRS.init(std.testing.allocator); + defer xcrs.deinit(); - const precomp = try PrecompMSM(2, 5, crs.DomainSize).init(test_allocator, CRS.Gs); + const precomp = try PrecompMSM(2, 5).init(std.testing.allocator, &xcrs.Gs); defer precomp.deinit(); var scalars: [crs.DomainSize]Fr = undefined; @@ -145,7 +151,7 @@ test "correctness" { } full_scalars[i] = Fr.zero(); } - const exp = CRS.commit(full_scalars); + const exp = xcrs.commitSlow(full_scalars); const got = try precomp.msm(msm_scalars); try std.testing.expect(Element.equal(exp, got)); diff --git a/src/multiproof/multiproof.zig b/src/multiproof/multiproof.zig index c3f341a..ae68c6e 100644 --- a/src/multiproof/multiproof.zig +++ b/src/multiproof/multiproof.zig @@ -8,6 +8,7 @@ const Transcript = @import("../ipa/transcript.zig"); const ipa = @import("../ipa/ipa.zig"); const crs = @import("../crs/crs.zig"); const CRS = crs.CRS; +const msm = @import("../msm/msm.zig"); const precomputed_weights = @import("../polynomial/precomputed_weights.zig"); const IPA = ipa.IPA(crs.DomainSize); @@ -74,7 +75,7 @@ pub const MultiProof = struct { power_of_r = Fr.mul(power_of_r, r); } - const D = CRS.commit(self.crs, g); + const D = try CRS.commit(self.crs, &g); transcript.appendPoint(D, "D"); // Step 2: Compute h in evaluation form @@ -105,7 +106,7 @@ pub const MultiProof = struct { // Step 3: Evaluate and compute IPA proofs - const E = CRS.commit(self.crs, h); + const E = try CRS.commit(self.crs, &h); transcript.appendPoint(E, "E"); var ipa_commitment: Element = undefined; @@ -203,7 +204,8 @@ pub const MultiProof = struct { Cs[i] = query.C; E_coefficients[i] = Fr.mul(powers_of_r[i], helper_scalar_den[queries[i].z]); } - const E = banderwagon.msm(Cs, E_coefficients); + var precomp = try msm.PrecompMSM(8, 8).init(allocator, Cs); + const E = try precomp.msm(E_coefficients); transcript.appendPoint(E, "E"); // Check IPA proof. @@ -330,9 +332,10 @@ test "basic" { Fr.fromInteger(1), } ** 8; - const vkt_crs = CRS.init(); - const C_a = CRS.commit(vkt_crs, poly_eval_a); - const C_b = CRS.commit(vkt_crs, poly_eval_b); + const xcrs = try CRS.init(std.testing.allocator); + defer xcrs.deinit(); + const C_a = try CRS.commit(xcrs, &poly_eval_a); + const C_b = try CRS.commit(xcrs, &poly_eval_b); const zs = [_]u8{ 0, 0 }; const ys = [_]Fr{ Fr.fromInteger(1), Fr.fromInteger(32) }; const fs = [_][256]Fr{ poly_eval_a, poly_eval_b }; @@ -351,7 +354,7 @@ test "basic" { .y = ys[1], }; - const multiproof = try MultiProof.init(vkt_crs); + const multiproof = try MultiProof.init(xcrs); var prover_transcript = Transcript.init("test"); const proof = try multiproof.createProof(&prover_transcript, &[_]ProverQuery{ query_a, query_b });