diff --git a/packages/eddsa-poseidon/src/utils.ts b/packages/eddsa-poseidon/src/utils.ts
index 3427a9b29..65ddf4400 100644
--- a/packages/eddsa-poseidon/src/utils.ts
+++ b/packages/eddsa-poseidon/src/utils.ts
@@ -1,4 +1,13 @@
-import { BigNumber, BigNumberish, Point, Signature } from "./types"
+import { Point } from "@zk-kit/baby-jubjub"
+import {
+ BigNumberish,
+ bigNumberishToBigint,
+ bigNumberishToBuffer,
+ bufferToBigint,
+ isBigNumberish,
+ isStringifiedBigint
+} from "@zk-kit/utils"
+import { Signature } from "./types"
export function pruneBuffer(buff: Buffer): Buffer {
buff[0] &= 0xf8
@@ -8,30 +17,6 @@ export function pruneBuffer(buff: Buffer): Buffer {
return buff
}
-export function isStringifiedBigint(s: BigNumber | string): boolean {
- try {
- BigInt(s)
-
- return true
- } catch (e) {
- return false
- }
-}
-
-export function isHexadecimal(s: string) {
- return /^(0x|0X)[0-9a-fA-F]+$/.test(s)
-}
-
-export function isBigNumberish(value: BigNumberish): boolean {
- return (
- typeof value === "number" ||
- typeof value === "bigint" ||
- (typeof value === "string" && isStringifiedBigint(value)) ||
- (typeof value === "string" && isHexadecimal(value)) ||
- Buffer.isBuffer(value)
- )
-}
-
export function isPoint(point: Point): boolean {
return Array.isArray(point) && point.length === 2 && isStringifiedBigint(point[0]) && isStringifiedBigint(point[1])
}
@@ -46,66 +31,9 @@ export function isSignature(signature: Signature): boolean {
)
}
-export function int2hex(n: bigint) {
- let hex = n.toString(16)
-
- // Ensure even length.
- if (hex.length % 2 !== 0) {
- hex = `0${hex}`
- }
-
- return hex
-}
-
-export function bigNumberish2Buff(value: BigNumberish): Buffer {
- if (
- typeof value === "number" ||
- typeof value === "bigint" ||
- (typeof value === "string" && isStringifiedBigint(value))
- ) {
- const hex = int2hex(BigInt(value))
-
- return Buffer.from(hex, "hex")
- }
-
- return value as Buffer
-}
-
-export function buff2int(buffer: Buffer): bigint {
- return BigInt(`0x${buffer.toString("hex")}`)
-}
-
-export function bigNumberish2BigNumber(value: BigNumberish): bigint {
- if (
- typeof value === "number" ||
- typeof value === "bigint" ||
- (typeof value === "string" && isStringifiedBigint(value)) ||
- (typeof value === "string" && isHexadecimal(value))
- ) {
- return BigInt(value)
- }
-
- return buff2int(value as Buffer)
-}
-
-export function leBuff2int(buffer: Buffer): bigint {
- return BigInt(`0x${buffer.reverse().toString("hex")}`)
-}
-
-export function leInt2Buff(n: bigint): Buffer {
- const hex = int2hex(n)
-
- // Allocate buffer of the desired size, filled with zeros.
- const buffer = Buffer.alloc(32, 0)
-
- Buffer.from(hex, "hex").reverse().copy(buffer)
-
- return buffer
-}
-
export function checkPrivateKey(privateKey: BigNumberish): Buffer {
if (isBigNumberish(privateKey)) {
- return bigNumberish2Buff(privateKey)
+ return bigNumberishToBuffer(privateKey)
}
if (typeof privateKey !== "string") {
@@ -117,12 +45,12 @@ export function checkPrivateKey(privateKey: BigNumberish): Buffer {
export function checkMessage(message: BigNumberish): bigint {
if (isBigNumberish(message)) {
- return bigNumberish2BigNumber(message)
+ return bigNumberishToBigint(message)
}
if (typeof message !== "string") {
throw TypeError("Invalid message type. Supported types: number, bigint, buffer, string.")
}
- return buff2int(Buffer.from(message))
+ return bufferToBigint(Buffer.from(message))
}
diff --git a/packages/imt/package.json b/packages/imt/package.json
index ee90e56d3..14668d34a 100644
--- a/packages/imt/package.json
+++ b/packages/imt/package.json
@@ -21,13 +21,10 @@
],
"repository": "git@github.com:privacy-scaling-explorations/zk-kit.git",
"homepage": "https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/imt",
- "author": {
- "name": "Cedoor",
- "email": "me@cedoor.dev",
- "url": "https://cedoor.dev"
+ "bugs": {
+ "url": "https://github.com/privacy-scaling-explorations/zk-kit.git/issues"
},
"scripts": {
- "build:watch": "rollup -c rollup.config.ts -w --configPlugin typescript",
"build": "rimraf dist && rollup -c rollup.config.ts --configPlugin typescript",
"prepublishOnly": "yarn build"
},
diff --git a/packages/imt/rollup.config.ts b/packages/imt/rollup.config.ts
index da32af1a2..43545a0f0 100644
--- a/packages/imt/rollup.config.ts
+++ b/packages/imt/rollup.config.ts
@@ -8,10 +8,11 @@ const banner = `/**
* @module ${pkg.name}
* @version ${pkg.version}
* @file ${pkg.description}
- * @copyright ${pkg.author.name} ${new Date().getFullYear()}
+ * @copyright Ethereum Foundation ${new Date().getFullYear()}
* @license ${pkg.license}
* @see [Github]{@link ${pkg.homepage}}
*/`
+
const name = pkg.name.substr(1).replace(/[-/]./g, (x: string) => x.toUpperCase()[1])
export default {
diff --git a/packages/utils/LICENSE b/packages/utils/LICENSE
new file mode 100644
index 000000000..4377091ec
--- /dev/null
+++ b/packages/utils/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Ethereum Foundation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/utils/README.md b/packages/utils/README.md
new file mode 100644
index 000000000..849a9fe56
--- /dev/null
+++ b/packages/utils/README.md
@@ -0,0 +1,79 @@
+
+
+ Utils
+
+ Essential zero-knowledge utility library for JavaScript developers.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+> [!WARNING]
+> This library has **not** been audited.
+
+## 🛠 Install
+
+### npm or yarn
+
+Install the `@zk-kit/utils` package and its peer dependencies with npm:
+
+```bash
+npm i @zk-kit/utils
+```
+
+or yarn:
+
+```bash
+yarn add @zk-kit/utils
+```
+
+### CDN
+
+You can also load it using a `script` tag using [unpkg](https://unpkg.com/):
+
+```html
+
+```
+
+or [JSDelivr](https://www.jsdelivr.com/):
+
+```html
+
+```
+
+## 📜 Usage
+
+For more information on the functions provided by `@zk-kit/utils`, please refer to the [documentation](https://zkkit.pse.dev/modules/_zk_kit_utils.html).
diff --git a/packages/utils/build.tsconfig.json b/packages/utils/build.tsconfig.json
new file mode 100644
index 000000000..2d4a1d6da
--- /dev/null
+++ b/packages/utils/build.tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "baseUrl": ".",
+ "declarationDir": "dist/types"
+ },
+ "include": ["src"]
+}
diff --git a/packages/utils/package.json b/packages/utils/package.json
new file mode 100644
index 000000000..2818697f9
--- /dev/null
+++ b/packages/utils/package.json
@@ -0,0 +1,41 @@
+{
+ "name": "@zk-kit/utils",
+ "version": "0.1.0",
+ "description": "Essential zero-knowledge utility library for JavaScript developers.",
+ "license": "MIT",
+ "iife": "dist/index.js",
+ "unpkg": "dist/index.min.js",
+ "jsdelivr": "dist/index.min.js",
+ "main": "dist/index.node.js",
+ "exports": {
+ "import": "./dist/index.mjs",
+ "require": "./dist/index.node.js",
+ "types": "./dist/types/index.d.ts"
+ },
+ "types": "dist/types/index.d.ts",
+ "files": [
+ "dist/",
+ "src/",
+ "LICENSE",
+ "README.md"
+ ],
+ "repository": "https://github.com/privacy-scaling-explorations/zk-kit",
+ "homepage": "https://github.com/privacy-scaling-explorations/zk-kit/tree/main/packages/utils",
+ "bugs": {
+ "url": "https://github.com/privacy-scaling-explorations/zk-kit.git/issues"
+ },
+ "scripts": {
+ "build": "rimraf dist && rollup -c rollup.config.ts --configPlugin typescript && yarn build:iife",
+ "build:iife": "rollup -c rollup.iife.config.ts --configPlugin typescript",
+ "prepublishOnly": "yarn build"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "devDependencies": {
+ "rollup-plugin-cleanup": "^3.2.1",
+ "rollup-plugin-polyfill-node": "^0.13.0",
+ "rollup-plugin-terser": "^7.0.2",
+ "rollup-plugin-typescript2": "^0.31.2"
+ }
+}
diff --git a/packages/utils/rollup.config.ts b/packages/utils/rollup.config.ts
new file mode 100644
index 000000000..75b0a7bb4
--- /dev/null
+++ b/packages/utils/rollup.config.ts
@@ -0,0 +1,26 @@
+import fs from "fs"
+import cleanup from "rollup-plugin-cleanup"
+import typescript from "rollup-plugin-typescript2"
+
+const pkg = JSON.parse(fs.readFileSync("./package.json", "utf8"))
+const banner = `/**
+ * @module ${pkg.name}
+ * @version ${pkg.version}
+ * @file ${pkg.description}
+ * @copyright Ethereum Foundation ${new Date().getFullYear()}
+ * @license ${pkg.license}
+ * @see [Github]{@link ${pkg.homepage}}
+*/`
+
+export default {
+ input: "src/index.ts",
+ output: [
+ { file: pkg.exports.require, format: "cjs", banner },
+ { file: pkg.exports.import, format: "es", banner }
+ ],
+ external: [],
+ plugins: [
+ typescript({ tsconfig: "./build.tsconfig.json", useTsconfigDeclarationDir: true }),
+ cleanup({ comments: "jsdoc" })
+ ]
+}
diff --git a/packages/utils/rollup.iife.config.ts b/packages/utils/rollup.iife.config.ts
new file mode 100644
index 000000000..002d7d9f5
--- /dev/null
+++ b/packages/utils/rollup.iife.config.ts
@@ -0,0 +1,41 @@
+import fs from "fs"
+import cleanup from "rollup-plugin-cleanup"
+import nodePolyfills from "rollup-plugin-polyfill-node"
+import { terser } from "rollup-plugin-terser"
+import typescript from "rollup-plugin-typescript2"
+
+const pkg = JSON.parse(fs.readFileSync("./package.json", "utf8"))
+const banner = `/**
+ * @module ${pkg.name}
+ * @version ${pkg.version}
+ * @file ${pkg.description}
+ * @copyright Ethereum Foundation ${new Date().getFullYear()}
+ * @license ${pkg.license}
+ * @see [Github]{@link ${pkg.homepage}}
+*/`
+
+const name = pkg.name.substr(1).replace(/[-/]./g, (x) => x.toUpperCase()[1])
+
+export default {
+ input: "src/index.ts",
+ output: [
+ {
+ file: pkg.iife,
+ name,
+ format: "iife",
+ banner
+ },
+ {
+ file: pkg.unpkg,
+ name,
+ format: "iife",
+ plugins: [terser({ output: { preamble: banner } })]
+ }
+ ],
+ external: [],
+ plugins: [
+ typescript({ tsconfig: "./build.tsconfig.json", useTsconfigDeclarationDir: true }),
+ nodePolyfills({ include: null }),
+ cleanup({ comments: "jsdoc" })
+ ]
+}
diff --git a/packages/baby-jubjub/src/field.ts b/packages/utils/src/f1-field.ts
similarity index 98%
rename from packages/baby-jubjub/src/field.ts
rename to packages/utils/src/f1-field.ts
index 4f322b6e2..e4ef99db2 100644
--- a/packages/baby-jubjub/src/field.ts
+++ b/packages/utils/src/f1-field.ts
@@ -1,6 +1,6 @@
import * as scalar from "./scalar"
-export default class Field {
+export default class F1Field {
one = BigInt(1)
zero = BigInt(0)
diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
new file mode 100644
index 000000000..e5604aac3
--- /dev/null
+++ b/packages/utils/src/index.ts
@@ -0,0 +1,7 @@
+import F1Field from "./f1-field"
+import * as scalar from "./scalar"
+
+export { F1Field, scalar }
+export * from "./types"
+export * from "./number-checks"
+export * from "./number-conversions"
diff --git a/packages/utils/src/number-checks.ts b/packages/utils/src/number-checks.ts
new file mode 100644
index 000000000..ac2e443f1
--- /dev/null
+++ b/packages/utils/src/number-checks.ts
@@ -0,0 +1,25 @@
+import { BigNumber, BigNumberish } from "./types"
+
+export function isStringifiedBigint(s: BigNumber | string): boolean {
+ try {
+ BigInt(s)
+
+ return true
+ } catch (e) {
+ return false
+ }
+}
+
+export function isHexadecimal(s: string) {
+ return /^(0x|0X)[0-9a-fA-F]+$/.test(s)
+}
+
+export function isBigNumberish(value: BigNumberish): boolean {
+ return (
+ typeof value === "number" ||
+ typeof value === "bigint" ||
+ (typeof value === "string" && isStringifiedBigint(value)) ||
+ (typeof value === "string" && isHexadecimal(value)) ||
+ Buffer.isBuffer(value)
+ )
+}
diff --git a/packages/utils/src/number-conversions.ts b/packages/utils/src/number-conversions.ts
new file mode 100644
index 000000000..dc1c1e730
--- /dev/null
+++ b/packages/utils/src/number-conversions.ts
@@ -0,0 +1,59 @@
+import { BigNumberish } from "./types"
+import { isHexadecimal, isStringifiedBigint } from "./number-checks"
+
+export function bigintToHexadecimal(n: bigint) {
+ let hex = n.toString(16)
+
+ // Ensure even length.
+ if (hex.length % 2 !== 0) {
+ hex = `0${hex}`
+ }
+
+ return hex
+}
+
+export function bigNumberishToBuffer(value: BigNumberish): Buffer {
+ if (
+ typeof value === "number" ||
+ typeof value === "bigint" ||
+ (typeof value === "string" && isStringifiedBigint(value))
+ ) {
+ const hex = bigintToHexadecimal(BigInt(value))
+
+ return Buffer.from(hex, "hex")
+ }
+
+ return value as Buffer
+}
+
+export function bufferToBigint(buffer: Buffer): bigint {
+ return BigInt(`0x${buffer.toString("hex")}`)
+}
+
+export function bigNumberishToBigint(value: BigNumberish): bigint {
+ if (
+ typeof value === "number" ||
+ typeof value === "bigint" ||
+ (typeof value === "string" && isStringifiedBigint(value)) ||
+ (typeof value === "string" && isHexadecimal(value))
+ ) {
+ return BigInt(value)
+ }
+
+ return bufferToBigint(value as Buffer)
+}
+
+export function leBufferToBigint(buffer: Buffer): bigint {
+ return BigInt(`0x${buffer.reverse().toString("hex")}`)
+}
+
+export function leBigintToBuffer(n: bigint): Buffer {
+ const hex = bigintToHexadecimal(n)
+
+ // Allocate buffer of the desired size, filled with zeros.
+ const buffer = Buffer.alloc(32, 0)
+
+ Buffer.from(hex, "hex").reverse().copy(buffer)
+
+ return buffer
+}
diff --git a/packages/baby-jubjub/src/scalar.ts b/packages/utils/src/scalar.ts
similarity index 100%
rename from packages/baby-jubjub/src/scalar.ts
rename to packages/utils/src/scalar.ts
diff --git a/packages/utils/src/types/index.ts b/packages/utils/src/types/index.ts
new file mode 100644
index 000000000..327c62aad
--- /dev/null
+++ b/packages/utils/src/types/index.ts
@@ -0,0 +1,3 @@
+export type BigNumber = bigint | string
+
+export type BigNumberish = BigNumber | number | Buffer
diff --git a/packages/utils/tests/index.test.ts b/packages/utils/tests/index.test.ts
new file mode 100644
index 000000000..73a625252
--- /dev/null
+++ b/packages/utils/tests/index.test.ts
@@ -0,0 +1,27 @@
+import { F1Field } from "../src"
+
+describe("Utils", () => {
+ describe("F1Field", () => {
+ let field: F1Field
+
+ beforeEach(() => {
+ field = new F1Field(BigInt(12))
+ })
+
+ it("Should create a finite field with a specific order", async () => {
+ expect(field.one).toBe(BigInt(1))
+ expect(field.zero).toBe(BigInt(0))
+ expect(field._order).toBe(BigInt(12))
+ expect(field._half).toBe(BigInt(12) >> BigInt(1))
+ expect(field._negone).toBe(BigInt(12) - BigInt(1))
+ })
+
+ it("Should map the value back into the finite field", async () => {
+ const a = field.e(BigInt(24))
+ const b = field.e(BigInt(-2))
+
+ expect(a).toBe(BigInt(0))
+ expect(b).toBe(BigInt(10))
+ })
+ })
+})
diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json
new file mode 100644
index 000000000..71510a096
--- /dev/null
+++ b/packages/utils/tsconfig.json
@@ -0,0 +1,4 @@
+{
+ "extends": "../../tsconfig.json",
+ "include": ["src", "tests", "rollup.config.ts"]
+}
diff --git a/packages/utils/typedoc.json b/packages/utils/typedoc.json
new file mode 100644
index 000000000..77a471c91
--- /dev/null
+++ b/packages/utils/typedoc.json
@@ -0,0 +1,3 @@
+{
+ "entryPoints": ["src/index.ts"]
+}
diff --git a/yarn.lock b/yarn.lock
index 5a5b3e8fa..c273afd9d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4423,12 +4423,13 @@ __metadata:
languageName: node
linkType: hard
-"@zk-kit/baby-jubjub@workspace:packages/baby-jubjub":
+"@zk-kit/baby-jubjub@0.1.0, @zk-kit/baby-jubjub@workspace:packages/baby-jubjub":
version: 0.0.0-use.local
resolution: "@zk-kit/baby-jubjub@workspace:packages/baby-jubjub"
dependencies:
"@rollup/plugin-commonjs": ^25.0.7
"@rollup/plugin-node-resolve": ^15.2.3
+ "@zk-kit/utils": 0.1.0
circomlibjs: 0.0.8
rollup-plugin-cleanup: ^3.2.1
rollup-plugin-polyfill-node: ^0.13.0
@@ -4456,6 +4457,8 @@ __metadata:
dependencies:
"@rollup/plugin-commonjs": ^25.0.7
"@rollup/plugin-node-resolve": ^15.2.3
+ "@zk-kit/baby-jubjub": 0.1.0
+ "@zk-kit/utils": 0.1.0
blake-hash: 2.0.0
circomlibjs: 0.0.8
poseidon-lite: 0.2.0
@@ -4576,6 +4579,17 @@ __metadata:
languageName: unknown
linkType: soft
+"@zk-kit/utils@0.1.0, @zk-kit/utils@workspace:packages/utils":
+ version: 0.0.0-use.local
+ resolution: "@zk-kit/utils@workspace:packages/utils"
+ dependencies:
+ rollup-plugin-cleanup: ^3.2.1
+ rollup-plugin-polyfill-node: ^0.13.0
+ rollup-plugin-terser: ^7.0.2
+ rollup-plugin-typescript2: ^0.31.2
+ languageName: unknown
+ linkType: soft
+
"JSONStream@npm:^1.0.4":
version: 1.3.5
resolution: "JSONStream@npm:1.3.5"