Spoorthi Satheesha

Sporadic writer
Serial anthropomorphizer

Share: 

ZK-Bootcamp - Homework 5 - BN128

    !python -m pip install py-ecc
    from py_ecc.bn128 import G1, add, multiply, curve_order

Problem 1: Rational numbers

Claim: “I know two rational numbers that add up to num/den”

Proof: ([A], [B], num, den)

Here, num is the numerator of the rational number and den is the denominator.

    class ECPoint:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
    def rational_add(A: ECPoint, B: ECPoint, num: int, den: int) -> bool:
        """
        Return True if the prover knows two numbers that add up to num/den.
        """
        # To prove a + b = num/den, the prover must know a and b such that:
        # a + b = num.den^-1
        # We prove this by checking
        # F(a + b) = F(a).F(b)
        # F(num.den^-1) = F(a).F(b)
        den_inv = pow(den, -1, curve_order)
        num_den_inv = num * den_inv
        F_num_den_inv = multiply(G1, num_den_inv)
        F_a_and_F_b = add((A.x, A.y), (B.x, B.y))
        return F_num_den_inv == F_a_and_F_b 
    
    def get_EC_point(a: int) -> ECPoint:
        """
        Convert an integer to an ECPoint on the BN-128 curve.
        """
        x, y = multiply(G1, a)
        return ECPoint(x, y)
    # Equation a + b = num / den
    # Solution 1: 5 + 10 = 45 / 3
    a = 5
    b = 10
    num = 45
    den = 3
    A = get_EC_point(a)
    B = get_EC_point(b)
    assert rational_add(A, B, num, den) == True
    
    # Solution 2: 2 + 3 = 5 / 1
    a = 2
    b = 3
    num = 5
    den = 1
    A = get_EC_point(a)
    B = get_EC_point(b)
    assert rational_add(A, B, num, den) == True
    
    # Invalid solution: 4 + 9 = 3 / 2
    a = 4
    b = 9
    num = 3
    den = 2
    A = get_EC_point(a)
    B = get_EC_point(b)
    assert rational_add(A, B, num, den) == False

Problem 2: Matrix Multiplication

There is no claim statement here, just execute the math.

Your code should implement matrix multiplication of an n x n matrix (M) of int and a n x 1 vector of points (s). It validates the claim that matrix Ms = o where o is a n x 1 matrix of uint256.

You will need to multiply o by the generator so that both sides have the same type.

Example

\begin{bmatrix}1 & 2 & 3\4 & 5 & 6\7 & 8 & 9\end{bmatrix}\begin{bmatrix}P\Q\R\end{bmatrix}=\begin{bmatrix}P+2Q+3R\4P+5Q+6R\7P + 8Q + 9R\end{bmatrix}\stackrel{?}{=}\begin{bmatrix}o_1G\o_2G\o_3G\end{bmatrix}

    def matmul(matrix, n, s, o):
        """
        matrix: matrix of size n x n
        n: size of the matrix
        s: list of n EC points (tuples: (x, y))
        o: list of n integers
        Returns True if Ms == o*G1 elementwise
        """
        for i in range(n): # looping through rows of the matrix
            expected_o = multiply(G1, o[i]) 
            found_o = multiply(G1, 0)  # Initialize found_o as the identity element
            for j in range(n): # looping through columns of the matrix
                matrix_element = matrix[i][j]
                point = s[j]
                scaled_point = multiply((point.x, point.y), matrix_element)
                found_o = add(found_o, scaled_point)
            if found_o != expected_o:
                return False
                
        return True
    matrix = [[1,2,3], [4,5,6], [7,8,9]]
    n = 3
    s = [get_EC_point(2), get_EC_point(3), get_EC_point(4)]
    o = [20, 47, 74] 
    
    assert matmul(matrix, n, s, o) == True
    
    o = [20, 47, 75]  # This should fail as its not a solution
    assert matmul(matrix, n, s, o) == False
,