Skip to content

Commit

Permalink
chore: move vector operators to ModuloCircuit
Browse files Browse the repository at this point in the history
  • Loading branch information
petscheit committed Dec 18, 2024
1 parent ebbe575 commit 45ee928
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 262 deletions.
46 changes: 0 additions & 46 deletions hydra/garaga/extension_field_modulo_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,52 +285,6 @@ def eval_poly_in_precomputed_Z(

return X_of_z

def extf_add(
self, X: list[ModuloCircuitElement], Y: list[ModuloCircuitElement]
) -> list[ModuloCircuitElement]:
"""
Adds two polynomials with coefficients `X` and `Y`.
Returns R = [x0 + y0, x1 + y1, x2 + y2, ... + xn-1 + yn-1] mod p
"""
assert len(X) == len(Y), f"len(X)={len(X)} != len(Y)={len(Y)}"
return [
self.add(x_i, y_i, comment=f"Fp{len(X)} add coeff {i}/{len(X)-1}")
for i, (x_i, y_i) in enumerate(zip(X, Y))
]

def extf_scalar_mul(
self, X: list[ModuloCircuitElement], c: ModuloCircuitElement
) -> list[ModuloCircuitElement]:
"""
Multiplies a polynomial with coefficients `X` by a scalar `c`.
Input : I(x) = i0 + i1*x + i2*x^2 + ... + in-1*x^n-1
Output : O(x) = ci0 + ci1*x + ci2*x^2 + ... + cin-1*x^n-1.
This is done in the circuit.
"""
assert isinstance(c, ModuloCircuitElement), "c must be a ModuloCircuitElement"
return [
self.mul(x_i, c, comment=f"Fp{len(X)} scalar mul coeff {i}/{len(X)-1}")
for i, x_i in enumerate(X)
]

def extf_neg(self, X: list[ModuloCircuitElement]) -> list[ModuloCircuitElement]:
"""
Negates a polynomial with coefficients `X`.
Returns R = [-x0, -x1, -x2, ... -xn-1] mod p
"""
return [
self.neg(x_i, comment=f"Fp{len(X)} neg coeff {i}/{len(X)-1}")
for i, x_i in enumerate(X)
]

def extf_sub(
self, X: list[ModuloCircuitElement], Y: list[ModuloCircuitElement]
) -> list[ModuloCircuitElement]:
return [
self.sub(x, y, comment=f"Fp{len(X)} sub coeff {i}/{len(X)-1}")
for i, (x, y) in enumerate(zip(X, Y))
]

def extf_mul(
self,
Ps: list[list[ModuloCircuitElement]],
Expand Down
46 changes: 46 additions & 0 deletions hydra/garaga/modulo_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,52 @@ def fp2_parity(
# Return parity as [s, 0]
return [s, zero]

def vector_sub(
self, X: list[ModuloCircuitElement], Y: list[ModuloCircuitElement]
) -> list[ModuloCircuitElement]:
return [
self.sub(x, y, comment=f"Fp{len(X)} sub coeff {i}/{len(X)-1}")
for i, (x, y) in enumerate(zip(X, Y))
]

def vector_scale(
self, X: list[ModuloCircuitElement], c: ModuloCircuitElement
) -> list[ModuloCircuitElement]:
"""
Multiplies a polynomial with coefficients `X` by a scalar `c`.
Input : I(x) = i0 + i1*x + i2*x^2 + ... + in-1*x^n-1
Output : O(x) = ci0 + ci1*x + ci2*x^2 + ... + cin-1*x^n-1.
This is done in the circuit.
"""
assert isinstance(c, ModuloCircuitElement), "c must be a ModuloCircuitElement"
return [
self.mul(x_i, c, comment=f"Fp{len(X)} scalar mul coeff {i}/{len(X)-1}")
for i, x_i in enumerate(X)
]

def vector_add(
self, X: list[ModuloCircuitElement], Y: list[ModuloCircuitElement]
) -> list[ModuloCircuitElement]:
"""
Adds two polynomials with coefficients `X` and `Y`.
Returns R = [x0 + y0, x1 + y1, x2 + y2, ... + xn-1 + yn-1] mod p
"""
assert len(X) == len(Y), f"len(X)={len(X)} != len(Y)={len(Y)}"
return [
self.add(x_i, y_i, comment=f"Fp{len(X)} add coeff {i}/{len(X)-1}")
for i, (x_i, y_i) in enumerate(zip(X, Y))
]

def vector_neg(self, X: list[ModuloCircuitElement]) -> list[ModuloCircuitElement]:
"""
Negates a polynomial with coefficients `X`.
Returns R = [-x0, -x1, -x2, ... -xn-1] mod p
"""
return [
self.neg(x_i, comment=f"Fp{len(X)} neg coeff {i}/{len(X)-1}")
for i, x_i in enumerate(X)
]

def sub_and_assert(
self,
a: ModuloCircuitElement,
Expand Down
62 changes: 8 additions & 54 deletions hydra/garaga/precompiled_circuits/ec.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,52 +662,6 @@ def __init__(self, name: str, curve_id: int, compilation_mode: int = 0):
)
self.curve = CURVES[curve_id]

def extf_sub(
self, X: list[ModuloCircuitElement], Y: list[ModuloCircuitElement]
) -> list[ModuloCircuitElement]:
return [
self.sub(x, y, comment=f"Fp{len(X)} sub coeff {i}/{len(X)-1}")
for i, (x, y) in enumerate(zip(X, Y))
]

def extf_scalar_mul(
self, X: list[ModuloCircuitElement], c: ModuloCircuitElement
) -> list[ModuloCircuitElement]:
"""
Multiplies a polynomial with coefficients `X` by a scalar `c`.
Input : I(x) = i0 + i1*x + i2*x^2 + ... + in-1*x^n-1
Output : O(x) = ci0 + ci1*x + ci2*x^2 + ... + cin-1*x^n-1.
This is done in the circuit.
"""
assert isinstance(c, ModuloCircuitElement), "c must be a ModuloCircuitElement"
return [
self.mul(x_i, c, comment=f"Fp{len(X)} scalar mul coeff {i}/{len(X)-1}")
for i, x_i in enumerate(X)
]

def extf_add(
self, X: list[ModuloCircuitElement], Y: list[ModuloCircuitElement]
) -> list[ModuloCircuitElement]:
"""
Adds two polynomials with coefficients `X` and `Y`.
Returns R = [x0 + y0, x1 + y1, x2 + y2, ... + xn-1 + yn-1] mod p
"""
assert len(X) == len(Y), f"len(X)={len(X)} != len(Y)={len(Y)}"
return [
self.add(x_i, y_i, comment=f"Fp{len(X)} add coeff {i}/{len(X)-1}")
for i, (x_i, y_i) in enumerate(zip(X, Y))
]

def extf_neg(self, X: list[ModuloCircuitElement]) -> list[ModuloCircuitElement]:
"""
Negates a polynomial with coefficients `X`.
Returns R = [-x0, -x1, -x2, ... -xn-1] mod p
"""
return [
self.neg(x_i, comment=f"Fp{len(X)} neg coeff {i}/{len(X)-1}")
for i, x_i in enumerate(X)
]

def _compute_adding_slope(
self,
P: tuple[
Expand All @@ -721,7 +675,7 @@ def _compute_adding_slope(
):
xP, yP = P
xQ, yQ = Q
slope = self.fp2_div(self.extf_sub(yP, yQ), self.extf_sub(xP, xQ))
slope = self.fp2_div(self.vector_sub(yP, yQ), self.vector_sub(xP, xQ))
return slope

def _compute_doubling_slope_a_eq_0(
Expand All @@ -733,8 +687,8 @@ def _compute_doubling_slope_a_eq_0(
# Compute doubling slope m = (3x^2 + A) / 2y
three = self.set_or_get_constant(self.field(3))

m_num = self.extf_scalar_mul(self.fp2_square(xP), three)
m_den = self.extf_add(yP, yP)
m_num = self.vector_scale(self.fp2_square(xP), three)
m_den = self.vector_add(yP, yP)
m = self.fp2_div(m_num, m_den)
return m

Expand All @@ -747,8 +701,8 @@ def add_points(
xQ, yQ = Q
slope = self._compute_adding_slope(P, Q)
slope_sqr = self.fp2_square(slope)
nx = self.extf_sub(self.extf_sub(slope_sqr, xP), xQ)
ny = self.extf_sub(self.fp2_mul(slope, self.extf_sub(xP, nx)), yP)
nx = self.vector_sub(self.vector_sub(slope_sqr, xP), xQ)
ny = self.vector_sub(self.fp2_mul(slope, self.vector_sub(xP, nx)), yP)
return (nx, ny)

def double_point_a_eq_0(
Expand All @@ -758,8 +712,8 @@ def double_point_a_eq_0(
xP, yP = P
slope = self._compute_doubling_slope_a_eq_0(P)
slope_sqr = self.fp2_square(slope)
nx = self.extf_sub(self.extf_sub(slope_sqr, xP), xP)
ny = self.extf_sub(self.fp2_mul(slope, self.extf_sub(xP, nx)), yP)
nx = self.vector_sub(self.vector_sub(slope_sqr, xP), xP)
ny = self.vector_sub(self.fp2_mul(slope, self.vector_sub(xP, nx)), yP)
return (nx, ny)

def double_n_times(self, P, n):
Expand All @@ -772,4 +726,4 @@ def negate_point(
self, P: tuple[list[ModuloCircuitElement], list[ModuloCircuitElement]]
) -> tuple[list[ModuloCircuitElement], list[ModuloCircuitElement]]:
x, y = P
return (x, self.extf_neg(y))
return (x, self.vector_neg(y))
14 changes: 7 additions & 7 deletions hydra/garaga/precompiled_circuits/final_exp.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ def square_torus(
X, self.curve_id, biject_from_direct=True
)
SQ = self.write_elements(SQ, WriteOps.COMMIT)
two_SQ = self.extf_add(SQ, SQ)
two_SQ_min_X = self.extf_sub(two_SQ, X)
two_SQ = self.vector_add(SQ, SQ)
two_SQ_min_X = self.vector_sub(two_SQ, X)

# %{
Q, V = nondeterministic_extension_field_mul_divmod(
Expand Down Expand Up @@ -113,7 +113,7 @@ def mul_torus(
num = copy.deepcopy(xy)
num[1] = self.add(xy[1], self.set_or_get_constant(1))

den = self.extf_add(X, Y)
den = self.vector_add(X, Y)
return self.extf_div(num, den, self.extension_degree)

def inverse_torus(self, X: list[ModuloCircuitElement]):
Expand Down Expand Up @@ -165,7 +165,7 @@ def frobenius_torus(
frob[i] = self.add(frob[i], op_res)

if len(self.v_torus_powers_inv[frob_power]) == 1:
return self.extf_scalar_mul(frob, self.v_torus_powers_inv[frob_power][0])
return self.vector_scale(frob, self.v_torus_powers_inv[frob_power][0])
else:
Y = [
self.set_or_get_constant(v) for v in self.v_torus_powers_inv[frob_power]
Expand All @@ -187,7 +187,7 @@ def easy_part(
assert len(den) == 6, f"Expected 6 elements in den, got {len(den)}"

num = self.write_elements(num, operation=WriteOps.INPUT)
num = self.extf_neg(num)
num = self.vector_neg(num)
den = self.write_elements(den, WriteOps.INPUT)

c = self.extf_div(num, den, self.extension_degree)
Expand Down Expand Up @@ -281,7 +281,7 @@ def final_exp_part1(self, num: list[PyFelt], den: list[PyFelt]) -> list[PyFelt]:
# The final exp result is DecompressTorus(MulTorus(c, t1)
# MulTorus(t1, c) = (t1*c + v)/(t1 + c).
# (t1+c = 0) ==> MulTorus(t1, c) is E12.One() in the Torus.
_sum = self.extf_add(t1, c)
_sum = self.vector_add(t1, c)
self.extend_output(_sum)
# From this case we can conclude the result is 1 or !=1 without decompression.
# In case we want to decompress to get the result in GT,
Expand Down Expand Up @@ -379,7 +379,7 @@ def final_exp_part1(
# The final exp result is DecompressTorus(MulTorus(t0, t2)).
# MulTorus(t0, t2) = (t0*t2 + v)/(t0 + t2).
# (T0+T2 = 0) ==> MulTorus(t0, t2) is one in the Torus.
_sum = self.extf_add(t0, t2)
_sum = self.vector_add(t0, t2)
self.extend_output(_sum)
# From this case we can conclude the result is 1 or !=1 without decompression.
# In case we want to decompress to get the result in GT,
Expand Down
Loading

0 comments on commit 45ee928

Please sign in to comment.