Skip to content

Commit

Permalink
allow for precomputed arguments in proving and verification, make nul…
Browse files Browse the repository at this point in the history
…lifier randomness required
  • Loading branch information
AndrewCLu committed Oct 12, 2023
1 parent 7043c9f commit 5753666
Show file tree
Hide file tree
Showing 12 changed files with 534 additions and 288 deletions.
6 changes: 4 additions & 2 deletions packages/lib/package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
"name": "babyjubjub-ecdsa",
"version": "1.0.11",
"version": "1.0.12",
"main": "build/lib.js",
"license": "MIT",
"dependencies": {
"@types/uuid": "^9.0.5",
"circomlibjs": "^0.1.7",
"elliptic": "^6.5.4",
"snarkjs": "^0.7.1"
"snarkjs": "^0.7.1",
"uuid": "^9.0.1"
},
"devDependencies": {
"@types/jest": "^29.5.5",
Expand Down
16 changes: 10 additions & 6 deletions packages/lib/src/ecdsa.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const ECSignature = require("elliptic/lib/elliptic/ec/signature");
const BN = require("bn.js");
import { WeierstrassPoint, babyjubjub } from "./babyJubjub";
import { EdwardsPoint, WeierstrassPoint, babyjubjub } from "./babyJubjub";
import { Signature } from "./types";

/**
Expand Down Expand Up @@ -101,20 +101,24 @@ export const recoverPubKeyIndexFromSignature = (
* @returns - The public parameters T, U
*/
export const computeTUFromR = (
R: WeierstrassPoint,
R: EdwardsPoint,
msgHash: bigint
): { T: WeierstrassPoint; U: WeierstrassPoint } => {
): { T: EdwardsPoint; U: EdwardsPoint } => {
const Fs = babyjubjub.Fs;

const r = R.x % Fs.p;
const shortR = R.toWeierstrass();
const r = shortR.x % Fs.p;
const rInv = Fs.inv(r);
const ecR = babyjubjub.ec.curve.point(R.x.toString(16), R.y.toString(16));
const ecR = babyjubjub.ec.curve.point(
shortR.x.toString(16),
shortR.y.toString(16)
);
const ecT = ecR.mul(rInv.toString(16));
const T = WeierstrassPoint.fromEllipticPoint(ecT);
const G = babyjubjub.ec.curve.g;
const rInvm = Fs.neg(Fs.mul(rInv, msgHash));
const ecU = G.mul(rInvm.toString(16));
const U = WeierstrassPoint.fromEllipticPoint(ecU);

return { T, U };
return { T: T.toEdwards(), U: U.toEdwards() };
};
37 changes: 20 additions & 17 deletions packages/lib/src/inputGen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ import { EdwardsPoint, WeierstrassPoint, babyjubjub } from "./babyJubjub";
import { Signature, MerkleProof } from "./types";
import { hashEdwardsPublicKey, hexToBigInt } from "./utils";

export const MERKLE_TREE_DEPTH = 8; // We used a fixed depth merkle tree for now
// Precomputed hashes of zero for each layer of the merkle tree
export const MERKLE_TREE_ZEROS = [
"0",
"14744269619966411208579211824598458697587494354926760081771325075741142829156",
"7423237065226347324353380772367382631490014989348495481811164164159255474657",
"11286972368698509976183087595462810875513684078608517520839298933882497716792",
"3607627140608796879659380071776844901612302623152076817094415224584923813162",
"19712377064642672829441595136074946683621277828620209496774504837737984048981",
"20775607673010627194014556968476266066927294572720319469184847051418138353016",
"3396914609616007258851405644437304192397291162432396347162513310381425243293",
];

/**
* Computes the merkle root based a list of public keys
* Note that public keys must be in Twisted Edwards form
Expand All @@ -18,7 +31,7 @@ export const computeMerkleRoot = async (
pubKeys: EdwardsPoint[],
hashFn?: any
): Promise<bigint> => {
const proof = await generateMerkleProof(pubKeys, 0, hashFn);
const proof = await computeMerkleProof(pubKeys, 0, hashFn);
return proof.root;
};

Expand All @@ -30,23 +43,11 @@ export const computeMerkleRoot = async (
* @param hashFn - The hash function to use for the merkle tree. Defaults to Poseidon
* @returns - The merkle proof
*/
export const generateMerkleProof = async (
export const computeMerkleProof = async (
pubKeys: EdwardsPoint[],
index: number,
hashFn?: any
): Promise<MerkleProof> => {
const TREE_DEPTH = 8; // We used a fixed depth merkle tree for now
// Precomputed hashes of zero for each layer of the merkle tree
const ZEROS = [
"0",
"14744269619966411208579211824598458697587494354926760081771325075741142829156",
"7423237065226347324353380772367382631490014989348495481811164164159255474657",
"11286972368698509976183087595462810875513684078608517520839298933882497716792",
"3607627140608796879659380071776844901612302623152076817094415224584923813162",
"19712377064642672829441595136074946683621277828620209496774504837737984048981",
"20775607673010627194014556968476266066927294572720319469184847051418138353016",
"3396914609616007258851405644437304192397291162432396347162513310381425243293",
];
// Building poseidon actually takes a while, so it's best if it is passed in for client side proving
const poseidon = hashFn === undefined ? await buildPoseidon() : hashFn;

Expand All @@ -60,19 +61,21 @@ export const generateMerkleProof = async (
let pathIndices: number[] = [];
let siblings: bigint[] = [];

for (let i = 0; i < TREE_DEPTH; i++) {
for (let i = 0; i < MERKLE_TREE_DEPTH; i++) {
pathIndices.push(index % 2);
const siblingIndex = index % 2 === 0 ? index + 1 : index - 1;
const sibling =
siblingIndex === prevLayer.length
? BigInt(ZEROS[i])
? BigInt(MERKLE_TREE_ZEROS[i])
: prevLayer[siblingIndex];
siblings.push(sibling);
index = Math.floor(index / 2);

for (let j = 0; j < prevLayer.length; j += 2) {
const secondNode =
j + 1 === prevLayer.length ? BigInt(ZEROS[i]) : prevLayer[j + 1];
j + 1 === prevLayer.length
? BigInt(MERKLE_TREE_ZEROS[i])
: prevLayer[j + 1];
const nextNode = poseidon([prevLayer[j], secondNode]);
nextLayer.push(hexToBigInt(poseidon.F.toString(nextNode, 16)));
}
Expand Down
Loading

0 comments on commit 5753666

Please sign in to comment.