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

docs: add documentation for disperser v2 grpc api and related functions/structs #1104

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion api/proto/common/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ syntax = "proto3";
package common;
option go_package = "github.com/Layr-Labs/eigenda/api/grpc/common";

// G1Commitment represents the serialized coordinates of a G1 KZG commitment.
// We use gnark-crypto so adopt its serialization, which is big-endian. See:
// https://github.com/Consensys/gnark-crypto/blob/779e884dabb38b92e677f4891286637a3d2e5734/ecc/bn254/fp/element.go#L862
message G1Commitment {
// The X coordinate of the KZG commitment. This is the raw byte representation of the field element.
bytes x = 1;
Expand All @@ -10,11 +13,20 @@ message G1Commitment {
}

// BlobCommitment represents commitment of a specific blob, containing its
// KZG commitment, degree proof, the actual degree, and data length in number of symbols.
// KZG commitment, degree proof, the actual degree, and data length in number of symbols (field elements).
// It deserializes into https://github.com/Layr-Labs/eigenda/blob/ce89dab18d2f8f55004002e17dd3a18529277845/encoding/data.go#L27
//
// See https://github.com/Layr-Labs/eigenda/blob/master/docs/spec/attestation/encoding.md#validation-via-kzg
// to understand how this commitment is used to validate the blob.
message BlobCommitment {
// Concatenation of the x and y coordinates of `common.G1Commitment`.
bytes commitment = 1;
// Serialization of the G2Commitment to the blob length.
bytes length_commitment = 2;
// Serialization of the G2Affine element representing the proof of the blob length.
bytes length_proof = 3;
// The length of the blob in symbols (field elements).
// TODO: is this length always a power of 2? Are there any other characteristics that we should list? etc.
uint32 length = 4;
}
Comment on lines +29 to 31
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does anyone know for this one?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes it's the padded length, always power of 2 (so maybe not really "actual degree/length" as commented above)


Expand Down
33 changes: 26 additions & 7 deletions api/proto/disperser/v2/disperser_v2.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,40 @@ service Disperser {
rpc GetBlobStatus(BlobStatusRequest) returns (BlobStatusReply) {}

// GetBlobCommitment is a utility method that calculates commitment for a blob payload.
// It is provided to help clients who are trying to construct a DisperseBlobRequest.blob_header
// and don't have the ability to calculate the commitment themselves (expensive operation which requires SRS points).
//
// For an example usage, see how our disperser_client makes a call to this endpoint when it doesn't have a local prover:
// https://github.com/Layr-Labs/eigenda/blob/6059c6a068298d11c41e50f5bcd208d0da44906a/api/clients/v2/disperser_client.go#L166
rpc GetBlobCommitment(BlobCommitmentRequest) returns (BlobCommitmentReply) {}

// GetPaymentState is a utility method to get the payment state of a given account.
// GetPaymentState is a utility method to get the payment state of a given account, at a given disperser.
// EigenDA's payment system for v2 is currently centralized, meaning that each disperser does its own accounting.
// A client wanting to disperse a blob would thus need to synchronize its local accounting state with that of the disperser.
// That typically only needs to be done once, and the state can be updated locally as the client disperses blobs.
// The accounting rules are simple and can be updated locally, but periodic checks with the disperser can't hurt.
//
// For an example usage, see how our disperser_client makes a call to this endpoint to populate its local accountant struct:
// https://github.com/Layr-Labs/eigenda/blob/6059c6a068298d11c41e50f5bcd208d0da44906a/api/clients/v2/disperser_client.go#L298
rpc GetPaymentState(GetPaymentStateRequest) returns (GetPaymentStateReply) {}
}

// Requests and Replys

message DisperseBlobRequest {
// The data to be dispersed.
// The size of data must be <= 16MiB. Every 32 bytes of data is interpreted as an integer in big endian format
// where the lower address has more significant bits. The integer must stay in the valid range to be interpreted
// as a field element on the bn254 curve. The valid range is
// 0 <= x < 21888242871839275222246405745257275088548364400416034343698204186575808495617
// If any one of the 32 bytes elements is outside the range, the whole request is deemed as invalid, and rejected.
// The encoded data to be dispersed to the EigenDA network.
//
// Validation rules:
// 1. The size of data must be <= 16MiB.
// 2. The data is allowed to not be a multiple of 32 bytes: the last chunk will be padded with zeros to make it so.
// 3. Every 32 bytes chunk (including the last after rule 2) must be a valid bid-endian serialized field element on the bn254 curve.
// The valid range for each 32 byte chunk is: 0 <= x < 21888242871839275222246405745257275088548364400416034343698204186575808495617
// If rule 1 or 3 is violated, the whole request is deemed as invalid, and rejected.
//
// To encode your payload data into the correct blob format, you can make use of our codec:
// https://github.com/Layr-Labs/eigenda/blob/82192985a2d15b88d85a6090404b2595f4922bef/api/clients/codecs/default_blob_codec.go#L21
// Most users will not need to interact with this low level codec directly however, given that the high-level eigenda_client does the encoding for you:
// https://github.com/Layr-Labs/eigenda/blob/master/api/clients/eigenda_client.go
bytes data = 1;
common.v2.BlobHeader blob_header = 2;
}
Expand Down
3 changes: 3 additions & 0 deletions encoding/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ type Prover interface {
// reconstruct the blob.
EncodeAndProve(data []byte, params EncodingParams) (BlobCommitments, []*Frame, error)

// GetCommitmentsForPaddedLength takes in a byte slice representing a list of bn254
// field elements (32 bytes each, except potentially the last element),
// pads the (potentially incomplete) last element with zeroes, and returns the commitments for the padded list.
GetCommitmentsForPaddedLength(data []byte) (BlobCommitments, error)

GetFrames(data []byte, params EncodingParams) ([]*Frame, error)
Expand Down
3 changes: 3 additions & 0 deletions encoding/kzg/prover/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ func (e *Prover) GetFrames(data []byte, params encoding.EncodingParams) ([]*enco
return chunks, nil
}

// GetCommitmentsForPaddedLength takes in a byte slice representing a list of bn254
// field elements (32 bytes each, except potentially the last element),
// pads the (potentially incomplete) last element with zeroes, and returns the commitments for the padded list.
func (e *Prover) GetCommitmentsForPaddedLength(data []byte) (encoding.BlobCommitments, error) {
symbols, err := rs.ToFrArray(data)
if err != nil {
Expand Down
13 changes: 12 additions & 1 deletion encoding/rs/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ import (
"github.com/consensys/gnark-crypto/ecc/bn254/fr"
)

// ToFrArray deserializes a byte array into a list of bn254 field elements.,
// where each 32-byte chunk needs to be a big-endian serialized bn254 field element.
// The last chunk is allowed to not have 32-bytes, and will be padded with zeroes
// on the right (so make sure that the last partial chunk represents a valid field element
// when padded with zeroes on the right and interpreted as big-endian).
//
// TODO: we should probably just force the data to be a multiple of 32 bytes.
// This would make the API and code simpler to read, and also allow the code
// to be auto-vectorized by the compiler (it probably isn't right now given the if inside the for loop).
Comment on lines +19 to +21
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can we do this? Really think it would greatly help devex.

func ToFrArray(data []byte) ([]fr.Element, error) {
numEle := GetNumElement(uint64(len(data)), encoding.BYTES_PER_SYMBOL)
eles := make([]fr.Element, numEle)
Expand All @@ -35,7 +44,9 @@ func ToFrArray(data []byte) ([]fr.Element, error) {
return eles, nil
}

// ToByteArray converts a list of Fr to a byte array
// ToByteArray serializes a slice of fields elements to a slice of bytes.
// The byte array is created by serializing each Fr element in big-endian format.
// It is the reverse operation of ToFrArray.
func ToByteArray(dataFr []fr.Element, maxDataSize uint64) []byte {
n := len(dataFr)
dataSize := int(math.Min(
Expand Down
Loading