|
| 1 | +pragma circom 2.0.0; |
| 2 | + |
| 3 | +/* |
| 4 | + * Decomposes `in` into `b` bits, given by `bits`. |
| 5 | + * Least significant bit in `bits[0]`. |
| 6 | + * Enforces that `in` is at most `b` bits long. |
| 7 | + */ |
| 8 | +template Num2Bits(b) { |
| 9 | + signal input in; |
| 10 | + signal output bits[b]; |
| 11 | + |
| 12 | + // First, compute the bit values |
| 13 | + for (var i = 0; i < b; i++) { |
| 14 | + // Use `<--` to assign to a signal without constraining it. |
| 15 | + // While our constraints can only use multiplication/addition, our |
| 16 | + // assignments can use any operation. |
| 17 | + bits[i] <-- (in >> i) & 1; |
| 18 | + } |
| 19 | + |
| 20 | + // Now, contrain each bit to be 0 or 1. |
| 21 | + for (var i = 0; i < b; i++) { |
| 22 | + // Use `===` to enforce a rank-1 constraint (R1C) on signals. |
| 23 | + bits[i] * (1 - bits[i]) === 0; |
| 24 | + // ^--A--^ ^-----B-----^ C |
| 25 | + // |
| 26 | + // The linear combinations A, B, and C in this R1C. |
| 27 | + } |
| 28 | + |
| 29 | + // Now, construct a sum of all the bits. |
| 30 | + // Note that var is a linear combination of signals since the `(2 ** i)` terms are constants. |
| 31 | + var sum_of_bits = 0; |
| 32 | + for (var i = 0; i < b; i++) { |
| 33 | + sum_of_bits += (2 ** i) * bits[i]; |
| 34 | + } |
| 35 | + // Constrain that `sum` is equal to the input `in`. |
| 36 | + sum_of_bits === in; |
| 37 | +} |
| 38 | + |
| 39 | +// Now we look at `SmallOdd`, a circuit which features: |
| 40 | +// |
| 41 | +// * the use of components, or sub-circuits |
| 42 | +// * the `<==` operator, which combines `<--` and `===`. |
| 43 | + |
| 44 | +/* |
| 45 | + * Enforces that `in` is an odd number less than 2 ** `b`. |
| 46 | + */ |
| 47 | +template SmallOdd(b) { |
| 48 | + signal input in; |
| 49 | + |
| 50 | + // Declare and intialize a sub-circuit; |
| 51 | + component binaryDecomposition = Num2Bits(b); |
| 52 | + |
| 53 | + // Use `<==` to **assign** and **constrain** simultaneously. |
| 54 | + binaryDecomposition.in <== in; |
| 55 | + |
| 56 | + // Constrain the least significant bit to be 1. |
| 57 | + binaryDecomposition.bits[0] === 1; |
| 58 | +} |
| 59 | + |
| 60 | +// Next we look at `SmallOddFactorization`, a circuit which features: |
| 61 | +// |
| 62 | +// * arrays of components |
| 63 | +// * using helper (witness) signals to express multiple multiplications |
| 64 | +// * (or any iterator general computation) |
| 65 | + |
| 66 | +/* |
| 67 | + * Enforces the factorization of `product` into `n` odd factors that are each |
| 68 | + * less than 2 ** `b`. |
| 69 | + */ |
| 70 | +template SmallOddFactorization(n, b) { |
| 71 | + signal input product; |
| 72 | + signal input factors[n]; |
| 73 | + |
| 74 | + // Constrain each factor to be small and odd. |
| 75 | + // We're going to need `n` subcircuits for small-odd-ness. |
| 76 | + component smallOdd[n]; |
| 77 | + for (var i = 0; i < n; i++) { |
| 78 | + smallOdd[i] = SmallOdd(b); |
| 79 | + smallOdd[i].in <== factors[i]; |
| 80 | + } |
| 81 | + |
| 82 | + // Now constrain the factors to multiply to the product. Since there are |
| 83 | + // many multiplications, we introduce helper signals to split the |
| 84 | + // multiplications up into R1Cs. |
| 85 | + signal partialProducts[n + 1]; |
| 86 | + partialProducts[0] <== 1; |
| 87 | + for (var i = 0; i < n; i++) { |
| 88 | + partialProducts[i + 1] <== partialProducts[i] * factors[i]; |
| 89 | + } |
| 90 | + product === partialProducts[n]; |
| 91 | +} |
| 92 | + |
| 93 | +// Finally, we set the `main` circuit for this file, which is the circuit that |
| 94 | +// `circom` will synthesize. |
| 95 | +component main {public [product]} = SmallOddFactorization(3, 8); |
0 commit comments