@aztec/blob-lib 0.0.1-fake-c83136db25 → 0.0.1-fake-ceab37513c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/blob.d.ts +98 -52
- package/dest/blob.d.ts.map +1 -1
- package/dest/blob.js +167 -73
- package/dest/blob_batching.d.ts +48 -15
- package/dest/blob_batching.d.ts.map +1 -1
- package/dest/blob_batching.js +120 -81
- package/dest/blob_batching_public_inputs.d.ts +71 -0
- package/dest/blob_batching_public_inputs.d.ts.map +1 -0
- package/dest/blob_batching_public_inputs.js +168 -0
- package/dest/encoding.d.ts +62 -22
- package/dest/encoding.d.ts.map +1 -1
- package/dest/encoding.js +104 -114
- package/dest/index.d.ts +2 -5
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +15 -5
- package/dest/sponge_blob.d.ts +9 -13
- package/dest/sponge_blob.d.ts.map +1 -1
- package/dest/sponge_blob.js +17 -28
- package/dest/testing.d.ts +12 -7
- package/dest/testing.d.ts.map +1 -1
- package/dest/testing.js +41 -54
- package/dest/types.d.ts +0 -2
- package/dest/types.d.ts.map +1 -1
- package/dest/types.js +0 -2
- package/package.json +4 -5
- package/src/blob.ts +198 -76
- package/src/blob_batching.ts +137 -109
- package/src/blob_batching_public_inputs.ts +252 -0
- package/src/encoding.ts +120 -136
- package/src/index.ts +18 -5
- package/src/sponge_blob.ts +14 -24
- package/src/testing.ts +40 -55
- package/src/types.ts +2 -2
- package/dest/blob_utils.d.ts +0 -30
- package/dest/blob_utils.d.ts.map +0 -1
- package/dest/blob_utils.js +0 -60
- package/dest/circuit_types/blob_accumulator.d.ts +0 -21
- package/dest/circuit_types/blob_accumulator.d.ts.map +0 -1
- package/dest/circuit_types/blob_accumulator.js +0 -58
- package/dest/circuit_types/final_blob_accumulator.d.ts +0 -22
- package/dest/circuit_types/final_blob_accumulator.d.ts.map +0 -1
- package/dest/circuit_types/final_blob_accumulator.js +0 -63
- package/dest/circuit_types/final_blob_batching_challenges.d.ts +0 -15
- package/dest/circuit_types/final_blob_batching_challenges.d.ts.map +0 -1
- package/dest/circuit_types/final_blob_batching_challenges.js +0 -25
- package/dest/circuit_types/index.d.ts +0 -4
- package/dest/circuit_types/index.d.ts.map +0 -1
- package/dest/circuit_types/index.js +0 -4
- package/dest/deserialize.d.ts +0 -14
- package/dest/deserialize.d.ts.map +0 -1
- package/dest/deserialize.js +0 -33
- package/dest/hash.d.ts +0 -35
- package/dest/hash.d.ts.map +0 -1
- package/dest/hash.js +0 -69
- package/dest/kzg_context.d.ts +0 -4
- package/dest/kzg_context.d.ts.map +0 -1
- package/dest/kzg_context.js +0 -5
- package/src/blob_utils.ts +0 -71
- package/src/circuit_types/blob_accumulator.ts +0 -84
- package/src/circuit_types/final_blob_accumulator.ts +0 -75
- package/src/circuit_types/final_blob_batching_challenges.ts +0 -29
- package/src/circuit_types/index.ts +0 -4
- package/src/deserialize.ts +0 -38
- package/src/hash.ts +0 -77
- package/src/kzg_context.ts +0 -5
package/dest/blob.d.ts
CHANGED
|
@@ -1,58 +1,54 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BLS12Fr, Fr } from '@aztec/foundation/fields';
|
|
1
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
3
2
|
import { BufferReader } from '@aztec/foundation/serialize';
|
|
3
|
+
import cKzg from 'c-kzg';
|
|
4
|
+
import type { Blob as BlobBuffer } from 'c-kzg';
|
|
4
5
|
import type { BlobJson } from './interface.js';
|
|
5
|
-
export
|
|
6
|
+
export declare const VERSIONED_HASH_VERSION_KZG = 1;
|
|
7
|
+
/** Versioned blob hash for an empty blob */
|
|
8
|
+
export declare const EMPTY_BLOB_VERSIONED_HASH: Buffer<ArrayBuffer>;
|
|
6
9
|
/**
|
|
7
10
|
* A class to create, manage, and prove EVM blobs.
|
|
8
|
-
*
|
|
9
|
-
* @dev Note: All methods in this class do not check the encoding of the given data. It's the responsibility of other
|
|
10
|
-
* components to ensure that the blob data (which might spread across multiple blobs) was created following the protocol
|
|
11
|
-
* and is correctly encoded.
|
|
12
11
|
*/
|
|
13
12
|
export declare class Blob {
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
readonly
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
/** The blob to be broadcast on L1 in bytes form. */
|
|
14
|
+
readonly data: BlobBuffer;
|
|
15
|
+
/** The hash of all tx effects inside the blob. Used in generating the challenge z and proving that we have included all required effects. */
|
|
16
|
+
readonly fieldsHash: Fr;
|
|
17
|
+
/** Challenge point z (= H(H(tx_effects), kzgCommmitment). Used such that p(z) = y for a single blob, used as z_i in batching (see ./blob_batching.ts). */
|
|
18
|
+
readonly challengeZ: Fr;
|
|
19
|
+
/** Commitment to the blob C. Used in compressed BLS12 point format (48 bytes). */
|
|
21
20
|
readonly commitment: Buffer;
|
|
22
21
|
constructor(
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
/** The blob to be broadcast on L1 in bytes form. */
|
|
23
|
+
data: BlobBuffer,
|
|
24
|
+
/** The hash of all tx effects inside the blob. Used in generating the challenge z and proving that we have included all required effects. */
|
|
25
|
+
fieldsHash: Fr,
|
|
26
|
+
/** Challenge point z (= H(H(tx_effects), kzgCommmitment). Used such that p(z) = y for a single blob, used as z_i in batching (see ./blob_batching.ts). */
|
|
27
|
+
challengeZ: Fr,
|
|
28
|
+
/** Commitment to the blob C. Used in compressed BLS12 point format (48 bytes). */
|
|
30
29
|
commitment: Buffer);
|
|
31
30
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* The encoded version of the blob will determine the end of the blob based on the transaction encoding.
|
|
32
|
+
* This is required when the fieldsHash of a blob will contain trailing zeros.
|
|
33
|
+
*
|
|
34
|
+
* See `./encoding.ts` for more details.
|
|
35
|
+
*
|
|
36
|
+
* This method is used to create a Blob from a buffer.
|
|
37
|
+
* @param blob - The buffer to create the Blob from.
|
|
38
|
+
* @param multiBlobFieldsHash - The fields hash to use for the Blob.
|
|
34
39
|
* @returns A Blob created from the buffer.
|
|
35
40
|
*
|
|
36
|
-
* @throws If
|
|
41
|
+
* @throws If unable to deserialize the blob.
|
|
37
42
|
*/
|
|
38
|
-
static
|
|
43
|
+
static fromEncodedBlobBuffer(blob: BlobBuffer, multiBlobFieldsHash?: Fr): Promise<Blob>;
|
|
39
44
|
/**
|
|
40
45
|
* Create a Blob from an array of fields.
|
|
41
46
|
*
|
|
42
|
-
* @dev This method pads 0s to the data, extending it to the size of a full blob.
|
|
43
|
-
*
|
|
44
47
|
* @param fields - The array of fields to create the Blob from.
|
|
48
|
+
* @param multiBlobFieldsHash - The fields hash to use for the Blob.
|
|
45
49
|
* @returns A Blob created from the array of fields.
|
|
46
50
|
*/
|
|
47
|
-
static fromFields(fields: Fr[]): Blob
|
|
48
|
-
/**
|
|
49
|
-
* Get the fields from the blob data.
|
|
50
|
-
*
|
|
51
|
-
* @dev WARNING: this method returns all fields
|
|
52
|
-
*
|
|
53
|
-
* @returns The fields from the blob.
|
|
54
|
-
*/
|
|
55
|
-
toFields(): Fr[];
|
|
51
|
+
static fromFields(fields: Fr[], multiBlobFieldsHash?: Fr): Promise<Blob>;
|
|
56
52
|
/**
|
|
57
53
|
* Create a Blob from a JSON object.
|
|
58
54
|
*
|
|
@@ -60,41 +56,78 @@ export declare class Blob {
|
|
|
60
56
|
* the beacon chain via `getBlobSidecars`
|
|
61
57
|
* https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Beacon/getBlobSidecars
|
|
62
58
|
*
|
|
59
|
+
* @dev WARNING: by default json deals with encoded buffers
|
|
60
|
+
*
|
|
63
61
|
* @param json - The JSON object to create the Blob from.
|
|
64
62
|
* @returns A Blob created from the JSON object.
|
|
65
63
|
*/
|
|
66
|
-
static fromJson(json: BlobJson): Blob
|
|
64
|
+
static fromJson(json: BlobJson): Promise<Blob>;
|
|
67
65
|
/**
|
|
68
66
|
* Get the JSON representation of the blob.
|
|
69
67
|
*
|
|
68
|
+
* @dev WARNING: by default json deals with encoded buffers
|
|
70
69
|
* @param index - optional - The index of the blob in the block.
|
|
71
70
|
* @returns The JSON representation of the blob.
|
|
72
71
|
*/
|
|
73
72
|
toJson(index: number): BlobJson;
|
|
74
|
-
getEthVersionedBlobHash(): Buffer;
|
|
75
73
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
74
|
+
* Get the fields from the blob.
|
|
75
|
+
*
|
|
76
|
+
* @dev WARNING: this method does not take into account trailing zeros
|
|
77
|
+
*
|
|
78
|
+
* @returns The fields from the blob.
|
|
79
|
+
*/
|
|
80
|
+
toFields(): Fr[];
|
|
81
|
+
/**
|
|
82
|
+
* Get the encoded fields from the blob.
|
|
83
|
+
*
|
|
84
|
+
* @dev This method takes into account trailing zeros
|
|
85
|
+
*
|
|
86
|
+
* @returns The encoded fields from the blob.
|
|
87
|
+
*
|
|
88
|
+
* @throws If unable to deserialize the blob.
|
|
89
|
+
*/
|
|
90
|
+
toEncodedFields(): Fr[];
|
|
91
|
+
/**
|
|
92
|
+
* Get the encoded fields from multiple blobs.
|
|
93
|
+
*
|
|
94
|
+
* @dev This method takes into account trailing zeros
|
|
95
|
+
*
|
|
96
|
+
* @returns The encoded fields from the blobs.
|
|
97
|
+
*/
|
|
98
|
+
static toEncodedFields(blobs: Blob[]): Fr[];
|
|
99
|
+
/**
|
|
100
|
+
* Get the commitment fields from the blob.
|
|
101
|
+
*
|
|
102
|
+
* The 48-byte commitment is encoded into two field elements:
|
|
103
|
+
* +------------------+------------------+
|
|
104
|
+
* | Field Element 1 | Field Element 2 |
|
|
105
|
+
* | [bytes 0-31] | [bytes 32-47] |
|
|
106
|
+
* +------------------+------------------+
|
|
107
|
+
* | 32 bytes | 16 bytes |
|
|
108
|
+
* +------------------+------------------+
|
|
109
|
+
* @returns The commitment fields from the blob.
|
|
78
110
|
*/
|
|
79
|
-
|
|
111
|
+
commitmentToFields(): [Fr, Fr];
|
|
112
|
+
getEthVersionedBlobHash(): Buffer;
|
|
113
|
+
static getEthVersionedBlobHash(commitment: Buffer): Buffer;
|
|
80
114
|
/**
|
|
81
115
|
* Evaluate the blob at a given challenge and return the evaluation and KZG proof.
|
|
82
116
|
*
|
|
83
|
-
* @param challengeZ - The challenge z at which to evaluate the blob.
|
|
84
|
-
* @param verifyProof - Whether to verify the KZG proof.
|
|
117
|
+
* @param challengeZ - The challenge z at which to evaluate the blob. If not given, assume we want to evaluate at the individual blob's z.
|
|
85
118
|
*
|
|
86
|
-
* @returns
|
|
87
|
-
* y:
|
|
119
|
+
* @returns -
|
|
120
|
+
* y: Buffer - Evaluation y = p(z), where p() is the blob polynomial. BLS12 field element, rep. as BigNum in nr, bigint in ts
|
|
88
121
|
* proof: Buffer - KZG opening proof for y = p(z). The commitment to quotient polynomial Q, used in compressed BLS12 point format (48 bytes).
|
|
89
122
|
*/
|
|
90
|
-
evaluate(challengeZ
|
|
91
|
-
y:
|
|
123
|
+
evaluate(challengeZ?: Fr): {
|
|
124
|
+
y: Buffer<ArrayBuffer>;
|
|
92
125
|
proof: Buffer<ArrayBuffer>;
|
|
93
126
|
};
|
|
94
127
|
/**
|
|
95
128
|
* Get the buffer representation of the ENTIRE blob.
|
|
96
129
|
*
|
|
97
|
-
* @dev WARNING: this buffer contains all metadata
|
|
130
|
+
* @dev WARNING: this buffer contains all metadata aswell as the data itself
|
|
98
131
|
*
|
|
99
132
|
* @returns The buffer representation of the blob.
|
|
100
133
|
*/
|
|
@@ -102,7 +135,7 @@ export declare class Blob {
|
|
|
102
135
|
/**
|
|
103
136
|
* Create a Blob from a buffer.
|
|
104
137
|
*
|
|
105
|
-
* @dev WARNING: this method contains all metadata
|
|
138
|
+
* @dev WARNING: this method contains all metadata aswell as the data itself
|
|
106
139
|
*
|
|
107
140
|
* @param buf - The buffer to create the Blob from.
|
|
108
141
|
* @returns A Blob created from the buffer.
|
|
@@ -112,10 +145,23 @@ export declare class Blob {
|
|
|
112
145
|
* Get the size of the blob in bytes
|
|
113
146
|
*/
|
|
114
147
|
getSize(): number;
|
|
148
|
+
/**
|
|
149
|
+
* @param blobs - The blobs to emit
|
|
150
|
+
* @returns The blobs' compressed commitments in hex prefixed by the number of blobs
|
|
151
|
+
* @dev Used for proposing blocks to validate injected blob commitments match real broadcast blobs:
|
|
152
|
+
* One byte for the number blobs + 48 bytes per blob commitment
|
|
153
|
+
*/
|
|
154
|
+
static getPrefixedEthBlobCommitments(blobs: Blob[]): `0x${string}`;
|
|
115
155
|
static getViemKzgInstance(): {
|
|
116
|
-
blobToKzgCommitment:
|
|
117
|
-
computeBlobKzgProof:
|
|
118
|
-
computeCellsAndKzgProofs:
|
|
156
|
+
blobToKzgCommitment: typeof cKzg.blobToKzgCommitment;
|
|
157
|
+
computeBlobKzgProof: typeof cKzg.computeBlobKzgProof;
|
|
158
|
+
computeCellsAndKzgProofs: typeof cKzg.computeCellsAndKzgProofs;
|
|
119
159
|
};
|
|
160
|
+
/**
|
|
161
|
+
* @param fields - Fields to broadcast in the blob(s)
|
|
162
|
+
* @returns As many blobs as we require to broadcast the given fields for a block
|
|
163
|
+
* @dev Assumes we share the fields hash between all blobs which can only be done for ONE BLOCK because the hash is calculated in block root.
|
|
164
|
+
*/
|
|
165
|
+
static getBlobsPerBlock(fields: Fr[]): Promise<Blob[]>;
|
|
120
166
|
}
|
|
121
167
|
//# sourceMappingURL=blob.d.ts.map
|
package/dest/blob.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blob.d.ts","sourceRoot":"","sources":["../src/blob.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"blob.d.ts","sourceRoot":"","sources":["../src/blob.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAqB,MAAM,6BAA6B,CAAC;AAG9E,OAAO,IAAI,MAAM,OAAO,CAAC;AACzB,OAAO,KAAK,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,OAAO,CAAC;AAIhD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAK/C,eAAO,MAAM,0BAA0B,IAAO,CAAC;AAE/C,4CAA4C;AAC5C,eAAO,MAAM,yBAAyB,qBAGrC,CAAC;AAEF;;GAEG;AACH,qBAAa,IAAI;IAEb,oDAAoD;aACpC,IAAI,EAAE,UAAU;IAChC,6IAA6I;aAC7H,UAAU,EAAE,EAAE;IAC9B,0JAA0J;aAC1I,UAAU,EAAE,EAAE;IAC9B,kFAAkF;aAClE,UAAU,EAAE,MAAM;;IAPlC,oDAAoD;IACpC,IAAI,EAAE,UAAU;IAChC,6IAA6I;IAC7H,UAAU,EAAE,EAAE;IAC9B,0JAA0J;IAC1I,UAAU,EAAE,EAAE;IAC9B,kFAAkF;IAClE,UAAU,EAAE,MAAM;IAGpC;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,qBAAqB,CAAC,IAAI,EAAE,UAAU,EAAE,mBAAmB,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAWvF;;;;;;OAMG;WACU,UAAU,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,mBAAmB,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB9E;;;;;;;;;;;OAWG;WACU,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAepD;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ;IAS/B;;;;;;OAMG;IACH,QAAQ,IAAI,EAAE,EAAE;IAIhB;;;;;;;;OAQG;IACH,eAAe,IAAI,EAAE,EAAE;IAUvB;;;;;;OAMG;IACH,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IAU3C;;;;;;;;;;;OAWG;IACH,kBAAkB,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;IAK9B,uBAAuB,IAAI,MAAM;IAMjC,MAAM,CAAC,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAM1D;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,EAAE;;;;IAWxB;;;;;;OAMG;IACH,QAAQ,IAAI,MAAM;IAalB;;;;;;;OAOG;IACH,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAKnD;;OAEG;IACH,OAAO;IAIP;;;;;OAKG;IACH,MAAM,CAAC,6BAA6B,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,MAAM,EAAE;IAYlE,MAAM,CAAC,kBAAkB;;;;;IAQzB;;;;OAIG;WACU,gBAAgB,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;CAU7D"}
|
package/dest/blob.js
CHANGED
|
@@ -1,69 +1,68 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { poseidon2Hash, sha256 } from '@aztec/foundation/crypto';
|
|
2
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
3
3
|
import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
4
|
-
|
|
5
|
-
import
|
|
6
|
-
|
|
4
|
+
// Importing directly from 'c-kzg' does not work:
|
|
5
|
+
import cKzg from 'c-kzg';
|
|
6
|
+
import { deserializeEncodedBlobToFields, extractBlobFieldsFromBuffer } from './encoding.js';
|
|
7
|
+
import { BlobDeserializationError } from './errors.js';
|
|
8
|
+
const { BYTES_PER_BLOB, FIELD_ELEMENTS_PER_BLOB, blobToKzgCommitment, computeKzgProof, verifyKzgProof } = cKzg;
|
|
9
|
+
// The prefix to the EVM blobHash, defined here: https://eips.ethereum.org/EIPS/eip-4844#specification
|
|
10
|
+
export const VERSIONED_HASH_VERSION_KZG = 0x01;
|
|
11
|
+
/** Versioned blob hash for an empty blob */ export const EMPTY_BLOB_VERSIONED_HASH = Buffer.from(`010657f37554c781402a22917dee2f75def7ab966d7b770905398eba3c444014`, 'hex');
|
|
7
12
|
/**
|
|
8
13
|
* A class to create, manage, and prove EVM blobs.
|
|
9
|
-
*
|
|
10
|
-
* @dev Note: All methods in this class do not check the encoding of the given data. It's the responsibility of other
|
|
11
|
-
* components to ensure that the blob data (which might spread across multiple blobs) was created following the protocol
|
|
12
|
-
* and is correctly encoded.
|
|
13
14
|
*/ export class Blob {
|
|
14
15
|
data;
|
|
16
|
+
fieldsHash;
|
|
17
|
+
challengeZ;
|
|
15
18
|
commitment;
|
|
16
|
-
constructor(/**
|
|
17
|
-
* The data to be broadcast on L1 in bytes form.
|
|
18
|
-
*/ data, /**
|
|
19
|
-
* Commitment to the blob data. Used in compressed BLS12 point format (48 bytes).
|
|
20
|
-
*/ commitment){
|
|
19
|
+
constructor(/** The blob to be broadcast on L1 in bytes form. */ data, /** The hash of all tx effects inside the blob. Used in generating the challenge z and proving that we have included all required effects. */ fieldsHash, /** Challenge point z (= H(H(tx_effects), kzgCommmitment). Used such that p(z) = y for a single blob, used as z_i in batching (see ./blob_batching.ts). */ challengeZ, /** Commitment to the blob C. Used in compressed BLS12 point format (48 bytes). */ commitment){
|
|
21
20
|
this.data = data;
|
|
21
|
+
this.fieldsHash = fieldsHash;
|
|
22
|
+
this.challengeZ = challengeZ;
|
|
22
23
|
this.commitment = commitment;
|
|
23
|
-
if (data.length !== BYTES_PER_BLOB) {
|
|
24
|
-
throw new Error(`Blob data must be ${BYTES_PER_BLOB} bytes. Got ${data.length}.`);
|
|
25
|
-
}
|
|
26
|
-
if (commitment.length !== BYTES_PER_COMMITMENT) {
|
|
27
|
-
throw new Error(`Blob commitment must be ${BYTES_PER_COMMITMENT} bytes. Got ${commitment.length}.`);
|
|
28
|
-
}
|
|
29
24
|
}
|
|
30
25
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
26
|
+
* The encoded version of the blob will determine the end of the blob based on the transaction encoding.
|
|
27
|
+
* This is required when the fieldsHash of a blob will contain trailing zeros.
|
|
28
|
+
*
|
|
29
|
+
* See `./encoding.ts` for more details.
|
|
30
|
+
*
|
|
31
|
+
* This method is used to create a Blob from a buffer.
|
|
32
|
+
* @param blob - The buffer to create the Blob from.
|
|
33
|
+
* @param multiBlobFieldsHash - The fields hash to use for the Blob.
|
|
33
34
|
* @returns A Blob created from the buffer.
|
|
34
35
|
*
|
|
35
|
-
* @throws If
|
|
36
|
-
*/ static
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
* @throws If unable to deserialize the blob.
|
|
37
|
+
*/ static fromEncodedBlobBuffer(blob, multiBlobFieldsHash) {
|
|
38
|
+
try {
|
|
39
|
+
const fields = deserializeEncodedBlobToFields(blob);
|
|
40
|
+
return Blob.fromFields(fields, multiBlobFieldsHash);
|
|
41
|
+
} catch {
|
|
42
|
+
throw new BlobDeserializationError(`Failed to create Blob from encoded blob buffer, this blob was likely not created by us`);
|
|
43
|
+
}
|
|
39
44
|
}
|
|
40
45
|
/**
|
|
41
46
|
* Create a Blob from an array of fields.
|
|
42
47
|
*
|
|
43
|
-
* @dev This method pads 0s to the data, extending it to the size of a full blob.
|
|
44
|
-
*
|
|
45
48
|
* @param fields - The array of fields to create the Blob from.
|
|
49
|
+
* @param multiBlobFieldsHash - The fields hash to use for the Blob.
|
|
46
50
|
* @returns A Blob created from the array of fields.
|
|
47
|
-
*/ static fromFields(fields) {
|
|
48
|
-
if (fields.length >
|
|
49
|
-
throw new Error(`Attempted to overfill blob with ${fields.length}
|
|
51
|
+
*/ static async fromFields(fields, multiBlobFieldsHash) {
|
|
52
|
+
if (fields.length > FIELD_ELEMENTS_PER_BLOB) {
|
|
53
|
+
throw new Error(`Attempted to overfill blob with ${fields.length} elements. The maximum is ${FIELD_ELEMENTS_PER_BLOB}`);
|
|
50
54
|
}
|
|
51
55
|
const data = Buffer.concat([
|
|
52
56
|
serializeToBuffer(fields)
|
|
53
57
|
], BYTES_PER_BLOB);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
* @returns The fields from the blob.
|
|
63
|
-
*/ toFields() {
|
|
64
|
-
const reader = BufferReader.asReader(this.data);
|
|
65
|
-
const numTotalFields = this.data.length / Fr.SIZE_IN_BYTES;
|
|
66
|
-
return reader.readArray(numTotalFields, Fr);
|
|
58
|
+
// This matches the output of SpongeBlob.squeeze() in the blob circuit
|
|
59
|
+
const fieldsHash = multiBlobFieldsHash ? multiBlobFieldsHash : await poseidon2Hash(fields);
|
|
60
|
+
const commitment = Buffer.from(blobToKzgCommitment(data));
|
|
61
|
+
const challengeZ = await poseidon2Hash([
|
|
62
|
+
fieldsHash,
|
|
63
|
+
...commitmentToFields(commitment)
|
|
64
|
+
]);
|
|
65
|
+
return new Blob(data, fieldsHash, challengeZ, commitment);
|
|
67
66
|
}
|
|
68
67
|
/**
|
|
69
68
|
* Create a Blob from a JSON object.
|
|
@@ -72,19 +71,24 @@ export { FIELDS_PER_BLOB };
|
|
|
72
71
|
* the beacon chain via `getBlobSidecars`
|
|
73
72
|
* https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Beacon/getBlobSidecars
|
|
74
73
|
*
|
|
74
|
+
* @dev WARNING: by default json deals with encoded buffers
|
|
75
|
+
*
|
|
75
76
|
* @param json - The JSON object to create the Blob from.
|
|
76
77
|
* @returns A Blob created from the JSON object.
|
|
77
|
-
*/ static fromJson(json) {
|
|
78
|
+
*/ static async fromJson(json) {
|
|
78
79
|
const blobBuffer = Buffer.from(json.blob.slice(2), 'hex');
|
|
79
|
-
const blob = Blob.
|
|
80
|
+
const blob = await Blob.fromEncodedBlobBuffer(blobBuffer);
|
|
80
81
|
if (blob.commitment.toString('hex') !== json.kzg_commitment.slice(2)) {
|
|
81
82
|
throw new Error('KZG commitment does not match');
|
|
82
83
|
}
|
|
84
|
+
// We do not check the proof, as it will be different if the challenge is shared
|
|
85
|
+
// across multiple blobs
|
|
83
86
|
return blob;
|
|
84
87
|
}
|
|
85
88
|
/**
|
|
86
89
|
* Get the JSON representation of the blob.
|
|
87
90
|
*
|
|
91
|
+
* @dev WARNING: by default json deals with encoded buffers
|
|
88
92
|
* @param index - optional - The index of the blob in the block.
|
|
89
93
|
* @returns The JSON representation of the blob.
|
|
90
94
|
*/ toJson(index) {
|
|
@@ -95,31 +99,84 @@ export { FIELDS_PER_BLOB };
|
|
|
95
99
|
kzg_commitment: `0x${this.commitment.toString('hex')}`
|
|
96
100
|
};
|
|
97
101
|
}
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Get the fields from the blob.
|
|
104
|
+
*
|
|
105
|
+
* @dev WARNING: this method does not take into account trailing zeros
|
|
106
|
+
*
|
|
107
|
+
* @returns The fields from the blob.
|
|
108
|
+
*/ toFields() {
|
|
109
|
+
return extractBlobFieldsFromBuffer(this.data);
|
|
100
110
|
}
|
|
101
111
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
|
|
105
|
-
|
|
112
|
+
* Get the encoded fields from the blob.
|
|
113
|
+
*
|
|
114
|
+
* @dev This method takes into account trailing zeros
|
|
115
|
+
*
|
|
116
|
+
* @returns The encoded fields from the blob.
|
|
117
|
+
*
|
|
118
|
+
* @throws If unable to deserialize the blob.
|
|
119
|
+
*/ toEncodedFields() {
|
|
120
|
+
try {
|
|
121
|
+
return deserializeEncodedBlobToFields(this.data);
|
|
122
|
+
} catch {
|
|
123
|
+
throw new BlobDeserializationError(`Failed to deserialize encoded blob fields, this blob was likely not created by us`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get the encoded fields from multiple blobs.
|
|
128
|
+
*
|
|
129
|
+
* @dev This method takes into account trailing zeros
|
|
130
|
+
*
|
|
131
|
+
* @returns The encoded fields from the blobs.
|
|
132
|
+
*/ static toEncodedFields(blobs) {
|
|
133
|
+
try {
|
|
134
|
+
return deserializeEncodedBlobToFields(Buffer.concat(blobs.map((b)=>b.data)));
|
|
135
|
+
} catch {
|
|
136
|
+
throw new BlobDeserializationError(`Failed to deserialize encoded blob fields, this blob was likely not created by us`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get the commitment fields from the blob.
|
|
141
|
+
*
|
|
142
|
+
* The 48-byte commitment is encoded into two field elements:
|
|
143
|
+
* +------------------+------------------+
|
|
144
|
+
* | Field Element 1 | Field Element 2 |
|
|
145
|
+
* | [bytes 0-31] | [bytes 32-47] |
|
|
146
|
+
* +------------------+------------------+
|
|
147
|
+
* | 32 bytes | 16 bytes |
|
|
148
|
+
* +------------------+------------------+
|
|
149
|
+
* @returns The commitment fields from the blob.
|
|
150
|
+
*/ commitmentToFields() {
|
|
151
|
+
return commitmentToFields(this.commitment);
|
|
152
|
+
}
|
|
153
|
+
// Returns ethereum's versioned blob hash, following kzg_to_versioned_hash: https://eips.ethereum.org/EIPS/eip-4844#helpers
|
|
154
|
+
getEthVersionedBlobHash() {
|
|
155
|
+
const hash = sha256(this.commitment);
|
|
156
|
+
hash[0] = VERSIONED_HASH_VERSION_KZG;
|
|
157
|
+
return hash;
|
|
158
|
+
}
|
|
159
|
+
static getEthVersionedBlobHash(commitment) {
|
|
160
|
+
const hash = sha256(commitment);
|
|
161
|
+
hash[0] = VERSIONED_HASH_VERSION_KZG;
|
|
162
|
+
return hash;
|
|
106
163
|
}
|
|
107
164
|
/**
|
|
108
165
|
* Evaluate the blob at a given challenge and return the evaluation and KZG proof.
|
|
109
166
|
*
|
|
110
|
-
* @param challengeZ - The challenge z at which to evaluate the blob.
|
|
111
|
-
* @param verifyProof - Whether to verify the KZG proof.
|
|
167
|
+
* @param challengeZ - The challenge z at which to evaluate the blob. If not given, assume we want to evaluate at the individual blob's z.
|
|
112
168
|
*
|
|
113
|
-
* @returns
|
|
114
|
-
* y:
|
|
169
|
+
* @returns -
|
|
170
|
+
* y: Buffer - Evaluation y = p(z), where p() is the blob polynomial. BLS12 field element, rep. as BigNum in nr, bigint in ts
|
|
115
171
|
* proof: Buffer - KZG opening proof for y = p(z). The commitment to quotient polynomial Q, used in compressed BLS12 point format (48 bytes).
|
|
116
|
-
*/ evaluate(challengeZ
|
|
117
|
-
const
|
|
118
|
-
|
|
172
|
+
*/ evaluate(challengeZ) {
|
|
173
|
+
const z = challengeZ || this.challengeZ;
|
|
174
|
+
const res = computeKzgProof(this.data, z.toBuffer());
|
|
175
|
+
if (!verifyKzgProof(this.commitment, z.toBuffer(), res[1], res[0])) {
|
|
119
176
|
throw new Error(`KZG proof did not verify.`);
|
|
120
177
|
}
|
|
121
178
|
const proof = Buffer.from(res[0]);
|
|
122
|
-
const y =
|
|
179
|
+
const y = Buffer.from(res[1]);
|
|
123
180
|
return {
|
|
124
181
|
y,
|
|
125
182
|
proof
|
|
@@ -128,39 +185,76 @@ export { FIELDS_PER_BLOB };
|
|
|
128
185
|
/**
|
|
129
186
|
* Get the buffer representation of the ENTIRE blob.
|
|
130
187
|
*
|
|
131
|
-
* @dev WARNING: this buffer contains all metadata
|
|
188
|
+
* @dev WARNING: this buffer contains all metadata aswell as the data itself
|
|
132
189
|
*
|
|
133
190
|
* @returns The buffer representation of the blob.
|
|
134
191
|
*/ toBuffer() {
|
|
135
|
-
return Buffer.from(serializeToBuffer(this.data.length, this.data, this.commitment.length, this.commitment));
|
|
192
|
+
return Buffer.from(serializeToBuffer(this.data.length, this.data, this.fieldsHash, this.challengeZ, this.commitment.length, this.commitment));
|
|
136
193
|
}
|
|
137
194
|
/**
|
|
138
195
|
* Create a Blob from a buffer.
|
|
139
196
|
*
|
|
140
|
-
* @dev WARNING: this method contains all metadata
|
|
197
|
+
* @dev WARNING: this method contains all metadata aswell as the data itself
|
|
141
198
|
*
|
|
142
199
|
* @param buf - The buffer to create the Blob from.
|
|
143
200
|
* @returns A Blob created from the buffer.
|
|
144
201
|
*/ static fromBuffer(buf) {
|
|
145
202
|
const reader = BufferReader.asReader(buf);
|
|
146
|
-
return new Blob(reader.readUint8Array(), reader.readBuffer());
|
|
203
|
+
return new Blob(reader.readUint8Array(), reader.readObject(Fr), reader.readObject(Fr), reader.readBuffer());
|
|
147
204
|
}
|
|
148
205
|
/**
|
|
149
206
|
* Get the size of the blob in bytes
|
|
150
207
|
*/ getSize() {
|
|
151
208
|
return this.data.length;
|
|
152
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* @param blobs - The blobs to emit
|
|
212
|
+
* @returns The blobs' compressed commitments in hex prefixed by the number of blobs
|
|
213
|
+
* @dev Used for proposing blocks to validate injected blob commitments match real broadcast blobs:
|
|
214
|
+
* One byte for the number blobs + 48 bytes per blob commitment
|
|
215
|
+
*/ static getPrefixedEthBlobCommitments(blobs) {
|
|
216
|
+
let buf = Buffer.alloc(0);
|
|
217
|
+
blobs.forEach((blob)=>{
|
|
218
|
+
buf = Buffer.concat([
|
|
219
|
+
buf,
|
|
220
|
+
blob.commitment
|
|
221
|
+
]);
|
|
222
|
+
});
|
|
223
|
+
// We prefix the number of blobs:
|
|
224
|
+
const lenBuf = Buffer.alloc(1);
|
|
225
|
+
lenBuf.writeUint8(blobs.length);
|
|
226
|
+
buf = Buffer.concat([
|
|
227
|
+
lenBuf,
|
|
228
|
+
buf
|
|
229
|
+
]);
|
|
230
|
+
return `0x${buf.toString('hex')}`;
|
|
231
|
+
}
|
|
153
232
|
static getViemKzgInstance() {
|
|
154
233
|
return {
|
|
155
|
-
blobToKzgCommitment:
|
|
156
|
-
computeBlobKzgProof:
|
|
157
|
-
computeCellsAndKzgProofs:
|
|
158
|
-
const result = kzg.computeCellsAndKzgProofs(b);
|
|
159
|
-
return [
|
|
160
|
-
result.cells,
|
|
161
|
-
result.proofs
|
|
162
|
-
];
|
|
163
|
-
}
|
|
234
|
+
blobToKzgCommitment: cKzg.blobToKzgCommitment,
|
|
235
|
+
computeBlobKzgProof: cKzg.computeBlobKzgProof,
|
|
236
|
+
computeCellsAndKzgProofs: cKzg.computeCellsAndKzgProofs
|
|
164
237
|
};
|
|
165
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* @param fields - Fields to broadcast in the blob(s)
|
|
241
|
+
* @returns As many blobs as we require to broadcast the given fields for a block
|
|
242
|
+
* @dev Assumes we share the fields hash between all blobs which can only be done for ONE BLOCK because the hash is calculated in block root.
|
|
243
|
+
*/ static async getBlobsPerBlock(fields) {
|
|
244
|
+
const numBlobs = Math.max(Math.ceil(fields.length / FIELD_ELEMENTS_PER_BLOB), 1);
|
|
245
|
+
const multiBlobFieldsHash = await poseidon2Hash(fields);
|
|
246
|
+
const res = [];
|
|
247
|
+
for(let i = 0; i < numBlobs; i++){
|
|
248
|
+
const end = fields.length < (i + 1) * FIELD_ELEMENTS_PER_BLOB ? fields.length : (i + 1) * FIELD_ELEMENTS_PER_BLOB;
|
|
249
|
+
res.push(await Blob.fromFields(fields.slice(i * FIELD_ELEMENTS_PER_BLOB, end), multiBlobFieldsHash));
|
|
250
|
+
}
|
|
251
|
+
return res;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// 48 bytes encoded in fields as [Fr, Fr] = [0->31, 31->48]
|
|
255
|
+
function commitmentToFields(commitment) {
|
|
256
|
+
return [
|
|
257
|
+
new Fr(commitment.subarray(0, 31)),
|
|
258
|
+
new Fr(commitment.subarray(31, 48))
|
|
259
|
+
];
|
|
166
260
|
}
|