@aztec/foundation 0.22.0 → 0.24.0

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.
Files changed (121) hide show
  1. package/dest/abi/buffer.js +2 -2
  2. package/dest/fields/fields.d.ts +1 -0
  3. package/dest/fields/fields.d.ts.map +1 -1
  4. package/dest/fields/fields.js +6 -3
  5. package/package.json +2 -2
  6. package/src/abi/abi.ts +337 -0
  7. package/src/abi/buffer.ts +36 -0
  8. package/src/abi/decoder.ts +176 -0
  9. package/src/abi/encoder.ts +143 -0
  10. package/src/abi/index.ts +6 -0
  11. package/src/abi/selector.ts +243 -0
  12. package/src/abi/utils.ts +50 -0
  13. package/src/array/array.ts +86 -0
  14. package/src/array/index.ts +1 -0
  15. package/src/async-map/index.ts +18 -0
  16. package/src/aztec-address/index.ts +36 -0
  17. package/src/bigint-buffer/index.ts +87 -0
  18. package/src/collection/array.ts +64 -0
  19. package/src/collection/index.ts +1 -0
  20. package/src/committable/committable.ts +46 -0
  21. package/src/committable/index.ts +1 -0
  22. package/src/crypto/index.ts +16 -0
  23. package/src/crypto/keccak/index.ts +33 -0
  24. package/src/crypto/pedersen/index.ts +1 -0
  25. package/src/crypto/pedersen/pedersen.elliptic.ts +584 -0
  26. package/src/crypto/pedersen/pedersen.noble.ts +573 -0
  27. package/src/crypto/pedersen/pedersen.wasm.ts +42 -0
  28. package/src/crypto/random/index.ts +42 -0
  29. package/src/crypto/sha256/index.ts +3 -0
  30. package/src/errors/index.ts +6 -0
  31. package/src/eth-address/index.ts +234 -0
  32. package/src/fields/coordinate.ts +104 -0
  33. package/src/fields/fields.ts +328 -0
  34. package/src/fields/index.ts +3 -0
  35. package/src/fields/point.ts +145 -0
  36. package/src/fifo/bounded_serial_queue.ts +100 -0
  37. package/src/fifo/index.ts +4 -0
  38. package/src/fifo/memory_fifo.ts +118 -0
  39. package/src/fifo/semaphore.ts +33 -0
  40. package/src/fifo/serial_queue.ts +81 -0
  41. package/src/index.ts +29 -0
  42. package/src/json-rpc/README.md +55 -0
  43. package/src/json-rpc/class_converter.ts +213 -0
  44. package/src/json-rpc/client/index.ts +1 -0
  45. package/src/json-rpc/client/json_rpc_client.ts +147 -0
  46. package/src/json-rpc/convert.ts +163 -0
  47. package/src/json-rpc/fixtures/class_a.ts +15 -0
  48. package/src/json-rpc/fixtures/class_b.ts +15 -0
  49. package/src/json-rpc/fixtures/test_state.ts +59 -0
  50. package/src/json-rpc/index.ts +8 -0
  51. package/src/json-rpc/js_utils.ts +20 -0
  52. package/src/json-rpc/server/index.ts +2 -0
  53. package/src/json-rpc/server/json_proxy.ts +60 -0
  54. package/src/json-rpc/server/json_rpc_server.ts +269 -0
  55. package/src/log/console.ts +39 -0
  56. package/src/log/debug.ts +83 -0
  57. package/src/log/index.ts +5 -0
  58. package/src/log/log_fn.ts +5 -0
  59. package/src/log/log_history.ts +44 -0
  60. package/src/log/logger.ts +137 -0
  61. package/src/mutex/index.ts +83 -0
  62. package/src/mutex/mutex_database.ts +12 -0
  63. package/src/noir/index.ts +1 -0
  64. package/src/noir/noir_package_config.ts +54 -0
  65. package/src/retry/index.ts +99 -0
  66. package/src/running-promise/index.ts +60 -0
  67. package/src/serialize/buffer_reader.ts +286 -0
  68. package/src/serialize/field_reader.ts +143 -0
  69. package/src/serialize/free_funcs.ts +147 -0
  70. package/src/serialize/index.ts +5 -0
  71. package/src/serialize/serialize.ts +303 -0
  72. package/src/serialize/types.ts +40 -0
  73. package/src/sleep/index.ts +71 -0
  74. package/src/testing/index.ts +1 -0
  75. package/src/testing/test_data.ts +36 -0
  76. package/src/timer/elapsed.ts +23 -0
  77. package/src/timer/index.ts +3 -0
  78. package/src/timer/timeout.ts +64 -0
  79. package/src/timer/timer.ts +48 -0
  80. package/src/transport/browser/index.ts +4 -0
  81. package/src/transport/browser/message_port_socket.ts +48 -0
  82. package/src/transport/browser/shared_worker_connector.ts +21 -0
  83. package/src/transport/browser/shared_worker_listener.ts +53 -0
  84. package/src/transport/browser/worker_connector.ts +30 -0
  85. package/src/transport/browser/worker_listener.ts +54 -0
  86. package/src/transport/dispatch/create_dispatch_fn.ts +35 -0
  87. package/src/transport/dispatch/create_dispatch_proxy.ts +141 -0
  88. package/src/transport/dispatch/messages.ts +58 -0
  89. package/src/transport/index.ts +11 -0
  90. package/src/transport/interface/connector.ts +9 -0
  91. package/src/transport/interface/listener.ts +16 -0
  92. package/src/transport/interface/socket.ts +15 -0
  93. package/src/transport/interface/transferable.ts +125 -0
  94. package/src/transport/node/index.ts +2 -0
  95. package/src/transport/node/node_connector.ts +30 -0
  96. package/src/transport/node/node_connector_socket.ts +52 -0
  97. package/src/transport/node/node_listener.ts +34 -0
  98. package/src/transport/node/node_listener_socket.ts +48 -0
  99. package/src/transport/transport_client.ts +131 -0
  100. package/src/transport/transport_server.ts +108 -0
  101. package/src/trees/index.ts +54 -0
  102. package/src/types/index.ts +8 -0
  103. package/src/url/index.ts +73 -0
  104. package/src/wasm/README.md +6 -0
  105. package/src/wasm/empty_wasi_sdk.ts +166 -0
  106. package/src/wasm/fixtures/gcd.wasm +0 -0
  107. package/src/wasm/fixtures/gcd.wat +27 -0
  108. package/src/wasm/index.ts +1 -0
  109. package/src/wasm/wasm_module.ts +260 -0
  110. package/src/worker/browser/index.ts +2 -0
  111. package/src/worker/browser/start_web_module.ts +23 -0
  112. package/src/worker/browser/web_data_store.ts +38 -0
  113. package/src/worker/browser/web_worker.ts +24 -0
  114. package/src/worker/data_store.ts +19 -0
  115. package/src/worker/index.ts +2 -0
  116. package/src/worker/node/index.ts +2 -0
  117. package/src/worker/node/node_data_store.ts +27 -0
  118. package/src/worker/node/node_worker.ts +22 -0
  119. package/src/worker/node/start_node_module.ts +29 -0
  120. package/src/worker/wasm_worker.ts +7 -0
  121. package/src/worker/worker_pool.ts +73 -0
@@ -0,0 +1,234 @@
1
+ import { keccak256String } from '../crypto/keccak/index.js';
2
+ import { randomBytes } from '../crypto/random/index.js';
3
+ import { Fr } from '../fields/index.js';
4
+ import { BufferReader, FieldReader } from '../serialize/index.js';
5
+
6
+ /**
7
+ * Represents an Ethereum address as a 20-byte buffer and provides various utility methods
8
+ * for converting between different representations, generating random addresses, validating
9
+ * checksums, and comparing addresses. EthAddress can be instantiated using a buffer or string,
10
+ * and can be serialized/deserialized from a buffer or BufferReader.
11
+ */
12
+ export class EthAddress {
13
+ /**
14
+ * The size of an Ethereum address in bytes.
15
+ */
16
+ public static SIZE_IN_BYTES = 20;
17
+ /**
18
+ * Represents a zero Ethereum address with 20 bytes filled with zeros.
19
+ */
20
+ public static ZERO = new EthAddress(Buffer.alloc(EthAddress.SIZE_IN_BYTES));
21
+
22
+ constructor(private buffer: Buffer) {
23
+ if (buffer.length !== EthAddress.SIZE_IN_BYTES) {
24
+ throw new Error(`Expect buffer size to be ${EthAddress.SIZE_IN_BYTES}. Got ${buffer.length}.`);
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Creates an EthAddress instance from a valid Ethereum address string.
30
+ * The input 'address' can be either in checksum format or lowercase, and it can be prefixed with '0x'.
31
+ * Throws an error if the input is not a valid Ethereum address.
32
+ *
33
+ * @param address - The string representing the Ethereum address.
34
+ * @returns An EthAddress instance.
35
+ */
36
+ public static fromString(address: string) {
37
+ if (!EthAddress.isAddress(address)) {
38
+ throw new Error(`Invalid address string: ${address}`);
39
+ }
40
+ return new EthAddress(Buffer.from(address.replace(/^0x/i, ''), 'hex'));
41
+ }
42
+
43
+ /**
44
+ * Create a random EthAddress instance with 20 random bytes.
45
+ * This method generates a new Ethereum address with a randomly generated set of 20 bytes.
46
+ * It is useful for generating test addresses or unique identifiers.
47
+ *
48
+ * @returns A randomly generated EthAddress instance.
49
+ */
50
+ public static random() {
51
+ return new EthAddress(randomBytes(20));
52
+ }
53
+
54
+ /**
55
+ * Determines if the given string represents a valid Ethereum address.
56
+ * A valid address should meet the following criteria:
57
+ * 1. Contains exactly 40 hex characters (excluding an optional '0x' prefix).
58
+ * 2. Is either all lowercase, all uppercase, or has a valid checksum based on EIP-55.
59
+ *
60
+ * @param address - The string to be checked for validity as an Ethereum address.
61
+ * @returns True if the input string represents a valid Ethereum address, false otherwise.
62
+ */
63
+ public static isAddress(address: string) {
64
+ if (!/^(0x)?[0-9a-f]{40}$/i.test(address)) {
65
+ // Does not have the basic requirements of an address.
66
+ return false;
67
+ } else if (/^(0x|0X)?[0-9a-f]{40}$/.test(address) || /^(0x|0X)?[0-9A-F]{40}$/.test(address)) {
68
+ // It's ALL lowercase or ALL uppercase.
69
+ return true;
70
+ } else {
71
+ return EthAddress.checkAddressChecksum(address);
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Checks if the EthAddress instance represents a zero address.
77
+ * A zero address consists of 20 bytes filled with zeros and is considered an invalid address.
78
+ *
79
+ * @returns A boolean indicating whether the EthAddress instance is a zero address or not.
80
+ */
81
+ public isZero() {
82
+ return this.equals(EthAddress.ZERO);
83
+ }
84
+
85
+ /**
86
+ * Checks if the given Ethereum address has a valid checksum.
87
+ * The input 'address' should be prefixed with '0x' or not, and have exactly 40 hex characters.
88
+ * Returns true if the address has a valid checksum, false otherwise.
89
+ *
90
+ * @param address - The hex-encoded string representing the Ethereum address.
91
+ * @returns A boolean value indicating whether the address has a valid checksum.
92
+ */
93
+ public static checkAddressChecksum(address: string) {
94
+ address = address.replace(/^0x/i, '');
95
+ const addressHash = keccak256String(address.toLowerCase());
96
+
97
+ for (let i = 0; i < 40; i++) {
98
+ // The nth letter should be uppercase if the nth digit of casemap is 1.
99
+ if (
100
+ (parseInt(addressHash[i], 16) > 7 && address[i].toUpperCase() !== address[i]) ||
101
+ (parseInt(addressHash[i], 16) <= 7 && address[i].toLowerCase() !== address[i])
102
+ ) {
103
+ return false;
104
+ }
105
+ }
106
+ return true;
107
+ }
108
+
109
+ /**
110
+ * Converts an Ethereum address to its checksum format.
111
+ * The input 'address' should be prefixed with '0x' or not, and have exactly 40 hex characters.
112
+ * The checksum format is created by capitalizing certain characters in the hex string
113
+ * based on the hash of the lowercase address.
114
+ * Throws an error if the input address is invalid.
115
+ *
116
+ * @param address - The Ethereum address as a hex-encoded string.
117
+ * @returns The Ethereum address in its checksum format.
118
+ */
119
+ public static toChecksumAddress(address: string) {
120
+ if (!EthAddress.isAddress(address)) {
121
+ throw new Error('Invalid address string.');
122
+ }
123
+
124
+ address = address.toLowerCase().replace(/^0x/i, '');
125
+ const addressHash = keccak256String(address);
126
+ let checksumAddress = '0x';
127
+
128
+ for (let i = 0; i < address.length; i++) {
129
+ // If ith character is 9 to f then make it uppercase.
130
+ if (parseInt(addressHash[i], 16) > 7) {
131
+ checksumAddress += address[i].toUpperCase();
132
+ } else {
133
+ checksumAddress += address[i];
134
+ }
135
+ }
136
+ return checksumAddress;
137
+ }
138
+
139
+ /**
140
+ * Checks whether the given EthAddress instance is equal to the current instance.
141
+ * Equality is determined by comparing the underlying byte buffers of both instances.
142
+ *
143
+ * @param rhs - The EthAddress instance to compare with the current instance.
144
+ * @returns A boolean value indicating whether the two instances are equal (true) or not (false).
145
+ */
146
+ public equals(rhs: EthAddress) {
147
+ return this.buffer.equals(rhs.buffer);
148
+ }
149
+
150
+ /**
151
+ * Converts the Ethereum address to a hex-encoded string.
152
+ * The resulting string is prefixed with '0x' and has exactly 40 hex characters.
153
+ * This method can be used to represent the EthAddress instance in the widely used hexadecimal format.
154
+ *
155
+ * @returns A hex-encoded string representation of the Ethereum address.
156
+ */
157
+ public toString() {
158
+ return `0x${this.buffer.toString('hex')}` as `0x${string}`;
159
+ }
160
+
161
+ /**
162
+ * Returns the Ethereum address as a checksummed string.
163
+ * The output string will have characters in the correct upper or lowercase form, according to EIP-55.
164
+ * This provides a way to verify if an address is typed correctly, by checking the character casing.
165
+ *
166
+ * @returns A checksummed Ethereum address string.
167
+ */
168
+ public toChecksumString() {
169
+ return EthAddress.toChecksumAddress(this.buffer.toString('hex'));
170
+ }
171
+
172
+ /**
173
+ * Returns a 20-byte buffer representation of the Ethereum address.
174
+ * @returns A 20-byte Buffer containing the Ethereum address.
175
+ */
176
+ public toBuffer() {
177
+ return this.buffer;
178
+ }
179
+
180
+ /**
181
+ * Returns a 32-byte buffer representation of the Ethereum address, with the original 20-byte address
182
+ * occupying the last 20 bytes and the first 12 bytes being zero-filled.
183
+ * This format is commonly used in smart contracts when handling addresses as 32-byte values.
184
+ *
185
+ * @returns A 32-byte Buffer containing the padded Ethereum address.
186
+ */
187
+ // TODO(#3938): nuke this
188
+ public toBuffer32() {
189
+ const buffer = Buffer.alloc(32);
190
+ this.buffer.copy(buffer, 12);
191
+ return buffer;
192
+ }
193
+
194
+ /**
195
+ * Returns a new field with the same contents as this EthAddress.
196
+ *
197
+ * @returns An Fr instance.
198
+ */
199
+ public toField() {
200
+ return Fr.fromBuffer(this.toBuffer32());
201
+ }
202
+
203
+ /**
204
+ * Converts a field to a eth address.
205
+ * @param fr - The field to convert.
206
+ * @returns The eth address.
207
+ */
208
+ static fromField(fr: Fr): EthAddress {
209
+ return new EthAddress(fr.toBuffer().slice(-EthAddress.SIZE_IN_BYTES));
210
+ }
211
+
212
+ static fromFields(fields: Fr[] | FieldReader) {
213
+ const reader = FieldReader.asReader(fields);
214
+ return EthAddress.fromField(reader.readField());
215
+ }
216
+
217
+ /**
218
+ * Deserializes from a buffer or reader, corresponding to a write in cpp.
219
+ * @param buffer - Buffer to read from.
220
+ * @returns The EthAddress.
221
+ */
222
+ static fromBuffer(buffer: Buffer | BufferReader): EthAddress {
223
+ const reader = BufferReader.asReader(buffer);
224
+ return new EthAddress(reader.readBytes(EthAddress.SIZE_IN_BYTES));
225
+ }
226
+
227
+ /**
228
+ * Friendly representation for debugging purposes.
229
+ * @returns A hex string representing the address.
230
+ */
231
+ toFriendlyJSON() {
232
+ return this.toString();
233
+ }
234
+ }
@@ -0,0 +1,104 @@
1
+ import { toBigIntBE } from '../bigint-buffer/index.js';
2
+ import { Tuple } from '../serialize/types.js';
3
+ import { Fr } from './fields.js';
4
+
5
+ /**
6
+ * Class to wrap a single point coordinate.
7
+ * This class handles the complexities of representing point coordinates as 32 byte buffers as well as fields.
8
+ * The coordinate value is split across 2 fields to ensure that the max size of a field is not breached.
9
+ * This is achieved by placing the most significant byte of the lower field into the least significant byte of the higher field.
10
+ * Calls to 'toBuffer' or 'toBigInt' undo this change and simply return the original 32 byte value.
11
+ * Calls to 'toFieldsBuffer' will return a 64 bytes buffer containing the serialized fields.
12
+ */
13
+ export class Coordinate {
14
+ static ZERO = new Coordinate([Fr.ZERO, Fr.ZERO]);
15
+
16
+ constructor(
17
+ /**
18
+ * The fields of the coordinate value. Least significant limb at index 0.
19
+ */
20
+ public fields: Tuple<Fr, 2>,
21
+ ) {}
22
+
23
+ /**
24
+ * Converts the coordinate data into a tuple of fields
25
+ * @returns A tuple of the coordinate fields
26
+ */
27
+ toFields(): Tuple<Fr, 2> {
28
+ return this.fields;
29
+ }
30
+
31
+ /**
32
+ * Generates a random coordinate value
33
+ * @returns The random coordinate
34
+ */
35
+ static random(): Coordinate {
36
+ return this.fromField(Fr.random());
37
+ }
38
+
39
+ /**
40
+ * serializes the object to buffer of 2 fields.
41
+ * @returns A buffer serialization of the object.
42
+ */
43
+ toFieldsBuffer(): Buffer {
44
+ return Buffer.concat([this.fields[0].toBuffer(), this.fields[1].toBuffer()]);
45
+ }
46
+
47
+ /**
48
+ * serializes the coordinate to a single 32 byte buffer.
49
+ * @returns A buffer serialization of the object.
50
+ */
51
+ toBuffer(): Buffer {
52
+ const buf0 = this.fields[0].toBuffer();
53
+ const buf1 = this.fields[1].toBuffer();
54
+ buf0[0] = buf1[31];
55
+ return buf0;
56
+ }
57
+
58
+ /**
59
+ * Returns true if this coordinate is equal to the one provided
60
+ * @param other - The coordinate against which to compare
61
+ * @returns True if the coordinates are the same, false otherwise
62
+ */
63
+ equals(other: Coordinate): boolean {
64
+ return this.toBigInt() === other.toBigInt();
65
+ }
66
+
67
+ /**
68
+ * Returns the coordinate's value as a bigint
69
+ * @returns The coordinate value as a bigint
70
+ */
71
+ toBigInt(): bigint {
72
+ return toBigIntBE(this.toBuffer());
73
+ }
74
+
75
+ /**
76
+ * Creates a coordinate object from a 32 byte coordinate value
77
+ * @param coordinate - A buffer containing the 32 byte coordinate value
78
+ * @returns The new coordinate object
79
+ */
80
+ static fromBuffer(coordinate: Buffer) {
81
+ if (coordinate.length != 32) {
82
+ throw new Error(`Invalid size of coordinate buffer`);
83
+ }
84
+ const buf0 = Buffer.alloc(32);
85
+ coordinate.copy(buf0, 0, 0, 32);
86
+ const buf1 = Buffer.alloc(32);
87
+ buf1[31] = buf0[0];
88
+ buf0[0] = 0;
89
+ return new Coordinate([Fr.fromBuffer(buf0), Fr.fromBuffer(buf1)]);
90
+ }
91
+
92
+ /**
93
+ * Creates a coordinate object from a field
94
+ * @param coordinate - The field containing the coordinate
95
+ * @returns The new coordinate object
96
+ */
97
+ static fromField(coordinate: Fr) {
98
+ const buf0 = coordinate.toBuffer();
99
+ const buf1 = Buffer.alloc(32);
100
+ buf1[31] = buf0[0];
101
+ buf0[0] = 0;
102
+ return new Coordinate([Fr.fromBuffer(buf0), Fr.fromBuffer(buf1)]);
103
+ }
104
+ }
@@ -0,0 +1,328 @@
1
+ import { toBigIntBE, toBufferBE } from '../bigint-buffer/index.js';
2
+ import { randomBytes } from '../crypto/random/index.js';
3
+ import { BufferReader } from '../serialize/buffer_reader.js';
4
+
5
+ const ZERO_BUFFER = Buffer.alloc(32);
6
+
7
+ /* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
8
+
9
+ /**
10
+ * Represents a field derived from BaseField.
11
+ */
12
+ type DerivedField<T extends BaseField> = {
13
+ new (value: any): T;
14
+ /**
15
+ * All derived fields will specify a MODULUS.
16
+ */
17
+ MODULUS: bigint;
18
+ };
19
+
20
+ /**
21
+ * Base field class.
22
+ * Conversions from Buffer to BigInt and vice-versa are not cheap.
23
+ * We allow construction with either form and lazily convert to other as needed.
24
+ * We only check we are within the field modulus when initializing with bigint.
25
+ * If NODE_ENV === 'test', we will always initialize both types to check the modulus.
26
+ * This is also necessary in test environment as a lot of tests just use deep equality to check equality.
27
+ * WARNING: This could lead to a bugs in production that don't reveal in tests, but it's low risk.
28
+ */
29
+ abstract class BaseField {
30
+ static SIZE_IN_BYTES = 32;
31
+ private asBuffer?: Buffer;
32
+ private asBigInt?: bigint;
33
+
34
+ /**
35
+ * Return bigint representation.
36
+ * @deprecated Just to get things compiling. Use toBigInt().
37
+ * */
38
+ get value(): bigint {
39
+ return this.toBigInt();
40
+ }
41
+
42
+ protected constructor(value: number | bigint | boolean | BaseField | Buffer) {
43
+ if (value instanceof Buffer) {
44
+ if (value.length > BaseField.SIZE_IN_BYTES) {
45
+ throw new Error(`Value length ${value.length} exceeds ${BaseField.SIZE_IN_BYTES}`);
46
+ }
47
+ this.asBuffer =
48
+ value.length === BaseField.SIZE_IN_BYTES
49
+ ? value
50
+ : Buffer.concat([Buffer.alloc(BaseField.SIZE_IN_BYTES - value.length), value]);
51
+ } else if (typeof value === 'bigint' || typeof value === 'number' || typeof value === 'boolean') {
52
+ this.asBigInt = BigInt(value);
53
+ if (this.asBigInt >= this.modulus()) {
54
+ throw new Error(`Value 0x${this.asBigInt.toString(16)} is greater or equal to field modulus.`);
55
+ }
56
+ } else if (value instanceof BaseField) {
57
+ this.asBuffer = value.asBuffer;
58
+ this.asBigInt = value.asBigInt;
59
+ } else {
60
+ throw new Error(`Type '${typeof value}' with value '${value}' passed to BaseField ctor.`);
61
+ }
62
+
63
+ // Loads of our tests are just doing deep equality rather than calling e.g. toBigInt() first.
64
+ // This ensures the deep equality passes regardless of the internal representation.
65
+ // It also ensures the value range is checked even when initializing as a buffer.
66
+ if (process.env.NODE_ENV === 'test') {
67
+ this.toBuffer();
68
+ this.toBigInt();
69
+ }
70
+ }
71
+
72
+ protected abstract modulus(): bigint;
73
+
74
+ /**
75
+ * We return a copy of the Buffer to ensure this remains immutable.
76
+ */
77
+ toBuffer(): Buffer {
78
+ if (!this.asBuffer) {
79
+ this.asBuffer = toBufferBE(this.asBigInt!, 32);
80
+ }
81
+ return Buffer.from(this.asBuffer);
82
+ }
83
+
84
+ toString(): `0x${string}` {
85
+ return `0x${this.toBuffer().toString('hex')}`;
86
+ }
87
+
88
+ toBigInt(): bigint {
89
+ if (this.asBigInt === undefined) {
90
+ this.asBigInt = toBigIntBE(this.asBuffer!);
91
+ if (this.asBigInt >= this.modulus()) {
92
+ throw new Error(`Value 0x${this.asBigInt.toString(16)} is greater or equal to field modulus.`);
93
+ }
94
+ }
95
+ return this.asBigInt;
96
+ }
97
+
98
+ toBool(): boolean {
99
+ return Boolean(this.toBigInt());
100
+ }
101
+
102
+ toNumber(): number {
103
+ const value = this.toBigInt();
104
+ if (value > Number.MAX_SAFE_INTEGER) {
105
+ throw new Error(`Value ${value.toString(16)} greater than than max safe integer`);
106
+ }
107
+ return Number(value);
108
+ }
109
+
110
+ toShortString(): string {
111
+ const str = this.toString();
112
+ return `${str.slice(0, 10)}...${str.slice(-4)}`;
113
+ }
114
+
115
+ equals(rhs: BaseField): boolean {
116
+ return this.toBuffer().equals(rhs.toBuffer());
117
+ }
118
+
119
+ lt(rhs: BaseField): boolean {
120
+ return this.toBigInt() < rhs.toBigInt();
121
+ }
122
+
123
+ isZero(): boolean {
124
+ return this.toBuffer().equals(ZERO_BUFFER);
125
+ }
126
+
127
+ toFriendlyJSON(): string {
128
+ return this.toString();
129
+ }
130
+
131
+ toField() {
132
+ return this;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Constructs a field from a Buffer of BufferReader.
138
+ * It maybe not read the full 32 bytes if the Buffer is shorter, but it will padded in BaseField constructor.
139
+ */
140
+ function fromBuffer<T extends BaseField>(buffer: Buffer | BufferReader, f: DerivedField<T>) {
141
+ const reader = BufferReader.asReader(buffer);
142
+ return new f(reader.readBytes(BaseField.SIZE_IN_BYTES));
143
+ }
144
+
145
+ /**
146
+ * Constructs a field from a Buffer, but reduces it first.
147
+ * This requires a conversion to a bigint first so the initial underlying representation will be a bigint.
148
+ */
149
+ function fromBufferReduce<T extends BaseField>(buffer: Buffer, f: DerivedField<T>) {
150
+ return new f(toBigIntBE(buffer) % f.MODULUS);
151
+ }
152
+
153
+ /**
154
+ * To ensure a field is uniformly random, it's important to reduce a 512 bit value.
155
+ * If you reduced a 256 bit number, there would a be a high skew in the lower range of the field.
156
+ */
157
+ function random<T extends BaseField>(f: DerivedField<T>): T {
158
+ return fromBufferReduce(randomBytes(64), f);
159
+ }
160
+
161
+ /**
162
+ * Constructs a field from a 0x prefixed hex string.
163
+ */
164
+ function fromString<T extends BaseField>(buf: string, f: DerivedField<T>) {
165
+ const buffer = Buffer.from(buf.replace(/^0x/i, ''), 'hex');
166
+ return new f(buffer);
167
+ }
168
+
169
+ /**
170
+ * Branding to ensure fields are not interchangeable types.
171
+ */
172
+ export interface Fr {
173
+ /** Brand. */
174
+ _branding: 'Fr';
175
+ }
176
+
177
+ /**
178
+ * Fr field class.
179
+ */
180
+ export class Fr extends BaseField {
181
+ static ZERO = new Fr(0n);
182
+ static MODULUS = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001n;
183
+
184
+ constructor(value: number | bigint | boolean | Fr | Buffer) {
185
+ super(value);
186
+ }
187
+
188
+ protected modulus() {
189
+ return Fr.MODULUS;
190
+ }
191
+
192
+ static random() {
193
+ return random(Fr);
194
+ }
195
+
196
+ static zero() {
197
+ return Fr.ZERO;
198
+ }
199
+
200
+ static fromBuffer(buffer: Buffer | BufferReader) {
201
+ return fromBuffer(buffer, Fr);
202
+ }
203
+
204
+ static fromBufferReduce(buffer: Buffer) {
205
+ return fromBufferReduce(buffer, Fr);
206
+ }
207
+
208
+ static fromString(buf: string) {
209
+ return fromString(buf, Fr);
210
+ }
211
+
212
+ /** Arithmetic */
213
+
214
+ add(rhs: Fr) {
215
+ return new Fr((this.toBigInt() + rhs.toBigInt()) % Fr.MODULUS);
216
+ }
217
+
218
+ sub(rhs: Fr) {
219
+ const result = this.toBigInt() - rhs.toBigInt();
220
+ return new Fr(result < 0 ? result + Fr.MODULUS : result);
221
+ }
222
+
223
+ mul(rhs: Fr) {
224
+ return new Fr((this.toBigInt() * rhs.toBigInt()) % Fr.MODULUS);
225
+ }
226
+
227
+ div(rhs: Fr) {
228
+ if (rhs.isZero()) {
229
+ throw new Error('Division by zero');
230
+ }
231
+
232
+ const bInv = modInverse(rhs.toBigInt());
233
+ return this.mul(bInv);
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Branding to ensure fields are not interchangeable types.
239
+ */
240
+ export interface Fq {
241
+ /** Brand. */
242
+ _branding: 'Fq';
243
+ }
244
+
245
+ /**
246
+ * Fq field class.
247
+ */
248
+ export class Fq extends BaseField {
249
+ static ZERO = new Fq(0n);
250
+ static MODULUS = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47n;
251
+ private static HIGH_SHIFT = BigInt((BaseField.SIZE_IN_BYTES / 2) * 8);
252
+ private static LOW_MASK = (1n << Fq.HIGH_SHIFT) - 1n;
253
+
254
+ get low(): Fr {
255
+ return new Fr(this.toBigInt() & Fq.LOW_MASK);
256
+ }
257
+
258
+ get high(): Fr {
259
+ return new Fr(this.toBigInt() >> Fq.HIGH_SHIFT);
260
+ }
261
+
262
+ constructor(value: number | bigint | boolean | Fq | Buffer) {
263
+ super(value);
264
+ }
265
+
266
+ protected modulus() {
267
+ return Fq.MODULUS;
268
+ }
269
+
270
+ static random() {
271
+ return random(Fq);
272
+ }
273
+
274
+ static zero() {
275
+ return Fq.ZERO;
276
+ }
277
+
278
+ static fromBuffer(buffer: Buffer | BufferReader) {
279
+ return fromBuffer(buffer, Fq);
280
+ }
281
+
282
+ static fromBufferReduce(buffer: Buffer) {
283
+ return fromBufferReduce(buffer, Fq);
284
+ }
285
+
286
+ static fromString(buf: string) {
287
+ return fromString(buf, Fq);
288
+ }
289
+
290
+ static fromHighLow(high: Fr, low: Fr): Fq {
291
+ return new Fq((high.toBigInt() << Fq.HIGH_SHIFT) + low.toBigInt());
292
+ }
293
+ }
294
+
295
+ // Beware: Performance bottleneck below
296
+
297
+ /**
298
+ * Find the modular inverse of a given element, for BN254 Fr.
299
+ */
300
+ function modInverse(b: bigint) {
301
+ const [gcd, x, _] = extendedEuclidean(b, Fr.MODULUS);
302
+ if (gcd != 1n) {
303
+ throw Error('Inverse does not exist');
304
+ }
305
+ // Add modulus if -ve to ensure positive
306
+ return new Fr(x > 0 ? x : x + Fr.MODULUS);
307
+ }
308
+
309
+ /**
310
+ * The extended Euclidean algorithm can be used to find the multiplicative inverse of a field element
311
+ * This is used to perform field division.
312
+ */
313
+ function extendedEuclidean(a: bigint, modulus: bigint): [bigint, bigint, bigint] {
314
+ if (a == 0n) {
315
+ return [modulus, 0n, 1n];
316
+ } else {
317
+ const [gcd, x, y] = extendedEuclidean(modulus % a, a);
318
+ return [gcd, y - (modulus / a) * x, x];
319
+ }
320
+ }
321
+
322
+ /**
323
+ * GrumpkinScalar is an Fq.
324
+ * @remarks Called GrumpkinScalar because it is used to represent elements in Grumpkin's scalar field as defined in
325
+ * the Aztec Yellow Paper.
326
+ */
327
+ export type GrumpkinScalar = Fq;
328
+ export const GrumpkinScalar = Fq;
@@ -0,0 +1,3 @@
1
+ export * from './fields.js';
2
+ export * from './point.js';
3
+ export * from './coordinate.js';