Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EIP7594 #455

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft

Add EIP7594 #455

wants to merge 6 commits into from

Conversation

gerceboss
Copy link

@gerceboss gerceboss commented Aug 11, 2024

@mratsim ,This is Nilav, I am permissionlessly taking part in EPF-5 this year, mentors on this project are agnish and tersec.

This PR is meant for adding one of the public methods in EIP-7594 namely compute_cells_and_kzg_proofs

The implementation is incomplete yet, needed help in figuring out some things.

  1. How to import functions and types from EIP-4844 file?
  2. Do the tests need to be written only for the public methods?
  3. Please mention the suggestions as well about refactoring or redundant code or any other improvements

I know I am already quite behind in starting the contributions but now, will keep up with pace

@gerceboss gerceboss marked this pull request as draft August 13, 2024 13:15
@mratsim
Copy link
Owner

mratsim commented Aug 19, 2024

Hi,

Thanks for your contribution, I think it would need to be split into multiple parts, 1 with just this and the rest as 8k lines PR are quite scary even if only just test vectors.

Regarding your questions:

  1. How to import functions and types from EIP-4844 file?

2 solutions, either use the export marker * or likely in this case as those are likely internal functions use the special {.all.} import with

import ./ethereum_eip4844_kzg {.all.} to access internal functions

  1. Do the tests need to be written only for the public methods?

We should at the very least use the same tests as the reference implementations in C and Rust, c-kzg-4844 and peerdas-kzg. If internal tests help you can either write them within the file with when isMainModule: at the bottom of the file or use the import ethereum_eip7594_kzg {.all.} and create a test files for internal functions.

I'll proceed with the review and we can merge this first part after.

./platforms/[abstractions, allocs],
./serialization/[codecs_status_codes, codecs_bls12_381, endians],
./commitments_setups/ethereum_kzg_srs
# ./ethereum_eip4844_kzg
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# ./ethereum_eip4844_kzg
import ./ethereum_eip4844_kzg {.all.}

@@ -64,7 +64,7 @@ const RANDOM_CHALLENGE_KZG_BATCH_DOMAIN = asBytes"RCKZGBATCH___V1_"

# Derived
# ------------------------------------------------------------
const BYTES_PER_BLOB = BYTES_PER_FIELD_ELEMENT*FIELD_ELEMENTS_PER_BLOB
const BYTES_PER_BLOB* = BYTES_PER_FIELD_ELEMENT*FIELD_ELEMENTS_PER_BLOB
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const BYTES_PER_BLOB* = BYTES_PER_FIELD_ELEMENT*FIELD_ELEMENTS_PER_BLOB
const BYTES_PER_BLOB = BYTES_PER_FIELD_ELEMENT*FIELD_ELEMENTS_PER_BLOB

not needed with the {.all.} import marker

@@ -177,7 +177,7 @@ func bytes_to_kzg_proof(dst: var KZGProof, src: array[48, byte]): CttCodecEccSta
return cttCodecEcc_Success
return status

func blob_to_bigint_polynomial(
func blob_to_bigint_polynomial*(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func blob_to_bigint_polynomial*(
func blob_to_bigint_polynomial(

not needed with the {.all.} import marker


# Derived
# ------------------------------------------------------------
const BYTES_PER_CELL= FIELD_ELEMENTS_PER_CELL*BYTES_PER_FIELD_ELEMENT
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const BYTES_PER_CELL= FIELD_ELEMENTS_PER_CELL*BYTES_PER_FIELD_ELEMENT
const BYTES_PER_CELL = FIELD_ELEMENTS_PER_CELL*BYTES_PER_FIELD_ELEMENT

# Derived
# ------------------------------------------------------------
const BYTES_PER_CELL= FIELD_ELEMENTS_PER_CELL*BYTES_PER_FIELD_ELEMENT
const FIELD_ELEMENTS_PER_EXT_BLOB=2*FIELD_ELEMENTS_PER_BLOB
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const FIELD_ELEMENTS_PER_EXT_BLOB=2*FIELD_ELEMENTS_PER_BLOB
const FIELD_ELEMENTS_PER_EXT_BLOB = 2*FIELD_ELEMENTS_PER_BLOB

# for i in 0 ..< FIELD_ELEMENTS_PER_CELL:
# var bytes = bls_field_to_bytes(cosetEvals[i])
# for j in 0 ..< bytes.len:
# dst[i* bytes.len + j] = bytes[j]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# dst[i* bytes.len + j] = bytes[j]
# dst[i* bytes.len + j] = bytes[j]

2 spaces everywhere, you can configure vs-code with 2 spaces for Nim with the following

ctrl+shift+P: Open users settings (JSON)

and add a language specific config

    "[nim]": {
        "editor.tabSize": 2,
    },

like this:
image

# Compute a KZG multi-evaluation proof for a set of `k` points.

# This is done by committing to the following quotient polynomial:
# Q(X) = f(X) - I(X) / Z(X)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unclear whether it's (f(X) - I(X)) / Z(X) or f(X) - (I(X) / Z(X))

# For all points, compute the evaluation of those points

for i in z:
ys[i]=evaluate_polynomialcoeff(polynomial_coeff, z[i])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is not defined, I assume this is pseudocode from the spec so I'll stop reviewing the file here.

It's OK to delete those, only check in the coset_eval_to_cell and the 8k lines of test vectors.

@@ -143,6 +143,32 @@ type InvDiffArrayKind* = enum
kArrayMinus
kMinusArray

# How do we do modulo? Field.fromBigInt()?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you talking about polynomial division / remainder or coefficients?

If it's coefficient, it's handled internally when you use fields.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mratsim ,Yes, I wanted to ask about that:

  1. How do I perform n % BLS_MODULUS?
  2. How do I do division between 2 polynomials given in form of their polynomial coefficients? I see that there are methods for sum and product.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. How do I perform n % BLS_MODULUS?

Field element do not need this, all operations are implicitly reduced modulo BLS_MODULUS.

  1. How do I do division between 2 polynomials given in form of their polynomial coefficients? I see that there are methods for sum and product.

Where is it used in the spec? EIP-4844 introduces polynomial division but for polynomial in Lagrange/evaluation form. I would expect the spec to introduce the polynomial division code if it's used.

Ultimately it's similar to integer division because integers are polynomials but with a twist, they carry.

for i in 0 ..< f.coefs.len:
f.coefs[i] -= g.coefs[i]

func prod*[N,F](r: var PolynomialCoef[N, F], s: F, f: PolynomialCoef[N, F])=
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect for polynomials in coefficient form.

(a + bx + cx²) * (u + vx + wx²) is not au + bvx + cwx²

Copy link
Author

@gerceboss gerceboss Aug 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mratsim, Agnish mentioned once that these are redundant as already there are methods for PolynomialEvals. Can you confirm? Because, from what I see multiplying here is of 2 polynomial coefficients and in the PolynomialEvals one , there is scalar getting multiplied to whole evaluated form.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EIP-4844 focused heavily on polynomial in evaluation form because they are asymptotically more efficient than polynomial in coefficient form.

  • Multiplication in evaluation form is O(n) with n the number of coefficient/evaluation.
  • Naive multiplication in coefficient form is O(n²).
  • Efficient multiplication in coefficient form would be O(n log n) with n log n FFT + O(n) eval multiplication + n log n inverse FFT

so I'm surprised if this is actually necessary in the spec?

@gerceboss
Copy link
Author

gerceboss commented Aug 25, 2024

Also, I don't know how to divide this PR in two parts as you mentioned, can you please guide on that?

And at some places tuples are used in consensus specs , and in nim tuples are immutable, so how do I approach writing such functions? @mratsim

@gerceboss gerceboss requested a review from mratsim August 25, 2024 22:02
@mratsim
Copy link
Owner

mratsim commented Aug 26, 2024

Also, I don't know how to divide this PR in two parts as you mentioned, can you please guide on that?

You can use a technique called "staggered PRs".

  • You create a branch for example eip7594-1, you put your first commits, here it would be just the test vectors.
  • Then you create a branch eip7594-2 from this eip7594-1 branch, adds your commit for your first feature(s).
  • And create a eip7594-3 from this eip7594-2 branch, etc

When opening a PR just make sure to target the previous branch
image
image

This allows you to make progress without waiting for me merging the code.
It allows reviewing features independently and fix the branch as well without mixing up commits, you can just rebase follow-up branch afterwards.
And more importantly it keeps PR size down so that they are easier to review and focus on.

And at some places tuples are used in consensus specs , and in nim tuples are immutable, so how do I approach writing such functions? @mratsim

Tuples are not immutable.

var myTuple = (1, 2)
myTuple[0] = 3
echo myTuple

var (a, b) = (1, 2)
a = 4
echo a

proc foo(tup: var (int, int)) =
  tup[0] += 1

proc bar(tup: var Tuple[x, y: int]) =
  tup.x += 1

are examples of mutable tuples.

This specific signature

def compute_kzg_proof_multi_impl(
        polynomial_coeff: PolynomialCoeff,
        zs: Coset) -> Tuple[KZGProof, CosetEvals]:

Should be transformed into:

proc compute_kzg_proof_multi_impl(
  cosetEvals: var XXXCosetEvalsXXX, # insert proper type here, it looks like openArray[Fr[BLS12_381]]
  proof: var KzgProof,
  poly: PolynomialCoeff,
  zs: Coset): ErrorType =

to follow the return value guideline here: https://github.com/mratsim/constantine/blob/master/ARCHITECTURE.md#return-values

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants