Skip to content

Commit

Permalink
feat: further update to support public inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
enricobottazzi committed May 2, 2024
1 parent eb96331 commit 4a06ab4
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 49 deletions.
69 changes: 42 additions & 27 deletions scripts/circuit_sk.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ def main(args):

# initiate counters for the number of advice cells needed for each constraint phase
phase_0_assignment_advice_cell_count = 0
phase_1_assignment_advice_cell_count = 0
phase_1_range_check_advice_cell_count = 0
phase_1_eval_at_gamma_constraint_advice_cell_count = 0
phase_1_encryption_constraint_advice_cell_count = 0
Expand All @@ -164,6 +163,8 @@ def main(args):

r1is_assigned = []
r2is_assigned = []
ais_assigned = []
ct0is_assigned = []

for i in range(len(ctis)):
r1i_assigned = assign_to_circuit(r1is[i], p)
Expand All @@ -174,42 +175,45 @@ def main(args):
phase_0_assignment_advice_cell_count += len(r1i_assigned.coefficients)
phase_0_assignment_advice_cell_count += len(r2i_assigned.coefficients)

ai_assigned = assign_to_circuit(ais[i], p)
ct0i_assigned = assign_to_circuit(ct0is[i], p)
ais_assigned.append(ai_assigned)
ct0is_assigned.append(ct0i_assigned)

phase_0_assignment_advice_cell_count += len(ai_assigned.coefficients)
phase_0_assignment_advice_cell_count += len(ct0i_assigned.coefficients)

# For the sake of simplicity, we generate a random challenge here
gamma = randint(0, 1000)

'''
CIRCUIT - PHASE 1 - ASSIGNMENT
CIRCUIT - PHASE 1
'''

# Every assigned value must be an element of the field Zp. Negative coefficients `-z` are assigned as `p - z`
ais_at_gamma_assigned = []
ct0is_at_gamma_assigned = []
# ais_at_gamma_assigned = []
# ct0is_at_gamma_assigned = []
qi_constants = []
k0i_constants = []

for i in range(len(ctis)):
ai_at_gamma = ais[i].evaluate(gamma)
ai_at_gamma_assigned = assign_to_circuit(Polynomial([ai_at_gamma]), p).coefficients[0]
ais_at_gamma_assigned.append(ai_at_gamma_assigned)
# ai_at_gamma = ais[i].evaluate(gamma)
# ai_at_gamma_assigned = assign_to_circuit(Polynomial([ai_at_gamma]), p).coefficients[0]
# ais_at_gamma_assigned.append(ai_at_gamma_assigned)

phase_1_assignment_advice_cell_count += 1
# phase_1_assignment_advice_cell_count += 1

ct0i_at_gamma = ctis[i][0].evaluate(gamma)
ct0i_at_gamma_assigned = assign_to_circuit(Polynomial([ct0i_at_gamma]), p).coefficients[0]
ct0is_at_gamma_assigned.append(ct0i_at_gamma_assigned)
# ct0i_at_gamma = ctis[i][0].evaluate(gamma)
# ct0i_at_gamma_assigned = assign_to_circuit(Polynomial([ct0i_at_gamma]), p).coefficients[0]
# ct0is_at_gamma_assigned.append(ct0i_at_gamma_assigned)

phase_1_assignment_advice_cell_count += 1
# phase_1_assignment_advice_cell_count += 1

qi_constants.append(qis[i])

k0i_constant = assign_to_circuit(Polynomial([k0is[i]]), p).coefficients[0]
k0i_constants.append(k0i_constant)

cyclo_at_gamma = cyclo.evaluate(gamma)
cyclo_at_gamma_assigned = assign_to_circuit(Polynomial([cyclo_at_gamma]), p).coefficients[0]

phase_1_assignment_advice_cell_count += 1

'''
CIRCUIT - PHASE 1 - RANGE CHECK
'''
Expand Down Expand Up @@ -258,6 +262,16 @@ def main(args):
k1_at_gamma_assigned = k1_assigned.evaluate(gamma)
phase_1_eval_at_gamma_constraint_advice_cell_count += len(k1_assigned.coefficients) * 2 - 1

cyclo_at_gamma = cyclo.evaluate(gamma)
cyclo_at_gamma_assigned = assign_to_circuit(Polynomial([cyclo_at_gamma]), p).coefficients[0]
n_bits_N = n.bit_length()

# This corresponds to `load_rlc_cache`
phase_1_eval_at_gamma_constraint_advice_cell_count += (n_bits_N - 1) * 4
# This corresponds to `add`
phase_1_eval_at_gamma_constraint_advice_cell_count += 4


for i in range(len(ctis)):
# sanity check. The coefficients of ct0i should be in the range [-(qi-1)/2, (qi-1)/2]
bound = int((qis[i] - 1) / 2)
Expand Down Expand Up @@ -337,12 +351,15 @@ def main(args):
phase_1_eval_at_gamma_constraint_advice_cell_count += len(r1is_assigned[i].coefficients) * 2 - 1
phase_1_eval_at_gamma_constraint_advice_cell_count += len(r2is_assigned[i].coefficients) * 2 - 1

ai_gamma_assigned = ais_assigned[i].evaluate(gamma)
ct0i_gamma_assigned = ct0is_assigned[i].evaluate(gamma)

'''
CIRCUIT - PHASE 1 - CORRECT ENCRYPTION CONSTRAINT
'''

lhs = ct0is_at_gamma_assigned[i]
rhs = (ais_at_gamma_assigned[i] * s_at_gamma_assigned + e_at_gamma_assigned + (k1_at_gamma_assigned * k0i_constants[i]) + (r1i_gamma_assigned * qi_constants[i]) + (r2i_gamma_assigned * cyclo_at_gamma_assigned))
lhs = ct0i_gamma_assigned
rhs = (ai_gamma_assigned * s_at_gamma_assigned + e_at_gamma_assigned + (k1_at_gamma_assigned * k0i_constants[i]) + (r1i_gamma_assigned * qi_constants[i]) + (r2i_gamma_assigned * cyclo_at_gamma_assigned))
phase_1_encryption_constraint_advice_cell_count += 16

assert lhs % p == rhs % p
Expand All @@ -355,22 +372,20 @@ def main(args):
cyclo_at_gamma_assigned_expected = assign_to_circuit(Polynomial([cyclo_at_gamma]), p).coefficients[0]
assert cyclo_at_gamma_assigned == cyclo_at_gamma_assigned_expected

ai_gamma = ais[i].evaluate(gamma)
ai_gamma_assigned_expected = assign_to_circuit(Polynomial([ai_gamma]), p).coefficients[0]
assert ais_at_gamma_assigned[i] == ai_gamma_assigned_expected
ai_gamma_assigned_expected = ais_assigned[i].evaluate(gamma)
assert ai_gamma_assigned == ai_gamma_assigned_expected

ct0i_gamma = ctis[i][0].evaluate(gamma)
ct0i_gamma_assigned_expected = assign_to_circuit(Polynomial([ct0i_gamma]), p).coefficients[0]
assert ct0is_at_gamma_assigned[i] == ct0i_gamma_assigned_expected
ct0i_gamma_assigned_expected = ct0is_assigned[i].evaluate(gamma)
assert ct0i_gamma_assigned == ct0i_gamma_assigned_expected

assert qis[i] == qi_constants[i]

k0i_assigned_expected = assign_to_circuit(Polynomial([k0is[i]]), p).coefficients[0]
assert k0i_constants[i] == k0i_assigned_expected

total_advice_cell_count = phase_0_assignment_advice_cell_count + phase_1_assignment_advice_cell_count + phase_1_range_check_advice_cell_count + phase_1_eval_at_gamma_constraint_advice_cell_count + phase_1_encryption_constraint_advice_cell_count
total_advice_cell_count = phase_0_assignment_advice_cell_count + phase_1_range_check_advice_cell_count + phase_1_eval_at_gamma_constraint_advice_cell_count + phase_1_encryption_constraint_advice_cell_count

print_advice_cells_info(total_advice_cell_count, phase_0_assignment_advice_cell_count, phase_1_assignment_advice_cell_count, phase_1_range_check_advice_cell_count, phase_1_eval_at_gamma_constraint_advice_cell_count, phase_1_encryption_constraint_advice_cell_count)
print_advice_cells_info(total_advice_cell_count, phase_0_assignment_advice_cell_count, phase_1_range_check_advice_cell_count, phase_1_eval_at_gamma_constraint_advice_cell_count, phase_1_encryption_constraint_advice_cell_count)
# ais and ct0is need to be parsed such that their coefficients are in the range [0, p - 1]
# we don't call them assigned because they are never assigned to the circuit
ais_in_p = [assign_to_circuit(ai, p) for ai in ais]
Expand Down
5 changes: 1 addition & 4 deletions scripts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,13 @@ def count_advice_cells_needed_for_poly_range_check(poly: Polynomial, bound: int,

return count

def print_advice_cells_info(total_advice_cell_count, phase_0_count, phase_1_assignment_count, phase_1_range_check_count, phase_1_eval_at_gamma_count, phase_1_encryption_constraint_count):
def print_advice_cells_info(total_advice_cell_count, phase_0_count, phase_1_range_check_count, phase_1_eval_at_gamma_count, phase_1_encryption_constraint_count):
print("Halo2 Circuit Profile:")
print(f"Total Advice Cells Needed: {total_advice_cell_count}")

print("\nPhase 0 - Assignment:")
print(f" - Count: {phase_0_count}, Percentage: {(phase_0_count / total_advice_cell_count) * 100:.2f}%")

print("\nPhase 1 - Assignment:")
print(f" - Count: {phase_1_assignment_count}, Percentage: {(phase_1_assignment_count / total_advice_cell_count) * 100:.2f}%")

print("\nPhase 1 - Range Check:")
print(f" - Count: {phase_1_range_check_count}, Percentage: {(phase_1_range_check_count / total_advice_cell_count) * 100:.2f}%")

Expand Down
2 changes: 1 addition & 1 deletion src/data/sk_enc_4096_2x55_65537.json

Large diffs are not rendered by default.

26 changes: 9 additions & 17 deletions src/sk_encryption_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl<F: ScalarField> RlcCircuitInstructions<F> for BfvSkEncryptionCircuit {
/// In this phase, the polynomials for each matrix $S_i$ are assigned to the circuit. Namely:
/// * polynomials `s`, `e`, `k1` are assigned to the witness table. This has to be done only once as these polynomial are common to each $S_i$ matrix
/// * polynomials `r1i`, `r2i` are assigned to the witness table for each $S_i$ matrix
/// * polynomials `ai`, `ct0i` are assigned to the witness table for each $S_i$ matrix
/// * polynomials `ai`, `ct0i` are assigned to the witness table for each $S_i$ matrix and exposed as public inputs

/// Witness values are element of the finite field $\mod{p}$. Negative coefficients $-z$ are assigned as field elements $p - z$.

Expand Down Expand Up @@ -145,14 +145,6 @@ impl<F: ScalarField> RlcCircuitInstructions<F> for BfvSkEncryptionCircuit {
/// - The coefficients of $S_i$ are in the expected range.
/// - $U_i(\gamma) \times S_i(\gamma) =Ct_{0,i}(\gamma)$

/// ##### Assignment
/// * Assign evaluations to the circuit: `ai(gamma)`, `ct0i(gamma)` for each $U_i$ matrix
/// * Assign `cyclo(gamma)` to the circuit. This has to be done only once as the cyclotomic polynomial is common to each $U_i$ matrix
/// * Expose `ai(gamma)`, `ct0i(gamma)` for each $U_i$ matrix
/// * Expose `cyclo(gamma)` as public input

/// Since the polynomials `cyclo`, `ai` and `ct0i` are known to the verifier, the evaluation at $\gamma$ doesn't need to be constrained inside the circuit. Instead, this can be safely be performed (and verified) outside the circuit.

/// ##### Range Check

/// The coefficients of the private polynomials from each $i$-th matrix $S_i$ are checked to be in the correct range
Expand All @@ -163,10 +155,10 @@ impl<F: ScalarField> RlcCircuitInstructions<F> for BfvSkEncryptionCircuit {

/// ##### Evaluation at $\gamma$ Constraint

/// Contrary to the polynomials `cyclo`, `ai` and `ct0i`, the polynomials belonging to each $S_i$ matrix are not known by the verifier. Therefore, their evaluation at $\gamma$ must be constrained inside the circuit.

/// * Constrain the evaluation of the polynomials `s`, `e`, `k1` at $\gamma$. This has to be done only once as these polynomial are common to each $S_i$ matrix
/// * Constrain the evaluation of the polynomials `r1i`, `r2i` at $\gamma$ for each $S_i$ matrix
/// * Constrain the evaluation of the polynomials `ai` and `ct0i` at $\gamma$ for each $U_i$ matrix
/// * Constrain the evaluation of the polynomials `cyclo` at $\gamma$ . This has to be done only once as the cyclotomic polynomial is common to each $U_i$ matrix

/// ##### Correct Encryption Constraint

Expand Down Expand Up @@ -204,12 +196,6 @@ impl<F: ScalarField> RlcCircuitInstructions<F> for BfvSkEncryptionCircuit {
k0i_constants.push(k0i_constant);
}

let bits_used = usize::BITS as usize - N.leading_zeros() as usize;
rlc.load_rlc_cache((ctx_gate, ctx_rlc), gate, bits_used);
let cyclo_at_gamma_assigned = rlc.rlc_pow_fixed(ctx_gate, gate, N);
let cyclo_at_gamma_assigned =
gate.add(ctx_gate, cyclo_at_gamma_assigned, Constant(F::from(1)));

s_assigned.range_check(ctx_gate, range, S_BOUND);
e_assigned.range_check(ctx_gate, range, E_BOUND);
k1_assigned.range_check(ctx_gate, range, K1_BOUND);
Expand All @@ -221,6 +207,12 @@ impl<F: ScalarField> RlcCircuitInstructions<F> for BfvSkEncryptionCircuit {

// EVALUATION AT GAMMA CONSTRAINT

let bits_used = usize::BITS as usize - N.leading_zeros() as usize;
rlc.load_rlc_cache((ctx_gate, ctx_rlc), gate, bits_used);
let cyclo_at_gamma_assigned = rlc.rlc_pow_fixed(ctx_gate, gate, N);
let cyclo_at_gamma_assigned =
gate.add(ctx_gate, cyclo_at_gamma_assigned, Constant(F::from(1)));

let s_at_gamma = s_assigned.enforce_eval_at_gamma(ctx_rlc, rlc);
let e_at_gamma = e_assigned.enforce_eval_at_gamma(ctx_rlc, rlc);
let k1_at_gamma = k1_assigned.enforce_eval_at_gamma(ctx_rlc, rlc);
Expand Down

0 comments on commit 4a06ab4

Please sign in to comment.