Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a performant bucketing MSM #68

Merged
merged 3 commits into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Utilities.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.16;

import "@std/Test.sol";
import "src/blocks/EqPolynomial.sol";

/**
Expand Down
59 changes: 59 additions & 0 deletions src/blocks/grumpkin/Grumpkin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ library Grumpkin {
uint256 self_z = 1;
uint256 rhs_z = 1;

if (is_identity(p1) && is_identity(p2)) {
return Identity();
}

if (is_identity(p1)) {
self_x = 0;
self_y = 1;
Expand Down Expand Up @@ -305,4 +309,59 @@ library Grumpkin {

return GrumpkinAffinePoint(x, y);
}

function getAt(uint256 segment, uint256 c, uint256 scalar) public returns (uint256) {
uint256 skipBits = segment * c;
if (skipBits >= 256) {
return 0;
}

uint256 res = (scalar >> skipBits) % (1 << c);
return res;
}

function multiScalarMulSerial(GrumpkinAffinePoint[] memory bases, uint256[] memory scalars)
public
returns (GrumpkinAffinePoint memory r)
{
require(scalars.length == bases.length, "MSM error: length does not match");

uint256 c;
if (bases.length < 4) {
c = 1;
} else if (bases.length < 32) {
c = 3;
} else {
c = CommonUtilities.log2(bases.length);
}

GrumpkinAffinePoint[] memory buckets = new GrumpkinAffinePoint[]((1 << c) - 1);
GrumpkinAffinePoint memory res = Identity();

uint256 segments = (256 / c) + 1;
for (uint256 segment = segments; segment > 0; segment--) {
for (uint256 i = 0; i < c; i++) {
res = double(res);
}

for (uint256 i = 0; i < buckets.length; i++) {
buckets[i] = Identity();
}

for (uint256 i = 0; i < bases.length; i++) {
uint256 limb = getAt(segment - 1, c, scalars[i]);
if (limb != 0) {
buckets[limb - 1] = add(buckets[limb - 1], bases[i]);
}
}

GrumpkinAffinePoint memory runningSum = Identity();
for (uint256 i = buckets.length; i > 0; i--) {
runningSum = add(buckets[i - 1], runningSum);
res = add(res, runningSum);
}
}

r = res;
}
}
10 changes: 10 additions & 0 deletions test/grumpkin-curves-tests.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,16 @@ contract GrumpkinCurvesContractTests is Test {
assertEq(a_add_b.y, 0x001a2f39bd6cddd97502bc15b89c9d3376c3bf227a1ef667ba593fc9ed1361cd);
}

function testGrumpkinPointsAddition11() public {
Grumpkin.GrumpkinAffinePoint memory a = Grumpkin.Identity();
Grumpkin.GrumpkinAffinePoint memory b = Grumpkin.Identity();

Grumpkin.GrumpkinAffinePoint memory a_add_b = Grumpkin.add(a, b);

assertEq(a_add_b.x, 0);
assertEq(a_add_b.y, 0);
}

function testGrumpkinScalarMultiplication() public {
uint256 scalar = 0x29bd9a803cd11224817183fc6bceb32d59926fd9aa37d3cfb1c7845cbf7fae0d;

Expand Down
Loading
Loading