After understanding the entire flow of the Verkle Cryptography API, and how it's supposed to work in Nim, for the Nimbus client.
I raised an issue soon after in Constantine, and broke down my work into 15 objective tasks.
They were soon after listed in my PR. The tasks were as follows:
Fixes #275
This to-do is updated to 7/10/2023.
For the past few weeks I have been racking my head on how to implement the precompute approach for Lagrangian interpolation of the polynomials. However, soon after I figured out, thanks to this article.
The followting is an excerpt from Kev's article.
We briefly restate the formula for a lagrange polynomial:
The i'th lagrange polynomial evaluated at is 1 and 0 everywhere else on the domain
We introduce the polynomial .
We also introduce the derivative of .
You can derive this yourself by generalising the product rule: https://en.wikipedia.org/wiki/Product_rule#Product_of_more_than_two_factors
In general this derivative does not have a succint/sparse form. We do have a succint form if the domain is the roots of unity!
Now note that
If we plug in into all the terms with will vanish, this is why the sum disappears into a single product.
We can use and to re-define our lagrange polynomial as :
Looking at the original lagrange formula, is the denominator and is the numerator.
The first barycentric form for a polynomial can now be defined as :
The Nim equivalent is stated here.
One of the main portions of the code is as follows:
Here the precomputed weights are and as follows. The type defined to store them is as follows :
The theoretical equivalent of this is here-
For our case where the domain is the discrete interval
We only need to precompute for . This is 510 values, so we would store 510 * 32 = 16Kb.
How would we lookup these values?
First we imagine that we have stored the values in an array:
We first note that we can easily get from to in the array by jumping forward 255 indices. Our strategy will be to find then jump to if we need to.
Example
We want to compute .
In practice, we can use an if statement to check whether 255 or 0 is larger, and subtract accordingly.
With the roots of unity, we did not need this optimisation as equaled which was trivial to fetch from the domain.
For this, we will need to store precomputed values, if we want to efficiently compute in steps, and to also avoid inversions.
(Dankrad): We precompute and . Given that we have 256 points in the domain. This will cost us 256 2 32 bytes = 16kB.
How would I lookup these values?
Similar to the previous optimisation, we store in an array.
Example
We want to compute
This is an optimisation that is being followed only in Go implementation apart from the Nim (Constantine) implementation, which is newly being developed.
Most of these functions exist in the common_utils.nim
file in my Constantine PR.
One of the very important tasks for me in here was writing a function to Derive the generator element for Pedersen Commitment.
These are the set of dependencies
The current seed being used is: eth_verkle_oct_2021
For Nim we use the Projective
coordinates, as that's what we've been using in order to make the library comparitively as fast as Go. Here is how the code looks like -
Sorry for writing articles biweekly, I just get lost into implementation sometimes, next update will be about how I'll be implementing splitting and folding of scalars
while performing Pedersen Commitments inside the Inner Product Argument setting.
I'll be also updating about how I'll be creating IPA proofs, creating a Multiproof using those IPA proofs and finally calling those proofs in a Multiproof Verifying Mechanism.
Till then, best wishes