Skip to content

Commit

Permalink
Merge pull request #195 from privacy-scaling-explorations/feat/maci-c…
Browse files Browse the repository at this point in the history
…ircuits

Add MACI template circuits
  • Loading branch information
0xjei committed Mar 11, 2024
2 parents 9001fde + 296955e commit f2204ee
Show file tree
Hide file tree
Showing 9 changed files with 1,473 additions and 0 deletions.
76 changes: 76 additions & 0 deletions packages/circuits/circom/circuits.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,81 @@
"file": "eddsa-proof",
"template": "EddsaProof",
"pubs": ["scope"]
},
"ecdh": {
"file": "ecdh",
"template": "Ecdh",
"pubs": ["publicKey"],
"params": []
},
"msb": {
"file": "float",
"template": "MSB",
"params": [252]
},
"shift": {
"file": "float",
"template": "Shift",
"params": [252]
},
"integer-division": {
"file": "float",
"template": "IntegerDivision",
"params": [252]
},
"to-float": {
"file": "float",
"template": "ToFloat",
"params": [74]
},
"division-from-float": {
"file": "float",
"template": "DivisionFromFloat",
"params": [74, 251]
},
"division-from-normal": {
"file": "float",
"template": "DivisionFromNormal",
"params": [74, 251]
},
"multiplication-from-float": {
"file": "float",
"template": "MultiplicationFromFloat",
"params": [74, 251]
},
"multiplication-from-normal": {
"file": "float",
"template": "MultiplicationFromNormal",
"params": [74, 251]
},
"safe-less-than": {
"file": "safe-comparators",
"template": "SafeLessThan",
"pubs": ["in"],
"params": [252]
},
"safe-less-eq-than": {
"file": "safe-comparators",
"template": "SafeLessEqThan",
"pubs": ["in"],
"params": [252]
},
"safe-greater-than": {
"file": "safe-comparators",
"template": "SafeGreaterThan",
"pubs": ["in"],
"params": [252]
},
"safe-greater-eq-than": {
"file": "safe-comparators",
"template": "SafeGreaterEqThan",
"pubs": ["in"],
"params": [252]
},
"unpack-element": {
"file": "unpack-element",
"template": "UnpackElement",
"params": [4],
"pubs": ["in"]
}
}
30 changes: 30 additions & 0 deletions packages/circuits/circom/ecdh.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
pragma circom 2.1.5;

// circomlib imports
include "./bitify.circom";
include "./escalarmulany.circom";

// ECDH Is a a template which allows to generate a shared secret
// from a private key and a public key
// on the baby jubjub curve
// It is important that the private key is hashed and pruned first
// which can be accomplished using the function
// deriveScalar from @zk-kit/baby-jubjub
template Ecdh() {
// the private key must pass through deriveScalar first
signal input privateKey;
signal input publicKey[2];

signal output sharedKey[2];

// convert the private key to its bits representation
var out[253];
out = Num2Bits(253)(privateKey);

// multiply the public key by the private key
var mulFix[2];
mulFix = EscalarMulAny(253)(out, publicKey);

// we can then wire the output to the shared secret signal
sharedKey <== mulFix;
}
205 changes: 205 additions & 0 deletions packages/circuits/circom/float.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
pragma circom 2.1.5;

include "./bitify.circom";
include "./comparators.circom";
include "./mux1.circom";

// Template to determine the most significant bit (MSB) of an input number.
template MSB(n) {
signal input in;
signal output out;

// Convert the number to its bit representation.
var n2b[n];
n2b = Num2Bits(n)(in);

// Assign the MSB to the output.
out <== n2b[n-1];
}

// Template for bit-shifting a dividend and partial remainder.
template Shift(n) {
// Dividend.
signal input dividend;
// Remainder.
signal input remainder;

// Shifted dividend.
signal output outDividend;
// Partial remainder (updated).
signal output outRemainder;

// Determine the MSB of the dividend.
var lmsb;
lmsb = MSB(n)(dividend);

// Shift the dividend.
outDividend <== dividend - lmsb * 2 ** (n - 1);

// Update the partial remainder.
outRemainder <== remainder * 2 + lmsb;
}

// Template for performing integer division.
template IntegerDivision(n) {
// Dividend.
signal input a;
// Divisor.
signal input b;
// Quotient.
signal output c;

// Ensure inputs are within the valid range.
var lta;
var ltb;

lta = LessThan(252)([a, 2**n]);
ltb = LessThan(252)([b, 2**n]);

assert(lta == 1);
assert(ltb == 1);

// Ensure the divisor 'b' is not zero.
var isz;

isz = IsZero()(b);

assert(isz == 0);

// Prepare variables for division.
var dividend = a;
var remainder = 0;

var bits[n];

// Loop to perform division through bit-shifting and subtraction.
for (var i = n - 1; i >= 0; i--) {
// Shift 'dividend' and 'rem' and determine if 'b' can be subtracted from the new 'rem'.
var shiftedDividend;
var shiftedRem;

(shiftedDividend, shiftedRem) = Shift(i + 1)(dividend, remainder);

// Determine if 'b' <= 'rem'.
var canSubtract;

canSubtract = LessEqThan(n)([b, shiftedRem]);

// Select 1 if 'b' can be subtracted (i.e., 'b' <= 'rem'), else select 0.
var subtractBit;

subtractBit = Mux1()([0, 1], canSubtract);

// Subtract 'b' from 'rem' if possible, and set the corresponding bit in 'bits'.
bits[i] = subtractBit;

remainder = shiftedRem - b * subtractBit;

// Prepare 'dividend' for the next iteration.
dividend = shiftedDividend;
}

// Convert the bit array representing the quotient into a number.
c <== Bits2Num(n)(bits);
}

// Converts an integer to its floating-point representation by multiplying it with 10^W.
template ToFloat(W) {
// Assert W to ensure the result is within the range of 2^252.
assert(W < 75);

signal input in;

signal output out;

// Ensure the input multiplied by 10^W is less than 10^75 to prevent overflow.
var lt;

lt = LessEqThan(252)([in, 10 ** (75 - W)]);

assert(lt == 1);

// Convert the integer to floating-point by multiplying with 10^W.
out <== in * (10**W);
}

// Performs division on floating-point numbers represented with W decimal digits.
template DivisionFromFloat(W, n) {
// Ensure W is within the valid range for floating-point representation.
assert(W < 75);
// Ensure n, the bit-width of inputs, is within a valid range.
assert(n < 252);

// Numerator.
signal input a;
// Denominator.
signal input b;
// Quotient.
signal output c;

// Ensure the numerator 'a' is within the range of valid floating-point numbers.
var lt;

lt = LessEqThan(252)([a, 10 ** (75 - W)]);

assert(lt == 1);

// Use IntegerDivision for division operation.
c <== IntegerDivision(n)(a * (10 ** W), b);
}

// Performs division on integers by first converting them to floating-point representation.
template DivisionFromNormal(W, n) {
// Numerator.
signal input a;
// Denominator.
signal input b;
// Quotient.
signal output c;

// Convert input to float and perform division.
c <== DivisionFromFloat(W, n)(ToFloat(W)(a), ToFloat(W)(b));
}

// Performs multiplication on floating-point numbers and converts the result back to integer form.
template MultiplicationFromFloat(W, n) {
// Ensure W is within the valid range for floating-point representation.
assert(W < 75);
// Ensure n, the bit-width of inputs, is within a valid range.
assert(n < 252);
// Ensure scaling factor is within the range of 'n' bits.
assert(10**W < 2**n);

// Multiplicand.
signal input a;
// Multiplier.
signal input b;
// Product.
signal output c;

// Ensure both inputs 'a' and 'b' are within a valid range for multiplication.
var lta;
var ltb;

lta = LessEqThan(252)([a, 2 ** 126]);
ltb = LessEqThan(252)([b, 2 ** 126]);

assert(lta == 1);
assert(ltb == 1);

// Perform integer division after multiplication to adjust the result back to W decimal digits.
c <== IntegerDivision(n)(a * b, 10 ** W);
}

// Performs multiplication on integers by first converting them to floating-point representation.
template MultiplicationFromNormal(W, n) {
// Multiplicand.
signal input a;
// Multiplier.
signal input b;
// Product.
signal output c;

// Convert input to float and perform multiplication.
c <== MultiplicationFromFloat(W, n)(ToFloat(W)(a), ToFloat(W)(b));
}
60 changes: 60 additions & 0 deletions packages/circuits/circom/safe-comparators.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
pragma circom 2.0.0;

include "./bitify.circom";

// Template for safely comparing if one input is less than another,
// ensuring inputs are within a specified bit-length.
template SafeLessThan(n) {
// Ensure the bit-length does not exceed 252 bits.
assert(n <= 252);

signal input in[2];
signal output out;

// Convert both inputs to their bit representations to ensure
// they fit within 'n' bits.
var n2b1[n];
n2b1 = Num2Bits(n)(in[0]);

var n2b2[n];
n2b2 = Num2Bits(n)(in[1]);

// Additional conversion to handle arithmetic operation and capture the comparison result.
var n2b[n+1];
n2b = Num2Bits(n + 1)(in[0] + (1<<n) - in[1]);

// Determine if in[0] is less than in[1] based on the most significant bit.
out <== 1 - n2b[n];
}

// Template to check if one input is less than or equal to another.
template SafeLessEqThan(n) {
signal input in[2];
signal output out;

// Use SafeLessThan to determine if in[0] is less than in[1] + 1.
out <== SafeLessThan(n)([in[0], in[1] + 1]);
}

// Template for safely comparing if one input is greater than another.
template SafeGreaterThan(n) {
// Two inputs to compare.
signal input in[2];
// Output signal indicating comparison result.
signal output out;

// Invert the inputs for SafeLessThan to check if in[1] is less than in[0].
out <== SafeLessThan(n)([in[1], in[0]]);
}

// Template to check if one input is greater than or equal to another.
template SafeGreaterEqThan(n) {
// Two inputs to compare.
signal input in[2];
// Output signal indicating comparison result.
signal output out;

// Invert the inputs and adjust for equality in SafeLessThan to
// check if in[1] is less than or equal to in[0].
out <== SafeLessThan(n)([in[1], in[0] + 1]);
}
Loading

0 comments on commit f2204ee

Please sign in to comment.