Skip to content

Commit

Permalink
Merge pull request #935 from privacy-scaling-explorations/refactor/cr…
Browse files Browse the repository at this point in the history
…ypto-cleanup

refactor(crypto): improve package structure
  • Loading branch information
ctrlc03 authored Jan 5, 2024
2 parents c4949d7 + ed85bc5 commit 16f5205
Show file tree
Hide file tree
Showing 8 changed files with 385 additions and 368 deletions.
5 changes: 3 additions & 2 deletions crypto/ts/AccQueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { OptimisedMT as IncrementalQuinTree } from "optimisedmt";

import assert from "assert";

import type { Leaf, Queue, StringifiedBigInts } from "./types";

import { deepCopyBigIntArray, stringifyBigInts, unstringifyBigInts } from "./bigIntUtils";
import { sha256Hash, hashLeftRight, hash5 } from "./crypto";
import { Leaf, Queue, StringifiedBigInts } from "./types";
import { sha256Hash, hashLeftRight, hash5 } from "./hashing";
import { calcDepthFromNumLeaves } from "./utils";

/**
Expand Down
16 changes: 4 additions & 12 deletions crypto/ts/__tests__/Crypto.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { expect } from "chai";

import { G1Point, G2Point, genRandomBabyJubValue } from "../babyjub";
import { SNARK_FIELD_SIZE } from "../constants";
import {
genPubKey,
genKeypair,
genEcdhSharedKey,
sha256Hash,
hash2,
hash3,
Expand All @@ -13,19 +11,13 @@ import {
hash13,
hashLeftRight,
hashN,
hashOne,
poseidonT3,
poseidonT4,
poseidonT5,
poseidonT6,
genRandomSalt,
G1Point,
G2Point,
hashOne,
genRandomBabyJubValue,
genPrivKey,
packPubKey,
unpackPubKey,
} from "../crypto";
} from "../hashing";
import { genPubKey, genKeypair, genEcdhSharedKey, genRandomSalt, genPrivKey, packPubKey, unpackPubKey } from "../keys";

describe("Crypto", function test() {
this.timeout(100000);
Expand Down
131 changes: 131 additions & 0 deletions crypto/ts/babyjub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import assert from "assert";
import { randomBytes } from "crypto";

import { SNARK_FIELD_SIZE } from "./constants";
import { PrivKey } from "./types";

/**
* @notice A class representing a point on the first group (G1)
* of the Jubjub curve
*/
export class G1Point {
x: bigint;

y: bigint;

/**
* Create a new instance of G1Point
* @param x the x coordinate
* @param y the y coordinate
*/
constructor(x: bigint, y: bigint) {
assert(x < SNARK_FIELD_SIZE && x >= 0, "G1Point x out of range");
assert(y < SNARK_FIELD_SIZE && y >= 0, "G1Point y out of range");
this.x = x;
this.y = y;
}

/**
* Check whether two points are equal
* @param pt the point to compare with
* @returns whether they are equal or not
*/
equals(pt: G1Point): boolean {
return this.x === pt.x && this.y === pt.y;
}

/**
* Return the point as a contract param in the form of an object
* @returns the point as a contract param
*/
asContractParam(): { x: string; y: string } {
return {
x: this.x.toString(),
y: this.y.toString(),
};
}
}

/**
* @notice A class representing a point on the second group (G2)
* of the Jubjub curve. This is usually an extension field of the
* base field of the curve.
*/
export class G2Point {
x: bigint[];

y: bigint[];

/**
* Create a new instance of G2Point
* @param x the x coordinate
* @param y the y coordinate
*/
constructor(x: bigint[], y: bigint[]) {
this.checkPointsRange(x, "x");
this.checkPointsRange(y, "y");

this.x = x;
this.y = y;
}

/**
* Check whether two points are equal
* @param pt the point to compare with
* @returns whether they are equal or not
*/
equals(pt: G2Point): boolean {
return this.x[0] === pt.x[0] && this.x[1] === pt.x[1] && this.y[0] === pt.y[0] && this.y[1] === pt.y[1];
}

/**
* Return the point as a contract param in the form of an object
* @returns the point as a contract param
*/
asContractParam(): { x: string[]; y: string[] } {
return {
x: this.x.map((n) => n.toString()),
y: this.y.map((n) => n.toString()),
};
}

/**
* Check whether the points are in range
* @param x the x coordinate
* @param type the type of the coordinate
*/
private checkPointsRange(x: bigint[], type: "x" | "y") {
assert(
x.every((n) => n < SNARK_FIELD_SIZE && n >= 0),
`G2Point ${type} out of range`,
);
}
}

/**
* Returns a BabyJub-compatible random value. We create it by first generating
* a random value (initially 256 bits large) modulo the snark field size as
* described in EIP197. This results in a key size of roughly 253 bits and no
* more than 254 bits. To prevent modulo bias, we then use this efficient
* algorithm:
* http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/lib/libc/crypt/arc4random_uniform.c
* @returns A BabyJub-compatible random value.
*/
export const genRandomBabyJubValue = (): bigint => {
// Prevent modulo bias
// const lim = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000')
// const min = (lim - SNARK_FIELD_SIZE) % SNARK_FIELD_SIZE
const min = BigInt("6350874878119819312338956282401532410528162663560392320966563075034087161851");

let privKey: PrivKey = SNARK_FIELD_SIZE;

do {
const rand = BigInt(`0x${randomBytes(32).toString("hex")}`);

if (rand >= min) {
privKey = rand % SNARK_FIELD_SIZE;
}
} while (privKey >= SNARK_FIELD_SIZE);

return privKey;
};
Loading

0 comments on commit 16f5205

Please sign in to comment.