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

refactor: public key compression #77

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
25 changes: 11 additions & 14 deletions circuits/circom/test/sha256Circuit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,18 @@ describe("SHA256 Circuit", () => {
hexToBigInt(hashMPk.y.toString()),
);

const public_key_compressed = Array.from(
Point.fromPrivateKey(testSecretKey).toRawBytes(true),
);

const sha_preimage_points: Point[] = [
Point.BASE,
Point.fromPrivateKey(testSecretKey),
hashMPkPoint,
nullifier,
rPoint,
hashedToCurveR,
];

const v1_sha256_preimage_bits = bufToSha256PaddedBitArr(
Buffer.from(
concatUint8Arrays(
sha_preimage_points.map((point) => point.toRawBytes(true)),
),
),
);
const v1_sha256_preimage_bit_length = parseInt(
v1_sha256_preimage_bits.slice(-64),
2,
);

const v1_binary_c = BigInt("0x" + c_v1)
.toString(2)
.split("")
Expand All @@ -65,7 +56,13 @@ describe("SHA256 Circuit", () => {
const p = path.join(__dirname, "./circuits/12_point_sha_256_test.circom");
const circuit = await wasm_tester(p, { json: true, sym: true });

const w = await circuit.calculateWitness({ coordinates }, true);
const w = await circuit.calculateWitness(
{
pk_compressed: public_key_compressed,
coordinates,
},
true,
);
await circuit.checkConstraints(w);
await circuit.assertOut(w, { out: v1_binary_c });
});
Expand Down
36 changes: 1 addition & 35 deletions circuits/circom/test/v1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,17 @@ import path from "path";
import { Point } from "@noble/secp256k1";
import { wasm as wasm_tester } from "circom_tester";
import { generate_inputs_from_array } from "secp256k1_hash_to_curve_circom/ts/generate_inputs";
import { bufToSha256PaddedBitArr } from "secp256k1_hash_to_curve_circom/ts/utils";
import { utils } from "ffjavascript";

import {
c_v1,
rPoint,
hashMPk,
hashedToCurveR,
nullifier,
s_v1,
testMessage,
testPublicKey,
testSecretKey,
} from "../../../javascript/test/consts";
import {
hexToBigInt,
concatUint8Arrays,
} from "../../../javascript/src/utils/encoding";
import { hexToBigInt } from "../../../javascript/src/utils/encoding";

import { pointToCircuitValue, scalarToCircuitValue } from "../utils";

Expand All @@ -30,37 +23,10 @@ describe("V1 Circuit", () => {
const public_key_bytes = Array.from(testPublicKey);
const message_bytes = Array.from(testMessage);

const hashMPkPoint = new Point(
hexToBigInt(hashMPk.x.toString()),
hexToBigInt(hashMPk.y.toString()),
);

const hash_to_curve_inputs = utils.stringifyBigInts(
generate_inputs_from_array(message_bytes.concat(public_key_bytes)),
);

const sha_preimage_points: Point[] = [
Point.BASE,
Point.fromPrivateKey(testSecretKey),
hashMPkPoint,
nullifier,
rPoint,
hashedToCurveR,
];

const v1_sha256_preimage_bits = bufToSha256PaddedBitArr(
Buffer.from(
concatUint8Arrays(
sha_preimage_points.map((point) => point.toRawBytes(true)),
),
),
);

const v1_sha256_preimage_bit_length = parseInt(
v1_sha256_preimage_bits.slice(-64),
2,
);

test("V1 circuit works", async () => {
const p = path.join(__dirname, "./circuits/v1_test.circom");
const circuit = await wasm_tester(p);
Expand Down
47 changes: 31 additions & 16 deletions circuits/circom/verify_nullifier.circom
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,16 @@ template plume_v1(n, k, message_length) {
signal input q1_x_mapped[4];
signal input q1_y_mapped[4];

// compressing public key here to avoid compressing it twice in both `check_ec_equations` and `sha256_12_coordinates`
component pk_compressor = compress_ec_point(n, k);
pk_compressor.uncompressed <== pk;

component check_ec_equations = check_ec_equations(n, k, message_length);

check_ec_equations.c <== c;
check_ec_equations.s <== s;
check_ec_equations.pk <== pk;
check_ec_equations.pk_compressed <== pk_compressor.compressed;
check_ec_equations.nullifier <== nullifier;

check_ec_equations.plume_message <== plume_message;
Expand All @@ -56,15 +61,15 @@ template plume_v1(n, k, message_length) {
var g[2][100];
g[0] = get_genx(n, k);
g[1] = get_geny(n, k);
c_sha256.pk_compressed <== pk_compressor.compressed;

for (var i = 0; i < 2; i++) {
for (var j = 0; j < k; j++) {
c_sha256.coordinates[i][j] <== g[i][j];
c_sha256.coordinates[2+i][j] <== pk[i][j];
c_sha256.coordinates[4+i][j] <== check_ec_equations.hashed_to_curve[i][j];
c_sha256.coordinates[6+i][j] <== nullifier[i][j];
c_sha256.coordinates[8+i][j] <== check_ec_equations.r_point[i][j];
c_sha256.coordinates[10+i][j] <== check_ec_equations.hashed_to_curve_r[i][j];
c_sha256.coordinates[2+i][j] <== check_ec_equations.hashed_to_curve[i][j];
c_sha256.coordinates[4+i][j] <== nullifier[i][j];
c_sha256.coordinates[6+i][j] <== check_ec_equations.r_point[i][j];
c_sha256.coordinates[8+i][j] <== check_ec_equations.hashed_to_curve_r[i][j];
}
}

Expand Down Expand Up @@ -112,11 +117,15 @@ template plume_v2(n, k, message_length) {
signal input q1_x_mapped[4];
signal input q1_y_mapped[4];

component pk_compressor = compress_ec_point(n, k);
pk_compressor.uncompressed <== pk;

component check_ec_equations = check_ec_equations(n, k, message_length);

check_ec_equations.c <== c;
check_ec_equations.s <== s;
check_ec_equations.pk <== pk;
check_ec_equations.pk_compressed <== pk_compressor.compressed;
check_ec_equations.nullifier <== nullifier;

check_ec_equations.plume_message <== plume_message;
Expand All @@ -142,6 +151,7 @@ template check_ec_equations(n, k, message_length) {
signal input s[k];
signal input plume_message[message_length];
signal input pk[2][k];
signal input pk_compressed[33];
signal input nullifier[2][k];

signal output r_point[2][k];
Expand Down Expand Up @@ -183,14 +193,10 @@ template check_ec_equations(n, k, message_length) {
component hash_to_curve = HashToCurve(message_length + 33);
for (var i = 0; i < message_length; i++) {
hash_to_curve.msg[i] <== plume_message[i];
}

component pk_compressor = compress_ec_point(n, k);

pk_compressor.uncompressed <== pk;
}

for (var i = 0; i < 33; i++) {
hash_to_curve.msg[message_length + i] <== pk_compressor.compressed[i];
hash_to_curve.msg[message_length + i] <== pk_compressed[i];
}

// Input precalculated values into HashToCurve
Expand Down Expand Up @@ -255,12 +261,13 @@ template a_div_b_pow_c(n, k) {
}

template sha256_12_coordinates(n, k) {
signal input coordinates[12][k];
signal input pk_compressed[33];
signal input coordinates[10][k];
signal output out[256];

// compress coordinates
component compressors[6];
for (var i = 0; i < 6; i++) {
component compressors[5];
for (var i = 0; i < 5; i++) {
compressors[i] = compress_ec_point(n, k);
compressors[i].uncompressed[0] <== coordinates[2*i];
compressors[i].uncompressed[1] <== coordinates[2*i + 1];
Expand All @@ -270,8 +277,16 @@ template sha256_12_coordinates(n, k) {
component binary[6*33];
for (var i = 0; i < 6; i++) { // for each compressor
for (var j = 0; j < 33; j++) { // for each byte
binary[33*i + j] = Num2Bits(8);
binary[33*i + j].in <== compressors[i].compressed[j];
if (i == 0) {
binary[33*i + j] = Num2Bits(8);
binary[33*i + j].in <== compressors[i].compressed[j];
} else if (i == 1) {
binary[33*i + j] = Num2Bits(8);
binary[33*i + j].in <== pk_compressed[j];
} else {
binary[33*i + j] = Num2Bits(8);
binary[33*i + j].in <== compressors[i-1].compressed[j];
}
}
}

Expand Down
Loading