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

Feat/u512 #128

Merged
merged 42 commits into from
Jan 28, 2025
Merged
Changes from 26 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
f3f6b79
init
dovgopoly Jan 9, 2025
9d6d09c
rm comments
dovgopoly Jan 9, 2025
c8c57db
wip
dovgopoly Jan 15, 2025
ba239ee
wip
dovgopoly Jan 15, 2025
3720814
fixed add & added test
dovgopoly Jan 16, 2025
a8a79a5
wip (passed ecdsa check) 17.8kk
dovgopoly Jan 16, 2025
c698a36
fix
dovgopoly Jan 16, 2025
85a2c36
opt
dovgopoly Jan 17, 2025
de6382b
-500k
Arvolear Jan 17, 2025
31a36eb
15.8kk 2p
dovgopoly Jan 17, 2025
4e00dc7
15.3kk
dovgopoly Jan 17, 2025
7facbab
rm shl 15.48kk
dovgopoly Jan 17, 2025
32a9716
wip
dovgopoly Jan 20, 2025
9efa52b
wip
dovgopoly Jan 20, 2025
2c5dd2d
added test vectors, tests are failed
dovgopoly Jan 20, 2025
ce83623
fixed ecdsa512 impl 22.2kk
dovgopoly Jan 21, 2025
8f7deb4
20.4kk
dovgopoly Jan 21, 2025
007dc1c
added assert
dovgopoly Jan 21, 2025
e650ce3
small fixes
dovgopoly Jan 21, 2025
85684f1
refactored
dovgopoly Jan 21, 2025
57f0f8d
typo
dovgopoly Jan 21, 2025
6db5141
added crazy optimization with bit skipping 20.1kk
dovgopoly Jan 21, 2025
b9462a7
13.86kk & typos
dovgopoly Jan 21, 2025
288f0c1
remove opt 384 libs
mllwchrry Jan 23, 2025
b3cffd6
add tests for U512
mllwchrry Jan 23, 2025
5df79f0
add natspec
mllwchrry Jan 24, 2025
82a88c0
add operator overloading
mllwchrry Jan 24, 2025
936c966
modify moddiv test
mllwchrry Jan 24, 2025
5b188af
rm ops and fixed tests
dovgopoly Jan 26, 2025
cfc730b
added assign & call & bitwise ops
dovgopoly Jan 26, 2025
c1c7cd8
added modexpU256 & tested gas
dovgopoly Jan 26, 2025
0aaa9fe
typo
dovgopoly Jan 26, 2025
52672ed
small adjustments
dovgopoly Jan 26, 2025
d87784e
add U512 usage example and fix tests
mllwchrry Jan 27, 2025
bbca148
fix natspec
mllwchrry Jan 27, 2025
4b65a75
fixed comment
dovgopoly Jan 27, 2025
bf130be
add toBytes to natspec
mllwchrry Jan 27, 2025
66ba3e1
typos
dovgopoly Jan 27, 2025
d5a813c
typos
dovgopoly Jan 27, 2025
0a427dc
typos
dovgopoly Jan 27, 2025
8dd88d9
small adjustments
dovgopoly Jan 28, 2025
d053dd7
update readme
Arvolear Jan 28, 2025
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,185 changes: 1,185 additions & 0 deletions contracts/libs/bn/U512.sol

Large diffs are not rendered by default.

1,034 changes: 224 additions & 810 deletions contracts/libs/crypto/ECDSA384.sol

Large diffs are not rendered by default.

432 changes: 432 additions & 0 deletions contracts/libs/crypto/ECDSA512.sol

Large diffs are not rendered by default.

581 changes: 581 additions & 0 deletions contracts/mock/libs/bn/U512Mock.sol

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions contracts/mock/libs/crypto/ECDSA384Mock.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {ECDSA384, U384} from "../../../libs/crypto/ECDSA384.sol";
import {ECDSA384} from "../../../libs/crypto/ECDSA384.sol";
import {uint512} from "../../../libs/bn/U512.sol";
import {U512} from "../../../libs/bn/U512.sol";

contract ECDSA384Mock {
using ECDSA384 for *;
@@ -73,8 +75,8 @@ contract ECDSA384Mock {
}

function cmpMock() external pure returns (int256 cmp_) {
uint256 a_;
uint256 b_;
uint512 a_;
uint512 b_;

assembly {
a_ := mload(0x40)
@@ -86,6 +88,6 @@ contract ECDSA384Mock {
mstore(0x40, add(b_, 0x40))
}

return U384.cmp(a_, b_);
return U512.cmp(a_, b_);
}
}
27 changes: 27 additions & 0 deletions contracts/mock/libs/crypto/ECDSA512Mock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {ECDSA512} from "../../../libs/crypto/ECDSA512.sol";

contract ECDSA512Mock {
using ECDSA512 for *;

ECDSA512.Parameters private _brainpoolP512r1CurveParams =
ECDSA512.Parameters({
a: hex"7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94ca",
b: hex"3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94cadc083e67984050b75ebae5dd2809bd638016f723",
gx: hex"81aee4bdd82ed9645a21322e9c4c6a9385ed9f70b5d916c1b43b62eef4d0098eff3b1f78e2d0d48d50d1687b93b97d5f7c6d5047406a5e688b352209bcb9f822",
gy: hex"7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892",
p: hex"aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca703308717d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3",
n: hex"aadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90069",
lowSmax: hex"556ecedc6df4e2459fea735719e4fe03e59846d9d9e4e9076b31ce65381984382a9f2e20a654930ca0c3308cbfd608238ed8e9c0842eed6edac3cb414e548034"
});

function verifyBrainpoolP512r1WithoutHashing(
bytes calldata message_,
bytes calldata signature_,
bytes calldata pubKey_
) external view returns (bool) {
return _brainpoolP512r1CurveParams.verify(abi.encodePacked(message_), signature_, pubKey_);
}
}
2 changes: 1 addition & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ const config: HardhatUserConfig = {
gasReporter: {
currency: "USD",
gasPrice: 50,
enabled: false,
enabled: true,
reportPureAndViewMethods: true,
coinmarketcap: `${process.env.COINMARKETCAP_KEY}`,
},
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@
"scripts": {
"prepare": "husky",
"compile": "npx hardhat compile --force",
"coverage": "npx hardhat coverage --solcoverjs ./.solcover.ts",
"coverage": "NODE_OPTIONS='--max-old-space-size=8192' npx hardhat coverage --solcoverjs ./.solcover.ts",
"test": "npx hardhat test",
"private-network": "npx hardhat node",
"lint-fix": "npm run lint-sol-fix && npm run lint-ts-fix && npm run lint-json-fix",
311 changes: 311 additions & 0 deletions test/libs/bn/U512.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
import { ethers } from "hardhat";
import { expect } from "chai";
import { Reverter } from "@/test/helpers/reverter";

import { U512Mock } from "@ethers-v6";

describe("U512", () => {
const reverter = new Reverter();

const prime = 76884956397045344220809746629001649092737531784414529538755519063063536359079n;

let u512: U512Mock;

function randomU512(): string {
return "0x" + ethers.toBigInt(ethers.randomBytes(64)).toString(16).padStart(128, "0");
}

function toBytes(value: bigint): string {
return "0x" + value.toString(16).padStart(128, "0");
}

function mod(a: string, m: string): string {
return toBytes(ethers.toBigInt(a) % ethers.toBigInt(m));
}

function add(a: string, b: string): string {
const maxUint512 = BigInt(1) << BigInt(512);

const aBigInt = ethers.toBigInt(a);
const bBigInt = ethers.toBigInt(b);

const result = (aBigInt + bBigInt) % maxUint512;

return toBytes(result);
}

function sub(a: string, b: string): string {
const maxUint512 = BigInt(1) << BigInt(512);

const aBigInt = ethers.toBigInt(a);
const bBigInt = ethers.toBigInt(b);

let result = (aBigInt - bBigInt) % maxUint512;

if (result < 0) {
result += maxUint512;
}

return toBytes(result);
}

function mul(a: string, b: string): string {
const maxUint512 = BigInt(1) << BigInt(512);

const aBigInt = ethers.toBigInt(a);
const bBigInt = ethers.toBigInt(b);

const result = (aBigInt * bBigInt) % maxUint512;

return toBytes(result);
}

function modadd(a: string, b: string, m: string): string {
return toBytes((ethers.toBigInt(a) + ethers.toBigInt(b)) % ethers.toBigInt(m));
}

function modmul(a: string, b: string, m: string): string {
return toBytes((ethers.toBigInt(a) * ethers.toBigInt(b)) % ethers.toBigInt(m));
}

function modexp(a: string, b: string, m: string): string {
return toBytes(ethers.toBigInt(a) ** ethers.toBigInt(b) % ethers.toBigInt(m));
}

function modinv(a: string, m: string): string {
const aBigInt = ethers.toBigInt(a);
const mBigInt = ethers.toBigInt(m);

if (aBigInt <= 0n || mBigInt <= 0n) {
throw new Error("Inputs must be positive integers.");
}

let [t, newT] = [0n, 1n];
let [r, newR] = [mBigInt, aBigInt];

while (newR !== 0n) {
const quotient = r / newR;
[t, newT] = [newT, t - quotient * newT];
[r, newR] = [newR, r - quotient * newR];
}

if (r > 1n) {
throw new Error("No modular inverse exists.");
}

if (t < 0n) {
t += mBigInt;
}

return toBytes(t);
}

function modsub(a: string, b: string, m: string): string {
const aBn = ethers.toBigInt(a);
const bBn = ethers.toBigInt(b);
const mBn = ethers.toBigInt(m);

return toBytes((((aBn - bBn) % mBn) + mBn) % mBn);
}

before(async () => {
const U512Mock = await ethers.getContractFactory("U512Mock");

u512 = await U512Mock.deploy();

await reverter.snapshot();
});

afterEach(reverter.revert);

it("copy test", async () => {
const [pointerOriginal, pointerCopy, valueOriginal, valueCopy] = await u512.copy(prime);

expect(pointerOriginal).to.be.lessThan(pointerCopy);
expect(valueOriginal).to.be.equal(valueCopy);
});

it("isNull test", async () => {
expect(await u512.isNull(0)).to.be.true;
expect(await u512.isNull(64)).to.be.false;
});

it("eq test", async () => {
expect(await u512.eq(toBytes(1020n), toBytes(1002n))).to.be.false;
expect(await u512.eq(toBytes(200n), toBytes(200n))).to.be.true;
expect(await u512.eq("0x00", "0x00")).to.be.true;
});

it("eqUint256 test", async () => {
expect(await u512.eqUint256(toBytes(1020n), 1002n)).to.be.false;
expect(await u512.eqUint256(toBytes(200n), 200n)).to.be.true;
expect(await u512.eqUint256("0x00", 0)).to.be.true;
});

it("cmp test", async () => {
expect(await u512.cmp(toBytes(705493n), toBytes(705492n))).to.be.equal(1);
expect(await u512.cmp(toBytes(1n), "0x00")).to.be.equal(1);
expect(await u512.cmp(toBytes(775n), toBytes(775n))).to.be.equal(0);
expect(await u512.cmp("0x00", "0x00")).to.be.equal(0);
expect(await u512.cmp(toBytes(380n), toBytes(400n))).to.be.equal(-1);
expect(await u512.cmp("0x00", toBytes(12n))).to.be.equal(-1);
});

it("mod test", async () => {
for (let i = 0; i < 100; ++i) {
const a = randomU512();
const m = randomU512();
const to = randomU512();

expect(await u512.mod(a, m)).to.be.equal(mod(a, m));
expect(await u512.modAssign(a, m)).to.be.equal(mod(a, m));
expect(await u512.modAssignTo(a, m, to)).to.be.equal(mod(a, m));
}
});

it("modinv test", async () => {
const m = toBytes(prime);

for (let i = 0; i < 100; ++i) {
const a = randomU512();
const to = randomU512();

expect(await u512.modinv(a, m)).to.be.equal(modinv(a, m));
expect(await u512.modinvAssign(a, m)).to.be.equal(modinv(a, m));
expect(await u512.modinvAssignTo(a, m, to)).to.be.equal(modinv(a, m));
}
});

it("add test", async () => {
for (let i = 0; i < 100; ++i) {
const a = randomU512();
const b = randomU512();
const to = randomU512();

expect(await u512.add(a, b)).to.be.equal(add(a, b));
expect(await u512.addAssign(a, b)).to.be.equal(add(a, b));
expect(await u512.addAssignTo(a, b, to)).to.be.equal(add(a, b));
}
});

it("sub test", async () => {
for (let i = 0; i < 100; ++i) {
const a = randomU512();
const b = randomU512();
const to = randomU512();

expect(await u512.sub(a, b)).to.be.equal(sub(a, b));
expect(await u512.subAssign(a, b)).to.be.equal(sub(a, b));
expect(await u512.subAssignTo(a, b, to)).to.be.equal(sub(a, b));
}
});

it("mul test", async () => {
for (let i = 0; i < 100; ++i) {
const a = randomU512();
const b = randomU512();
const to = randomU512();

expect(await u512.mul(a, b)).to.be.equal(mul(a, b));
expect(await u512.mulAssign(a, b)).to.be.equal(mul(a, b));
expect(await u512.mulAssignTo(a, b, to)).to.be.equal(mul(a, b));
}
});

it("modadd test", async () => {
for (let i = 0; i < 100; ++i) {
const a = randomU512();
const b = randomU512();
const m = randomU512();
const to = randomU512();

expect(await u512.modadd(a, b, m)).to.equal(modadd(a, b, m));
expect(await u512.modaddAssign(a, b, m)).to.equal(modadd(a, b, m));
expect(await u512.modaddAssignTo(a, b, m, to)).to.equal(modadd(a, b, m));
}
});

it("redadd test", async () => {
for (let i = 0; i < 100; ++i) {
const m = randomU512();

const a = mod(randomU512(), m);
const b = mod(randomU512(), m);

const to = randomU512();

expect(await u512.redadd(a, b, m)).to.equal(modadd(a, b, m));
expect(await u512.redaddAssign(a, b, m)).to.equal(modadd(a, b, m));
expect(await u512.redaddAssignTo(a, b, m, to)).to.equal(modadd(a, b, m));
}
});

it("modmul test", async () => {
for (let i = 0; i < 100; ++i) {
const a = randomU512();
const b = randomU512();
const m = randomU512();
const to = randomU512();

expect(await u512.modmul(a, b, m)).to.equal(modmul(a, b, m));
expect(await u512.modmulAssign(a, b, m)).to.equal(modmul(a, b, m));
expect(await u512.modmulAssignTo(a, b, m, to)).to.equal(modmul(a, b, m));
}
});

it("modsub test", async () => {
for (let i = 0; i < 100; ++i) {
const a = randomU512();
const b = randomU512();
const m = randomU512();
const to = randomU512();

expect(await u512.modsub(a, b, m)).to.equal(modsub(a, b, m));
expect(await u512.modsubAssign(a, b, m)).to.equal(modsub(a, b, m));
expect(await u512.modsubAssignTo(a, b, m, to)).to.equal(modsub(a, b, m));
}
});

it("redsub test", async () => {
for (let i = 0; i < 100; ++i) {
const m = randomU512();

const a = mod(randomU512(), m);
const b = mod(randomU512(), m);

const to = randomU512();

expect(await u512.redsub(a, b, m)).to.equal(modsub(a, b, m));
expect(await u512.redsubAssign(a, b, m)).to.equal(modsub(a, b, m));
expect(await u512.redsubAssignTo(a, b, m, to)).to.equal(modsub(a, b, m));
}
});

it("modexp test", async () => {
for (let i = 0; i < 100; ++i) {
const a = randomU512();
const b = toBytes(100n);
const m = randomU512();
const to = randomU512();

expect(await u512.modexp(a, b, m)).to.equal(modexp(a, b, m));
expect(await u512.modexpAssign(a, b, m)).to.equal(modexp(a, b, m));
expect(await u512.modexpAssignTo(a, b, m, to)).to.equal(modexp(a, b, m));
}
});

it("moddiv test", async () => {
const m = toBytes(prime);

const a = toBytes(779149564533142355434093157610126726613246737199n);
const b = toBytes(29118654464229156312755475164902924590603964377702716942232927993582928167089n);

const to = randomU512();

const expected = toBytes(30823410400962253491978005949535646087432096635784775122170630924100507445065n);

expect(await u512.moddiv(a, b, m)).to.equal(expected);
expect(await u512.moddivAssign(a, b, m)).to.equal(expected);
expect(await u512.moddivAssignTo(a, b, m, to)).to.equal(expected);
});
});
Loading