@@ -440,23 +440,61 @@ def compute_kzg_proof(blob: Blob, z: Bytes32) -> KZGProof:
440440 return compute_kzg_proof_impl(polynomial, bytes_to_bls_field(z))
441441```
442442
443+ #### ` compute_quotient_eval_within_domain `
444+
445+ ``` python
446+ def compute_quotient_eval_within_domain (z : BLSFieldElement,
447+ polynomial : Polynomial,
448+ y : BLSFieldElement
449+ ) -> BLSFieldElement:
450+ """
451+ Given `y == p(z)` for a polynomial `p(x)`, compute `q(z)`: the KZG quotient polynomial evaluated at `z` for the
452+ special case where `z` is in `ROOTS_OF_UNITY`.
453+
454+ For more details, read https://dankradfeist.de/ethereum/2021/06/18/pcs-multiproofs.html section "Dividing
455+ when one of the points is zero". The code below computes q(x_m) for the roots of unity special case.
456+ """
457+ roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY )
458+ result = 0
459+ for i, omega_i in enumerate (roots_of_unity_brp):
460+ if omega_i == z: # skip the evaluation point in the sum
461+ continue
462+
463+ f_i = int (BLS_MODULUS ) + int (polynomial[i]) - int (y) % BLS_MODULUS
464+ numerator = f_i * int (omega_i) % BLS_MODULUS
465+ denominator = int (z) * (int (BLS_MODULUS ) + int (z) - int (omega_i)) % BLS_MODULUS
466+ result += div(BLSFieldElement(numerator), BLSFieldElement(denominator))
467+
468+ return BLSFieldElement(result % BLS_MODULUS )
469+ ```
470+
443471#### ` compute_kzg_proof_impl `
444472
445473``` python
446474def compute_kzg_proof_impl (polynomial : Polynomial, z : BLSFieldElement) -> KZGProof:
447475 """
448476 Helper function for compute_kzg_proof() and compute_aggregate_kzg_proof().
449477 """
478+ roots_of_unity_brp = bit_reversal_permutation(ROOTS_OF_UNITY )
479+
480+ # For all x_i, compute p(x_i) - p(z)
450481 y = evaluate_polynomial_in_evaluation_form(polynomial, z)
451482 polynomial_shifted = [BLSFieldElement((int (p) - int (y)) % BLS_MODULUS ) for p in polynomial]
452483
453- # Make sure we won't divide by zero during division
454- assert z not in ROOTS_OF_UNITY
484+ # For all x_i, compute (x_i - z)
455485 denominator_poly = [BLSFieldElement((int (x) - int (z)) % BLS_MODULUS )
456486 for x in bit_reversal_permutation(ROOTS_OF_UNITY )]
457487
458- # Calculate quotient polynomial by doing point-by-point division
459- quotient_polynomial = [div(a, b) for a, b in zip (polynomial_shifted, denominator_poly)]
488+ # Compute the quotient polynomial directly in evaluation form
489+ quotient_polynomial = [BLSFieldElement(0 )] * FIELD_ELEMENTS_PER_BLOB
490+ for i, (a, b) in enumerate (zip (polynomial_shifted, denominator_poly)):
491+ if b == 0 :
492+ # The denominator is zero hence `z` is a root of unity: we must handle it as a special case
493+ quotient_polynomial[i] = compute_quotient_eval_within_domain(roots_of_unity_brp[i], polynomial, y)
494+ else :
495+ # Compute: q(x_i) = (p(x_i) - p(z)) / (x_i - z).
496+ quotient_polynomial[i] = div(a, b)
497+
460498 return KZGProof(g1_lincomb(bit_reversal_permutation(KZG_SETUP_LAGRANGE ), quotient_polynomial))
461499```
462500
0 commit comments