Streaming Based Evaluation of Multilinear Lagrange Interpolating Polynomials

September 03, 2024

  • Let f:{0,1}vFf: \{0,1\}^v \rightarrow \mathbb{F} and suppose a verifier has all evaluations f(x)f(x) for x{0,1}vx \in \{0,1\}^v.
    • The domain of ff has size {0,1}v=2v=n|\{0,1\}^v| = 2^v = n.
  • Given f(w)f(w) for all w{0,1}vw \in \{0,1\}^v and a vv-dimensional vector rFvr \in \mathbb{F}^v, the verifier must efficiently evaluate f~(r)\tilde{f}(r).

Streaming Interactive Proofs

  • See the paper Verifying Computations with Streaming Interactive Proofs
  • The verifier can compute f~(r)\tilde{f}(r) in O(nlog(n))O(n\cdot log(n)) time and O(log(n))O(log(n)) space by streaming the inputs f(w)f(w) for all w{0,1}vw \in \{0,1\}^v.
  • The order of the inputs does not matter
  • VV can calculate the sum
    f~(r)=w{0,1}vf(w)Lw(r1,,rv)\tilde{f}(r) = \sum_{w\in \{0,1\}^v} f(w)\cdot L_w(r_1,\dots,r_v)
    with a recursive algorithm.
  • Begin by initializing the accumulator to 0: f~(r)0\tilde{f}(r) \leftarrow 0. Then with each entry, add the next term to the accumulator
    f~(r)f~(r)+f(w)Lw(r)\tilde{f}(r) \leftarrow \tilde{f}(r) + f(w) \cdot L_w(r)
  • With this approach, the verifier only needs to store the value rr and the current value of f~(r)\tilde{f}(r) as it iterates through values of w{0,1}vw \in \{0,1\}^v. rr is a vv-dimensional vector of elements of F\mathbb{F} and f~(r)F\tilde{f}(r) \in \mathbb{F}, so the algorithm's space usage is v+1v+1 field elements or O(v)=O(log2(n))O(v ) = O(log_2(n))
  • The verifier runs through each of the 2v=n2^v = n values in w{0,1}vw \in \{0,1\}^v, each time evaluating the vv-term Lagrange basis polynomial Lw(r)L_w(r)
    Lw(r1,,rv):=i=1vriwi+(1ri)(iwi)L_w(r_1,\dots,r_v) := \prod^{v}_{i=1} r_i\cdot w_i + (1-r_i)(i-w_i)
    so 2v2^v operations in O(v)O(v) are run to compute the full sum, resulting in a runtime of O(v2v)O(v \cdot 2^v) or O(nlog(n))O(n \cdot log(n)) .

Implementation

function getMultilinearLagrange(message: string, x: Field[]): Field {
  const n = message.length;
  if (n === 0) {
    throw Error("Dataset cannot be empty.");
  }
  // dimension of hypercube required to encode n entries  
  // 2^d must be at least as large as n  const d = Math.ceil(Math.log2(n));  

  // accumulator for result as terms in summation are evaluated  
  let accumulator = Field(0);
  // ordered list of n vertices being interpolated  
  const interpolatingSet = generateBinaryVertices(d);
  let lagrangeBasisAtInput;

  // sum over all vertices in the d dimensional hypercube to create the interpolating polynomial  
  // O(n)  // todo - can we sum over n entries of the message instead of 2^d vertices?  
  for (let i = 0; i < interpolatingSet.length; i++) {
    // obtain field representation of ascii character in message  
    // 2^d will likely be larger than n, right-pad the message with zeroes    const coefficient =  
    i >= message.length ? Field(0) : Field(asciiToNumber(message[i]));
    lagrangeBasisAtInput = getMultilinearLagrangeBasisAt(
            interpolatingSet[i],
            interpolatingSet,
            x,
    );

    // Add the current term (coefficient * current basis) to the result  
    accumulator = accumulator.add(coefficient.mul(lagrangeBasisAtInput));
  }

  return accumulator;
}

function getMultilinearLagrangeBasisAt(
        w: number[],
        interpolatingSet: number[][],
        x: Field[],
): Field {
  if (
          w.length !== interpolatingSet[0].length ||
          x.length !== interpolatingSet[0].length
  )
    throw Error(
            `Vectors w: ${w} and x: ${x} must be ${interpolatingSet.length}-dimensional`,
    );

  let accumulator = Field(1);
  // lagrange basis polynomial is a product over all entries in the vertex w  
  for (let i = 0; i < w.length; i++) {
    accumulator = accumulator.mul(
            x[i].mul(w[i]).add(
                    Field(1)
                            .sub(x[i])
                            .mul(1 - w[i]),
            ),
    );
  }

  return accumulator;
}

Profile picture

Written by Breads