@arcium-hq/client 0.1.46 → 0.1.47

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/build/index.mjs CHANGED
@@ -1,14 +1,21 @@
1
1
  import { blake2s } from '@noble/hashes/blake2s';
2
- import { randomBytes, createHash, createCipheriv } from 'crypto';
2
+ import { randomBytes, createHash, createCipheriv, hkdfSync, createDecipheriv } from 'crypto';
3
3
  import { ed25519, x25519 } from '@noble/curves/ed25519';
4
4
  export { x25519 } from '@noble/curves/ed25519';
5
5
  import * as anchor from '@coral-xyz/anchor';
6
6
  import { Program } from '@coral-xyz/anchor';
7
- import { shake256 } from '@noble/hashes/sha3';
7
+ import { shake256, sha3_512 } from '@noble/hashes/sha3';
8
8
  import { invert } from '@noble/curves/abstract/modular';
9
+ import { randomBytes as randomBytes$1 } from '@noble/hashes/utils';
10
+ import { twistedEdwards } from '@noble/curves/abstract/edwards';
9
11
  import { PublicKey } from '@solana/web3.js';
10
12
 
11
- // Converts a bigint to an array of bits (least significant to most significant, in 2's complement representation).
13
+ /**
14
+ * Converts a bigint to an array of bits (least significant to most significant, in 2's complement representation).
15
+ * @param x - The bigint to convert.
16
+ * @param binSize - The number of bits to use in the representation.
17
+ * @returns An array of booleans representing the bits of x.
18
+ */
12
19
  function toBinLE(x, binSize) {
13
20
  const res = [];
14
21
  for (let i = 0; i < binSize; ++i) {
@@ -16,7 +23,11 @@ function toBinLE(x, binSize) {
16
23
  }
17
24
  return res;
18
25
  }
19
- // Converts an array of bits (least significant to most significant, in 2's complement representation) to a bigint.
26
+ /**
27
+ * Converts an array of bits (least significant to most significant, in 2's complement representation) to a bigint.
28
+ * @param xBin - The array of bits to convert.
29
+ * @returns The bigint represented by the bit array.
30
+ */
20
31
  function fromBinLE(xBin) {
21
32
  let res = 0n;
22
33
  for (let i = 0; i < xBin.length - 1; ++i) {
@@ -24,8 +35,14 @@ function fromBinLE(xBin) {
24
35
  }
25
36
  return res - (BigInt(xBin[xBin.length - 1]) << BigInt(xBin.length - 1));
26
37
  }
27
- // Binary adder between x and y (we assume that xBin and yBin are of same length,
28
- // and that the length is large enough to represent the sum of the two).
38
+ /**
39
+ * Binary adder between x and y (assumes xBin and yBin are of the same length and large enough to represent the sum).
40
+ * @param xBin - The first operand as a bit array.
41
+ * @param yBin - The second operand as a bit array.
42
+ * @param carryIn - The initial carry-in value.
43
+ * @param binSize - The number of bits to use in the operation.
44
+ * @returns The sum as a bit array.
45
+ */
29
46
  function adder(xBin, yBin, carryIn, binSize) {
30
47
  const res = [];
31
48
  let carry = carryIn;
@@ -40,12 +57,24 @@ function adder(xBin, yBin, carryIn, binSize) {
40
57
  }
41
58
  return res;
42
59
  }
43
- // Constant time addition.
60
+ /**
61
+ * Constant-time addition of two bigints, using 2's complement representation.
62
+ * @param x - The first operand.
63
+ * @param y - The second operand.
64
+ * @param binSize - The number of bits to use in the operation.
65
+ * @returns The sum as a bigint.
66
+ */
44
67
  function ctAdd(x, y, binSize) {
45
68
  const resBin = adder(toBinLE(x, binSize), toBinLE(y, binSize), false, binSize);
46
69
  return fromBinLE(resBin);
47
70
  }
48
- // Constant time subtraction.
71
+ /**
72
+ * Constant-time subtraction of two bigints, using 2's complement representation.
73
+ * @param x - The first operand.
74
+ * @param y - The second operand.
75
+ * @param binSize - The number of bits to use in the operation.
76
+ * @returns The difference as a bigint.
77
+ */
49
78
  function ctSub(x, y, binSize) {
50
79
  const yBin = toBinLE(y, binSize);
51
80
  const yBinNot = [];
@@ -55,23 +84,44 @@ function ctSub(x, y, binSize) {
55
84
  const resBin = adder(toBinLE(x, binSize), yBinNot, true, binSize);
56
85
  return fromBinLE(resBin);
57
86
  }
58
- // Constant time sign bit circuit.
87
+ /**
88
+ * Returns the sign bit of a bigint in constant time.
89
+ * @param x - The bigint to check.
90
+ * @param binSize - The bit position to check (typically the highest bit).
91
+ * @returns True if the sign bit is set, false otherwise.
92
+ */
59
93
  function ctSignBit(x, binSize) {
60
94
  return ((x >> binSize) & 1n) === 1n;
61
95
  }
62
- // Constant time less than circuit.
96
+ /**
97
+ * Constant-time less-than comparison for two bigints.
98
+ * @param x - The first operand.
99
+ * @param y - The second operand.
100
+ * @param binSize - The number of bits to use in the operation.
101
+ * @returns True if x < y, false otherwise.
102
+ */
63
103
  function ctLt(x, y, binSize) {
64
104
  return ctSignBit(ctSub(x, y, binSize), binSize);
65
105
  }
66
- // Constant time select.
106
+ /**
107
+ * Constant-time select between two bigints based on a boolean condition.
108
+ * @param b - The condition; if true, select x, otherwise select y.
109
+ * @param x - The value to select if b is true.
110
+ * @param y - The value to select if b is false.
111
+ * @param binSize - The number of bits to use in the operation.
112
+ * @returns The selected bigint.
113
+ */
67
114
  function ctSelect(b, x, y, binSize) {
68
115
  return ctAdd(y, BigInt(b) * (ctSub(x, y, binSize)), binSize);
69
116
  }
70
- // This function returns `true` if -2^binSize <= x < 2^binSize, and `false` otherwise.
71
- // The function is not constant-time for arbitrary x, but it is so for all inputs
72
- // for which the function returns `true`. If you assert your inputs to satisfy
73
- // verifyBinSize(x, binSize), then you need not care about the non constant-timeness
74
- // of this function.
117
+ /**
118
+ * Checks if a bigint fits in the range -2^binSize <= x < 2^binSize.
119
+ * Not constant-time for arbitrary x, but is constant-time for all inputs for which the function returns true.
120
+ * If you assert your inputs satisfy verifyBinSize(x, binSize), you need not care about the non constant-timeness of this function.
121
+ * @param x - The bigint to check.
122
+ * @param binSize - The number of bits to use in the check.
123
+ * @returns True if x fits in the range, false otherwise.
124
+ */
75
125
  function verifyBinSize(x, binSize) {
76
126
  const bin = (x >> binSize).toString(2);
77
127
  return bin === '0' || bin === '-1';
@@ -259,10 +309,17 @@ function randMatrix(field, nrows, ncols) {
259
309
  return new Matrix(field, data);
260
310
  }
261
311
 
312
+ /**
313
+ * Curve25519 base field as an IField instance.
314
+ */
262
315
  const CURVE25519_BASE_FIELD = ed25519.CURVE.Fp;
263
316
  // hardcode security level to 128 bits
264
317
  const SECURITY_LEVEL = 128;
265
318
  // We refer to https://tosc.iacr.org/index.php/ToSC/article/view/8695/8287 for more details.
319
+ /**
320
+ * Description and parameters for the Rescue cipher or hash function, including round constants, MDS matrix, and key schedule.
321
+ * See: https://tosc.iacr.org/index.php/ToSC/article/view/8695/8287
322
+ */
266
323
  class RescueDesc {
267
324
  mode;
268
325
  field;
@@ -278,6 +335,12 @@ class RescueDesc {
278
335
  mdsMatInverse;
279
336
  // The round keys, needed for encryption and decryption.
280
337
  roundKeys;
338
+ /**
339
+ * Constructs a RescueDesc for a given field and mode (cipher or hash).
340
+ * Initializes round constants, MDS matrix, and key schedule.
341
+ * @param field - The field to use (e.g., CURVE25519_BASE_FIELD).
342
+ * @param mode - The mode: block cipher or hash function.
343
+ */
281
344
  constructor(field, mode) {
282
345
  this.field = field;
283
346
  this.mode = mode;
@@ -323,6 +386,11 @@ class RescueDesc {
323
386
  }
324
387
  }
325
388
  }
389
+ /**
390
+ * Samples round constants for the Rescue permutation, using SHAKE256.
391
+ * @param nRounds - The number of rounds.
392
+ * @returns An array of round constant matrices.
393
+ */
326
394
  sampleConstants(nRounds) {
327
395
  const field = this.field;
328
396
  const m = this.m;
@@ -396,9 +464,19 @@ class RescueDesc {
396
464
  default: return [];
397
465
  }
398
466
  }
467
+ /**
468
+ * Applies the Rescue permutation to a state matrix.
469
+ * @param state - The input state matrix.
470
+ * @returns The permuted state matrix.
471
+ */
399
472
  permute(state) {
400
473
  return rescuePermutation(this.mode, this.alpha, this.alphaInverse, this.mdsMat, this.roundKeys, state)[2 * this.nRounds];
401
474
  }
475
+ /**
476
+ * Applies the inverse Rescue permutation to a state matrix.
477
+ * @param state - The input state matrix.
478
+ * @returns The inverse-permuted state matrix.
479
+ */
402
480
  permuteInverse(state) {
403
481
  return rescuePermutationInverse(this.mode, this.alpha, this.alphaInverse, this.mdsMatInverse, this.roundKeys, state)[2 * this.nRounds];
404
482
  }
@@ -570,7 +648,17 @@ function toVec(data) {
570
648
  return dataVec;
571
649
  }
572
650
 
651
+ /**
652
+ * Number of mantissa bits for double-precision floating point values.
653
+ */
573
654
  const DOUBLE_PRECISION_MANTISSA = 52;
655
+ /**
656
+ * Encodes a value as a bigint suitable for Rescue encryption, handling booleans, bigints, and numbers.
657
+ * The encoding is performed in constant-time to avoid leaking information through timing side-channels.
658
+ * Throws if the value is out of the supported range for the field.
659
+ * @param v - The value to encode (MScalar, MFloat, or MBoolean).
660
+ * @returns The encoded value as a bigint.
661
+ */
574
662
  function encodeAsRescueEncryptable(v) {
575
663
  if (typeof v === 'boolean') {
576
664
  return v ? 1n : 0n;
@@ -599,6 +687,13 @@ function encodeAsRescueEncryptable(v) {
599
687
  // but typescript kept thinking ixInput: readonly null[] and I can't figure out why, so we do this hack
600
688
  // for now.
601
689
  // TODO: Revisit and fix the types correctly.
690
+ /**
691
+ * Secret-shares the inputs for a confidential instruction, encoding each value as needed and splitting it for each node's public key.
692
+ * @param ixInput - The array of input values to secret-share.
693
+ * @param nodeX25519Keys - The array of node X25519 public keys to share with.
694
+ * @returns A 2D array of SecretShare objects, one array per input value.
695
+ * @throws Error if an input type cannot be parsed.
696
+ */
602
697
  function secretShareInputs(ixInput, nodeX25519Keys) {
603
698
  const shares = [];
604
699
  // Need to explicitly tell typescript input can be any of these, else it only thinks {} is possible
@@ -650,9 +745,16 @@ function getBinSize(max) {
650
745
  return BigInt(Math.floor(Math.log2(Number(max)))) + 3n;
651
746
  }
652
747
 
653
- // Scalar field prime modulus 2^252 + 27742317777372353535851937790883648493
748
+ /**
749
+ * Scalar field prime modulus for Curve25519: 2^252 + 27742317777372353535851937790883648493
750
+ */
654
751
  const CURVE25519_SCALAR_FIELD_MODULUS = ed25519.CURVE.n;
655
- // High level function for encrypting a value into the format the da layer expects
752
+ /**
753
+ * Encrypts a value into the format expected by the DA layer, using secret sharing and encryption for each node's public key.
754
+ * @param val - The value to secret-share and encrypt.
755
+ * @param nodeX25519Keys - The array of node X25519 public keys.
756
+ * @returns An array of SecretShare objects, one for each node.
757
+ */
656
758
  function secretShareValue(val, nodeX25519Keys) {
657
759
  const rawShares = genRawShares(val, nodeX25519Keys.length, CURVE25519_SCALAR_FIELD_MODULUS);
658
760
  return zip(rawShares, nodeX25519Keys).map(([share, key]) => encryptForDA(key, share, CURVE25519_SCALAR_FIELD_MODULUS));
@@ -671,10 +773,10 @@ function newSecretShare(ciphertext, nonce, ephemeralPublicKey) {
671
773
  }
672
774
  /**
673
775
  * Generates secret shares for a given value in the Curve25519 field.
674
- * @param secret The secret value to be shared (as a BigInt)
675
- * @param n The number of shares to generate
676
- * @param mod The modulo of the field over which to generate shares
677
- * @returns An array of n secret shares
776
+ * @param secret - The secret value to be shared (as a BigInt).
777
+ * @param n - The number of shares to generate.
778
+ * @param mod - The modulo of the field over which to generate shares (default: CURVE25519_SCALAR_FIELD_MODULUS).
779
+ * @returns An array of n secret shares as bigints.
678
780
  */
679
781
  function genRawShares(secret, n, mod = CURVE25519_SCALAR_FIELD_MODULUS) {
680
782
  const shares = [];
@@ -690,11 +792,11 @@ function genRawShares(secret, n, mod = CURVE25519_SCALAR_FIELD_MODULUS) {
690
792
  }
691
793
  /// ENCRYPTION
692
794
  /**
693
- * Encrypts a field element for the DA layer.
694
- * @param publicKey The recipient's x25519 public key
695
- * @param valueToEncrypt The bigint value to encrypt
696
- * @param modulo Bound on the value
697
- * @returns An object containing the ciphertext and ephemeral public key. Always pads to 32 bytes.
795
+ * Encrypts a field element for the DA layer using the recipient's x25519 public key.
796
+ * @param publicKey - The recipient's x25519 public key.
797
+ * @param valueToEncrypt - The bigint value to encrypt.
798
+ * @param modulo - Bound on the value (default: CURVE25519_SCALAR_FIELD_MODULUS).
799
+ * @returns An object containing the ciphertext, nonce, and ephemeral public key.
698
800
  */
699
801
  function encryptForDA(publicKey, valueToEncrypt, modulo = CURVE25519_SCALAR_FIELD_MODULUS) {
700
802
  // Check if the value to encrypt is smaller than the modulo
@@ -710,6 +812,12 @@ function encryptForDA(publicKey, valueToEncrypt, modulo = CURVE25519_SCALAR_FIEL
710
812
  const { ciphertext, nonce } = aesCtrEncrypt(valueToEncrypt, sharedSecret);
711
813
  return newSecretShare(ciphertext, nonce, ephemeralPublicKey);
712
814
  }
815
+ /**
816
+ * Computes a shared encryption key using ECDH (x25519) and hashes it with blake2s.
817
+ * @param privKey - The private key as a Uint8Array.
818
+ * @param pubKey - The public key as a Uint8Array.
819
+ * @returns The derived encryption key as a Uint8Array.
820
+ */
713
821
  function getEncryptionKey(privKey, pubKey) {
714
822
  const sharedSecret = x25519.getSharedSecret(privKey, pubKey);
715
823
  return blake2s(sharedSecret);
@@ -743,9 +851,10 @@ function aesCtrEncrypt(val, key) {
743
851
  }
744
852
  /// HELPERS
745
853
  /**
746
- * Generates a random val within the field bound by q.
854
+ * Generates a random value within the field bound by q.
855
+ * @param q - The upper bound (exclusive) for the random value.
747
856
  * @returns A random bigint value between 0 and q-1.
748
- */
857
+ */
749
858
  function generateRandomFieldElem(q) {
750
859
  const byteLength = (q.toString(2).length + 7) >> 3;
751
860
  let r;
@@ -755,10 +864,22 @@ function generateRandomFieldElem(q) {
755
864
  } while (r >= q);
756
865
  return r;
757
866
  }
758
- // Helper function for positive modulo
867
+ /**
868
+ * Computes the positive modulo of a over m.
869
+ * @param a - The dividend.
870
+ * @param m - The modulus.
871
+ * @returns The positive remainder of a mod m.
872
+ */
759
873
  function positiveModulo(a, m) {
760
874
  return ((a % m) + m) % m;
761
875
  }
876
+ /**
877
+ * Serializes a bigint to a little-endian Uint8Array of the specified length.
878
+ * @param val - The bigint value to serialize.
879
+ * @param lengthInBytes - The desired length of the output array.
880
+ * @returns The serialized value as a Uint8Array.
881
+ * @throws Error if the value is too large for the specified length.
882
+ */
762
883
  function serializeLE(val, lengthInBytes) {
763
884
  const result = new Uint8Array(lengthInBytes);
764
885
  let tempVal = val;
@@ -771,6 +892,11 @@ function serializeLE(val, lengthInBytes) {
771
892
  }
772
893
  return result;
773
894
  }
895
+ /**
896
+ * Deserializes a little-endian Uint8Array to a bigint.
897
+ * @param bytes - The Uint8Array to deserialize.
898
+ * @returns The deserialized bigint value.
899
+ */
774
900
  function deserializeLE(bytes) {
775
901
  let result = BigInt(0);
776
902
  for (let i = 0; i < bytes.length; i++) {
@@ -779,6 +905,11 @@ function deserializeLE(bytes) {
779
905
  return result;
780
906
  }
781
907
  // GENERAL
908
+ /**
909
+ * Computes the SHA-256 hash of an array of Uint8Arrays.
910
+ * @param byteArrays - The arrays to hash.
911
+ * @returns The SHA-256 hash as a Buffer.
912
+ */
782
913
  function sha256(byteArrays) {
783
914
  const hash = createHash('sha256');
784
915
  byteArrays.forEach((byteArray) => {
@@ -787,19 +918,28 @@ function sha256(byteArrays) {
787
918
  return hash.digest();
788
919
  }
789
920
 
790
- /// The Rescue-Prime hash funtion, see https://eprint.iacr.org/2020/1143.pdf.
791
- /// We use it with fixed m = 6 and capacity = 1, hence rate = 5. According to Section 2.2, this
792
- /// offers log2(CURVE25519_BASE_FIELD.ORDER) / 2 bits of security against collision, preimage and
793
- /// second-preimage attacks.
921
+ /**
922
+ * The Rescue-Prime hash function, as described in https://eprint.iacr.org/2020/1143.pdf.
923
+ * Used with fixed m = 6 and capacity = 1 (rate = 5). According to Section 2.2, this offers log2(CURVE25519_BASE_FIELD.ORDER) / 2 bits of security against collision, preimage, and second-preimage attacks.
924
+ * See the referenced paper for further details.
925
+ */
794
926
  class RescuePrimeHash {
795
927
  desc;
796
928
  rate;
929
+ /**
930
+ * Constructs a RescuePrimeHash instance with m = 6 and capacity = 1.
931
+ */
797
932
  constructor() {
798
933
  this.desc = new RescueDesc(CURVE25519_BASE_FIELD, { kind: 'hash', m: 6, capacity: 1 });
799
934
  this.rate = 6 - 1;
800
935
  }
801
936
  // This is Algorithm 1 from https://eprint.iacr.org/2020/1143.pdf, though with the padding (see Algorithm 2).
802
937
  // The hash function outputs this.rate elements.
938
+ /**
939
+ * Computes the Rescue-Prime hash of a message, with padding as described in Algorithm 2 of the paper.
940
+ * @param message - The input message as an array of bigints.
941
+ * @returns The hash output as an array of bigints (length = rate).
942
+ */
803
943
  digest(message) {
804
944
  message.push(1n);
805
945
  while (message.length % this.rate !== 0) {
@@ -829,21 +969,33 @@ class RescuePrimeHash {
829
969
  }
830
970
  }
831
971
 
832
- /// The HMAC-Rescue-Prime function. Since Rescue-Prime is based on the sponge construction,
833
- /// the traditional HMAC can be replaced by the simpler MAC, see e.g.
834
- /// https://keccak.team/files/SpongeFunctions.pdf (Appendix B) or
835
- /// https://keccak.team/keccak_strengths.html.
972
+ /**
973
+ * HMACRescuePrime provides a message authentication code (MAC) using the Rescue-Prime hash function.
974
+ * Rescue-Prime is based on the sponge construction, which allows the use of a simpler MAC in place of the traditional HMAC.
975
+ * For more details and explanations, see: https://keccak.team/files/SpongeFunctions.pdf (Appendix B) or https://keccak.team/keccak_strengths.html.
976
+ */
836
977
  class HMACRescuePrime {
837
978
  hasher;
979
+ /**
980
+ * Constructs a new HMACRescuePrime instance.
981
+ */
838
982
  constructor() {
839
983
  this.hasher = new RescuePrimeHash();
840
984
  }
985
+ /**
986
+ * Computes the HMAC (or MAC) digest of a message with a given key using Rescue-Prime.
987
+ * The key is padded to the hash function's rate, then concatenated with the message.
988
+ * @param key - The key as an array of bigints.
989
+ * @param message - The message as an array of bigints.
990
+ * @returns The MAC digest as an array of bigints.
991
+ * @throws Error if the key is longer than the hash function's rate.
992
+ */
841
993
  digest(key, message) {
842
994
  // HMAC-digest(key, message) = hasher.digest(key || message), since Rescue-Prime is based on
843
995
  // the sponge construction.
844
996
  // We follow https://datatracker.ietf.org/doc/html/rfc2104, though since Rescue-Prime is not based
845
997
  // on the Merkle-Damgard construction we cannot have an exact anology between the
846
- // parameters. For our purpose, we set B = L = hasher.rate().
998
+ // parameters. For our purpose, we set B = L = hasher.rate.
847
999
  if (key.length > this.hasher.rate) {
848
1000
  throw Error(`length of key is supposed to be at most the hash function's rate (found ${key.length} and ${this.hasher.rate})`);
849
1001
  }
@@ -856,39 +1008,82 @@ class HMACRescuePrime {
856
1008
  }
857
1009
  }
858
1010
 
859
- /// The HMAC-Rescue-Prime function. Since Rescue-Prime is based on the sponge construction,
860
- /// the traditional HMAC can be replaced by the simpler MAC, see e.g.
861
- /// https://keccak.team/files/SpongeFunctions.pdf (Appendix B) or
862
- /// https://keccak.team/keccak_strengths.html.
1011
+ /**
1012
+ * HKDF (HMAC-based Extract-and-Expand Key Derivation Function) using the Rescue-Prime hash function.
1013
+ * Follows RFC 5869. Only supports L = HashLen.
1014
+ */
863
1015
  class HKDFRescuePrime {
864
1016
  hmac;
1017
+ /**
1018
+ * Constructs a new HKDFRescuePrime instance.
1019
+ */
865
1020
  constructor() {
866
1021
  this.hmac = new HMACRescuePrime();
867
1022
  }
1023
+ /**
1024
+ * HKDF-Extract step: derives a pseudorandom key (PRK) from the input keying material (IKM) and salt.
1025
+ * @param salt - The salt value as an array of bigints.
1026
+ * @param ikm - The input keying material as an array of bigints.
1027
+ * @returns The pseudorandom key (PRK) as an array of bigints.
1028
+ */
868
1029
  extract(salt, ikm) {
1030
+ if (salt.length === 0) {
1031
+ // HashLen = hasher.rate for Rescue-Prime
1032
+ for (let i = 0; i < this.hmac.hasher.rate; ++i) {
1033
+ salt.push(0n);
1034
+ }
1035
+ }
869
1036
  return this.hmac.digest(salt, ikm);
870
1037
  }
1038
+ /**
1039
+ * HKDF-Expand step: expands the pseudorandom key (PRK) with info to produce output keying material (OKM).
1040
+ * Only supports L = HashLen = 5, i.e. N = 1.
1041
+ * @param prk - The pseudorandom key as an array of bigints.
1042
+ * @param info - The context and application specific information as an array of bigints.
1043
+ * @returns The output keying material (OKM) as an array of bigints.
1044
+ */
871
1045
  expand(prk, info) {
872
- // we go with L = HashLen = 5, i.e. N = 1
1046
+ // we only support L = HashLen = 5, i.e. N = 1
1047
+ // message = empty string | info | 0x01
873
1048
  info.push(1n);
874
1049
  return this.hmac.digest(prk, info);
875
1050
  }
1051
+ /**
1052
+ * Performs the full HKDF (extract and expand) to derive output keying material (OKM).
1053
+ * @param salt - The salt value as an array of bigints.
1054
+ * @param ikm - The input keying material as an array of bigints.
1055
+ * @param info - The context and application specific information as an array of bigints.
1056
+ * @returns The output keying material (OKM) as an array of bigints.
1057
+ */
876
1058
  okm(salt, ikm, info) {
877
1059
  const prk = this.extract(salt, ikm);
878
1060
  return this.expand(prk, info);
879
1061
  }
880
1062
  }
881
1063
 
882
- /// The Rescue cipher, see https://tosc.iacr.org/index.php/ToSC/article/view/8695/8287.
883
- /// We use it in Counter (CTR) mode, with a fixed m = 5.
1064
+ /**
1065
+ * The Rescue cipher in Counter (CTR) mode, with a fixed block size m = 5.
1066
+ * See: https://tosc.iacr.org/index.php/ToSC/article/view/8695/8287
1067
+ */
884
1068
  class RescueCipher {
885
1069
  desc;
1070
+ /**
1071
+ * Constructs a RescueCipher instance using a shared secret.
1072
+ * The key is derived using HKDF-RescuePrime and used to initialize the RescueDesc.
1073
+ * @param sharedSecret - The shared secret to derive the cipher key from.
1074
+ */
886
1075
  constructor(sharedSecret) {
887
1076
  const hkdf = new HKDFRescuePrime();
888
- const rescueKey = hkdf.okm([0n, 0n, 0n, 0n, 0n], [deserializeLE(sharedSecret)], [0n]);
1077
+ const rescueKey = hkdf.okm([], [deserializeLE(sharedSecret)], []);
889
1078
  this.desc = new RescueDesc(CURVE25519_BASE_FIELD, { kind: 'cipher', key: rescueKey });
890
1079
  }
891
- /// Encrypt the plaintext vector in Counter (CTR) mode.
1080
+ /**
1081
+ * Encrypts the plaintext vector in Counter (CTR) mode (raw, returns bigints).
1082
+ * @param plaintext - The array of plaintext bigints to encrypt.
1083
+ * @param nonce - A 16-byte nonce for CTR mode.
1084
+ * @returns The ciphertext as an array of bigints.
1085
+ * @throws Error if the nonce is not 16 bytes long.
1086
+ */
892
1087
  encrypt_raw(plaintext, nonce) {
893
1088
  if (nonce.length !== 16) {
894
1089
  throw Error(`nonce must be of length 16 (found ${nonce.length})`);
@@ -921,11 +1116,22 @@ class RescueCipher {
921
1116
  }
922
1117
  return ciphertext;
923
1118
  }
924
- /// Encrypt the plaintext vector in Counter (CTR) mode and serialize.
1119
+ /**
1120
+ * Encrypts the plaintext vector in Counter (CTR) mode and serializes each block.
1121
+ * @param plaintext - The array of plaintext bigints to encrypt.
1122
+ * @param nonce - A 16-byte nonce for CTR mode.
1123
+ * @returns The ciphertext as an array of arrays of numbers (each 32 bytes).
1124
+ */
925
1125
  encrypt(plaintext, nonce) {
926
1126
  return this.encrypt_raw(plaintext, nonce).map((c) => Array.from(serializeLE(c, 32)));
927
1127
  }
928
- /// Decrypt the ciphertext vector in Counter (CTR) mode.
1128
+ /**
1129
+ * Decrypts the ciphertext vector in Counter (CTR) mode (raw, expects bigints).
1130
+ * @param ciphertext - The array of ciphertext bigints to decrypt.
1131
+ * @param nonce - A 16-byte nonce for CTR mode.
1132
+ * @returns The decrypted plaintext as an array of bigints.
1133
+ * @throws Error if the nonce is not 16 bytes long.
1134
+ */
929
1135
  decrypt_raw(ciphertext, nonce) {
930
1136
  if (nonce.length !== 16) {
931
1137
  throw Error(`nonce must be of length 16 (found ${nonce.length})`);
@@ -955,7 +1161,12 @@ class RescueCipher {
955
1161
  }
956
1162
  return decrypted;
957
1163
  }
958
- /// Deserialize and decrypt the ciphertext vector in Counter (CTR) mode
1164
+ /**
1165
+ * Deserializes and decrypts the ciphertext vector in Counter (CTR) mode.
1166
+ * @param ciphertext - The array of arrays of numbers (each 32 bytes) to decrypt.
1167
+ * @param nonce - A 16-byte nonce for CTR mode.
1168
+ * @returns The decrypted plaintext as an array of bigints.
1169
+ */
959
1170
  decrypt(ciphertext, nonce) {
960
1171
  return this.decrypt_raw(ciphertext.map((c) => {
961
1172
  if (c.length !== 32) {
@@ -965,6 +1176,12 @@ class RescueCipher {
965
1176
  }), nonce);
966
1177
  }
967
1178
  }
1179
+ /**
1180
+ * Generates the counter values for Rescue cipher CTR mode.
1181
+ * @param nonce - The initial nonce as a bigint.
1182
+ * @param nBlocks - The number of blocks to generate counters for.
1183
+ * @returns An array of counter values as bigints.
1184
+ */
968
1185
  function getCounter(nonce, nBlocks) {
969
1186
  const counter = [];
970
1187
  for (let i = 0n; i < nBlocks; ++i) {
@@ -977,10 +1194,203 @@ function getCounter(nonce, nBlocks) {
977
1194
  return counter;
978
1195
  }
979
1196
 
1197
+ // The arcisEd25519 signature scheme. This is essentially ed25519 but we use the hash function
1198
+ // SHA3-512 instead of SHA-512 since its multiplicative depth is much lower, which
1199
+ // makes it much better suited to be evaluated in MPC.
1200
+ // Those are the parameters specified [here](https://datatracker.ietf.org/doc/html/rfc8032#section-5.1)
1201
+ // (except for the hash function, see above). The below is copied from [here](https://github.com/paulmillr/noble-curves/blob/main/src/ed25519.ts#L111).
1202
+ const arcisEd25519Defaults = (() => ({
1203
+ a: BigInt(-1),
1204
+ d: BigInt('37095705934669439343138083508754565189542113879843219016388785533085940283555'),
1205
+ Fp: ed25519.CURVE.Fp,
1206
+ n: BigInt('7237005577332262213973186563042994240857116359379907606001950938285454250989'),
1207
+ h: BigInt(8),
1208
+ Gx: BigInt('15112221349535400772501151409588531511454012693041857206046113283949847762202'),
1209
+ Gy: BigInt('46316835694926478169428394003475163141307993866256225615783033603165251855960'),
1210
+ hash: sha3_512,
1211
+ randomBytes: randomBytes$1,
1212
+ adjustScalarBytes,
1213
+ uvRatio,
1214
+ }))();
1215
+ /**
1216
+ * Clamps a 32-byte scalar as required by the Ed25519 signature scheme.
1217
+ * See: https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.5
1218
+ * @param bytes - The 32-byte scalar to clamp.
1219
+ * @returns The clamped scalar as a Uint8Array.
1220
+ */
1221
+ function adjustScalarBytes(bytes) {
1222
+ const clamped = bytes;
1223
+ clamped[0] &= 248;
1224
+ clamped[31] &= 127;
1225
+ clamped[31] |= 64;
1226
+ return clamped;
1227
+ }
1228
+ /**
1229
+ * Dummy function for compatibility; not used in the ArcisEd25519 signature scheme.
1230
+ * Always returns { isValid: true, value: 0n }.
1231
+ * @returns An object with isValid: true and value: 0n.
1232
+ */
1233
+ function uvRatio() {
1234
+ return { isValid: true, value: 0n };
1235
+ }
1236
+ /**
1237
+ * Ed25519 curve instance using SHA3-512 for hashing, suitable for MPC (ArcisEd25519 signature scheme).
1238
+ * This is essentially Ed25519 but with SHA3-512 instead of SHA-512 for lower multiplicative depth.
1239
+ * See: https://datatracker.ietf.org/doc/html/rfc8032#section-5.1
1240
+ */
1241
+ const arcisEd25519 = (() => twistedEdwards(arcisEd25519Defaults))();
1242
+
1243
+ /**
1244
+ * AES-128 cipher in Counter (CTR) mode, using HKDF-SHA3-256 to derive the key from a shared secret.
1245
+ * See: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf (Section 6.5) for details on CTR mode.
1246
+ */
1247
+ class Aes128Cipher {
1248
+ key;
1249
+ /**
1250
+ * Constructs an AES-128 cipher instance using a shared secret.
1251
+ * The key is derived using HKDF-SHA3-256.
1252
+ * @param sharedSecret - The shared secret to derive the AES key from.
1253
+ */
1254
+ constructor(sharedSecret) {
1255
+ const aesKey = hkdfSync('sha3-256', sharedSecret, new Uint8Array(), new Uint8Array(), 16);
1256
+ this.key = new Uint8Array(aesKey);
1257
+ }
1258
+ /**
1259
+ * Encrypts the plaintext array in Counter (CTR) mode.
1260
+ * @param plaintext - The data to encrypt.
1261
+ * @param nonce - An 8-byte nonce for CTR mode.
1262
+ * @returns The encrypted ciphertext as a Uint8Array.
1263
+ * @throws Error if the nonce is not 8 bytes long.
1264
+ */
1265
+ encrypt(plaintext, nonce) {
1266
+ if (nonce.length !== 8) {
1267
+ throw Error(`nonce must be of length 8 (found ${nonce.length})`);
1268
+ }
1269
+ const paddedNonce = Buffer.concat([nonce, Buffer.alloc(16 - nonce.length, 0)]);
1270
+ const cipher = createCipheriv('aes-128-ctr', this.key, paddedNonce);
1271
+ const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
1272
+ return new Uint8Array(ciphertext);
1273
+ }
1274
+ /**
1275
+ * Decrypts the ciphertext array in Counter (CTR) mode.
1276
+ * @param ciphertext - The data to decrypt.
1277
+ * @param nonce - An 8-byte nonce for CTR mode.
1278
+ * @returns The decrypted plaintext as a Uint8Array.
1279
+ * @throws Error if the nonce is not 8 bytes long.
1280
+ */
1281
+ decrypt(ciphertext, nonce) {
1282
+ if (nonce.length !== 8) {
1283
+ throw Error(`nonce must be of length 8 (found ${nonce.length})`);
1284
+ }
1285
+ const paddedNonce = Buffer.concat([nonce, Buffer.alloc(16 - nonce.length, 0)]);
1286
+ const cipher = createDecipheriv('aes-128-ctr', this.key, paddedNonce);
1287
+ const decrypted = Buffer.concat([cipher.update(ciphertext), cipher.final()]);
1288
+ return new Uint8Array(decrypted);
1289
+ }
1290
+ }
1291
+
1292
+ /**
1293
+ * AES-192 cipher in Counter (CTR) mode, using HKDF-SHA3-256 to derive the key from a shared secret.
1294
+ * See: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf (Section 6.5) for details on CTR mode.
1295
+ */
1296
+ class Aes192Cipher {
1297
+ key;
1298
+ /**
1299
+ * Constructs an AES-192 cipher instance using a shared secret.
1300
+ * The key is derived using HKDF-SHA3-256.
1301
+ * @param sharedSecret - The shared secret to derive the AES key from.
1302
+ */
1303
+ constructor(sharedSecret) {
1304
+ const aesKey = hkdfSync('sha3-256', sharedSecret, new Uint8Array(), new Uint8Array(), 24);
1305
+ this.key = new Uint8Array(aesKey);
1306
+ }
1307
+ /**
1308
+ * Encrypts the plaintext array in Counter (CTR) mode.
1309
+ * @param plaintext - The data to encrypt.
1310
+ * @param nonce - An 8-byte nonce for CTR mode.
1311
+ * @returns The encrypted ciphertext as a Uint8Array.
1312
+ * @throws Error if the nonce is not 8 bytes long.
1313
+ */
1314
+ encrypt(plaintext, nonce) {
1315
+ if (nonce.length !== 8) {
1316
+ throw Error(`nonce must be of length 8 (found ${nonce.length})`);
1317
+ }
1318
+ const paddedNonce = Buffer.concat([nonce, Buffer.alloc(16 - nonce.length, 0)]);
1319
+ const cipher = createCipheriv('aes-192-ctr', this.key, paddedNonce);
1320
+ const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
1321
+ return new Uint8Array(ciphertext);
1322
+ }
1323
+ /**
1324
+ * Decrypts the ciphertext array in Counter (CTR) mode.
1325
+ * @param ciphertext - The data to decrypt.
1326
+ * @param nonce - An 8-byte nonce for CTR mode.
1327
+ * @returns The decrypted plaintext as a Uint8Array.
1328
+ * @throws Error if the nonce is not 8 bytes long.
1329
+ */
1330
+ decrypt(ciphertext, nonce) {
1331
+ if (nonce.length !== 8) {
1332
+ throw Error(`nonce must be of length 8 (found ${nonce.length})`);
1333
+ }
1334
+ const paddedNonce = Buffer.concat([nonce, Buffer.alloc(16 - nonce.length, 0)]);
1335
+ const cipher = createDecipheriv('aes-192-ctr', this.key, paddedNonce);
1336
+ const decrypted = Buffer.concat([cipher.update(ciphertext), cipher.final()]);
1337
+ return new Uint8Array(decrypted);
1338
+ }
1339
+ }
1340
+
1341
+ /**
1342
+ * AES-256 cipher in Counter (CTR) mode, using HKDF-SHA3-256 to derive the key from a shared secret.
1343
+ * See: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf (Section 6.5) for details on CTR mode.
1344
+ */
1345
+ class Aes256Cipher {
1346
+ key;
1347
+ /**
1348
+ * Constructs an AES-256 cipher instance using a shared secret.
1349
+ * The key is derived using HKDF-SHA3-256.
1350
+ * @param sharedSecret - The shared secret to derive the AES key from.
1351
+ */
1352
+ constructor(sharedSecret) {
1353
+ const aesKey = hkdfSync('sha3-256', sharedSecret, new Uint8Array(), new Uint8Array(), 32);
1354
+ this.key = new Uint8Array(aesKey);
1355
+ }
1356
+ /**
1357
+ * Encrypts the plaintext array in Counter (CTR) mode.
1358
+ * @param plaintext - The data to encrypt.
1359
+ * @param nonce - An 8-byte nonce for CTR mode.
1360
+ * @returns The encrypted ciphertext as a Uint8Array.
1361
+ * @throws Error if the nonce is not 8 bytes long.
1362
+ */
1363
+ encrypt(plaintext, nonce) {
1364
+ if (nonce.length !== 8) {
1365
+ throw Error(`nonce must be of length 8 (found ${nonce.length})`);
1366
+ }
1367
+ const paddedNonce = Buffer.concat([nonce, Buffer.alloc(16 - nonce.length, 0)]);
1368
+ const cipher = createCipheriv('aes-256-ctr', this.key, paddedNonce);
1369
+ const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
1370
+ return new Uint8Array(ciphertext);
1371
+ }
1372
+ /**
1373
+ * Decrypts the ciphertext array in Counter (CTR) mode.
1374
+ * @param ciphertext - The data to decrypt.
1375
+ * @param nonce - An 8-byte nonce for CTR mode.
1376
+ * @returns The decrypted plaintext as a Uint8Array.
1377
+ * @throws Error if the nonce is not 8 bytes long.
1378
+ */
1379
+ decrypt(ciphertext, nonce) {
1380
+ if (nonce.length !== 8) {
1381
+ throw Error(`nonce must be of length 8 (found ${nonce.length})`);
1382
+ }
1383
+ const paddedNonce = Buffer.concat([nonce, Buffer.alloc(16 - nonce.length, 0)]);
1384
+ const cipher = createDecipheriv('aes-256-ctr', this.key, paddedNonce);
1385
+ const decrypted = Buffer.concat([cipher.update(ciphertext), cipher.final()]);
1386
+ return new Uint8Array(decrypted);
1387
+ }
1388
+ }
1389
+
980
1390
  var address = "BKck65TgoKRokMjQM3datB9oRwJ8rAj2jxPXvHXUvcL6";
981
1391
  var metadata = {
982
1392
  name: "arcium",
983
- version: "0.1.46",
1393
+ version: "0.1.47",
984
1394
  spec: "0.1.0",
985
1395
  description: "The Arcium program"
986
1396
  };
@@ -11522,32 +11932,75 @@ var ARCIUM_IDL = /*#__PURE__*/Object.freeze({
11522
11932
  types: types
11523
11933
  });
11524
11934
 
11935
+ /**
11936
+ * The deployed address of the Arcium program, as specified in the IDL.
11937
+ */
11525
11938
  const ARCIUM_ADDR = address;
11526
11939
 
11527
- // Seed for ClockAccount PDA
11940
+ /**
11941
+ * Seed for ClockAccount PDA
11942
+ * @constant {string}
11943
+ */
11528
11944
  const CLOCK_ACC_SEED = 'ClockAccount';
11529
- // Seed for StakingPoolAccount PDA
11945
+ /**
11946
+ * Seed for StakingPoolAccount PDA
11947
+ * @constant {string}
11948
+ */
11530
11949
  const POOL_ACC_SEED = 'StakingPoolAccount';
11531
- // Seed for ComputationAccount PDA
11950
+ /**
11951
+ * Seed for ComputationAccount PDA
11952
+ * @constant {string}
11953
+ */
11532
11954
  const COMPUTATION_ACC_SEED = 'ComputationAccount';
11533
- // Seed for Mempool PDA
11955
+ /**
11956
+ * Seed for Mempool PDA
11957
+ * @constant {string}
11958
+ */
11534
11959
  const MEMPOOL_ACC_SEED = 'Mempool';
11535
- // Seed for ExecutingPoolAccount PDA
11960
+ /**
11961
+ * Seed for ExecutingPoolAccount PDA
11962
+ * @constant {string}
11963
+ */
11536
11964
  const EXEC_POOL_ACC_SEED = 'Execpool';
11537
- // Seed for ClusterAccount PDA
11965
+ /**
11966
+ * Seed for ClusterAccount PDA
11967
+ * @constant {string}
11968
+ */
11538
11969
  const CLUSTER_ACC_SEED = 'Cluster';
11539
- // Seed for ArxNodeAccount PDA
11970
+ /**
11971
+ * Seed for ArxNodeAccount PDA
11972
+ * @constant {string}
11973
+ */
11540
11974
  const ARX_NODE_ACC_SEED = 'ArxNode';
11541
- // Seed for MXEAccAccount PDA
11975
+ /**
11976
+ * Seed for MXEAccAccount PDA
11977
+ * @constant {string}
11978
+ */
11542
11979
  const MXE_ACC_ACC_SEED = 'PersistentMXEAccount';
11543
- // Seed for CompDefAccount PDA
11980
+ /**
11981
+ * Seed for CompDefAccount PDA
11982
+ * @constant {string}
11983
+ */
11544
11984
  const COMP_DEF_ACC_SEED = 'ComputationDefinitionAccount';
11985
+ /**
11986
+ * Maximum number of bytes that can be reallocated per instruction.
11987
+ * @constant {number}
11988
+ */
11545
11989
  const MAX_REALLOC_PER_IX = 10240;
11546
- // Max number of bytes we can upload in a single transaction with the upload instruction
11990
+ /**
11991
+ * Maximum number of bytes that can be uploaded in a single transaction with the upload instruction.
11992
+ * @constant {number}
11993
+ */
11547
11994
  const MAX_UPLOAD_PER_TX_BYTES = 814;
11548
- // Max size of an account in bytes
11549
- const MAX_ACCOUNT_SIZE = 10485760; // 10MB = 10 * 1024 * 1024
11550
- // Max number of arcium embiggen instructions we can have in a single transaction (due to CUs)
11995
+ /**
11996
+ * Maximum size of an account in bytes (10MB = 10 * 1024 * 1024).
11997
+ * @constant {number}
11998
+ */
11999
+ const MAX_ACCOUNT_SIZE = 10485760;
12000
+ /**
12001
+ * Maximum number of arcium embiggen instructions allowed in a single transaction (due to compute unit limits).
12002
+ * @constant {number}
12003
+ */
11551
12004
  const MAX_EMBIGGEN_IX_PER_TX = 18;
11552
12005
 
11553
12006
  const TINY_MEMPOOL_ACC_NAME = 'tinyMempool';
@@ -11650,9 +12103,19 @@ const EXECPOOL_DISCRIMINATOR_MAP = {
11650
12103
  [MEDIUM_EXECPOOL_DISCRIMINATOR.toString()]: MEDIUM_EXECPOOL_ACC_NAME,
11651
12104
  [LARGE_EXECPOOL_DISCRIMINATOR.toString()]: LARGE_EXECPOOL_ACC_NAME,
11652
12105
  };
12106
+ /**
12107
+ * Returns the public key of the deployed Arcium program on Solana.
12108
+ * @returns The Arcium program's public key.
12109
+ */
11653
12110
  function getArciumProgAddress() {
11654
12111
  return new anchor.web3.PublicKey(ARCIUM_ADDR);
11655
12112
  }
12113
+ /**
12114
+ * Fetches the DA (Data Availability) info for all nodes in a cluster.
12115
+ * @param provider - The Anchor provider to use for fetching accounts.
12116
+ * @param clusterAddr - The public key of the cluster account.
12117
+ * @returns An array of NodeDAInfo objects for each node in the cluster.
12118
+ */
11656
12119
  async function getClusterDAInfo(provider, clusterAddr) {
11657
12120
  const program = getArciumProgram(provider);
11658
12121
  const clusterAcc = await program.account.cluster.fetch(clusterAddr);
@@ -11663,6 +12126,13 @@ async function getClusterDAInfo(provider, clusterAddr) {
11663
12126
  return { solanaPubkey: nodeAccPubkey, x25519Pubkey: Uint8Array.from(nodeAcc.encryptionPubkey) };
11664
12127
  }));
11665
12128
  }
12129
+ /**
12130
+ * Fetches and decodes the mempool account data for any mempool account size.
12131
+ * @param provider - The Anchor provider to use for fetching accounts.
12132
+ * @param mempoolAccPubkey - The public key of the mempool account.
12133
+ * @returns The decoded mempool account data.
12134
+ * @throws Error if the account cannot be fetched or the discriminator is unknown.
12135
+ */
11666
12136
  async function getMempoolAccData(provider, mempoolAccPubkey) {
11667
12137
  const accData = await provider.connection.getAccountInfo(mempoolAccPubkey);
11668
12138
  if (accData === null) {
@@ -11676,6 +12146,13 @@ async function getMempoolAccData(provider, mempoolAccPubkey) {
11676
12146
  const program = getArciumProgram(provider);
11677
12147
  return program.coder.accounts.decode(accName, accData.data);
11678
12148
  }
12149
+ /**
12150
+ * Fetches and decodes the executing pool account data for any pool size.
12151
+ * @param provider - The Anchor provider to use for fetching accounts.
12152
+ * @param executingPoolAccPubkey - The public key of the executing pool account.
12153
+ * @returns The decoded executing pool account data.
12154
+ * @throws Error if the account cannot be fetched or the discriminator is unknown.
12155
+ */
11679
12156
  async function getExecutingPoolAccData(provider, executingPoolAccPubkey) {
11680
12157
  const accData = await provider.connection.getAccountInfo(executingPoolAccPubkey);
11681
12158
  if (accData === null) {
@@ -11689,6 +12166,16 @@ async function getExecutingPoolAccData(provider, executingPoolAccPubkey) {
11689
12166
  const program = getArciumProgram(provider);
11690
12167
  return program.coder.accounts.decode(accName, accData.data);
11691
12168
  }
12169
+ /**
12170
+ * Uploads a circuit to the blockchain, splitting it into multiple accounts if necessary.
12171
+ * @param provider - The Anchor provider to use for transactions.
12172
+ * @param circuitName - The name of the circuit.
12173
+ * @param mxeProgramID - The public key of the MXE program.
12174
+ * @param rawCircuit - The raw circuit data as a Uint8Array.
12175
+ * @param logging - Whether to log progress (default: true).
12176
+ * @param chunkSize - The number of upload transactions to send in parallel (default: 500).
12177
+ * @returns An array of transaction signatures for all upload and finalize transactions.
12178
+ */
11692
12179
  async function uploadCircuit(provider, circuitName, mxeProgramID, rawCircuit, logging = true, chunkSize = 500) {
11693
12180
  const numAccs = Math.ceil(rawCircuit.length / (MAX_ACCOUNT_SIZE - 9));
11694
12181
  const compDefAccInfo = getCompDefAccInfo(circuitName, mxeProgramID);
@@ -11703,6 +12190,13 @@ async function uploadCircuit(provider, circuitName, mxeProgramID, rawCircuit, lo
11703
12190
  sigs.push(await signAndSendWithBlockhash(provider, finalizeCompDefTx, await provider.connection.getLatestBlockhash()));
11704
12191
  return sigs;
11705
12192
  }
12193
+ /**
12194
+ * Builds a transaction to finalize a computation definition.
12195
+ * @param provider - The Anchor provider to use for transactions.
12196
+ * @param compDefOffset - The offset of the computation definition.
12197
+ * @param mxeProgramID - The public key of the MXE program.
12198
+ * @returns The transaction to finalize the computation definition.
12199
+ */
11706
12200
  async function buildFinalizeCompDefTx(provider, compDefOffset, mxeProgramID) {
11707
12201
  const program = getArciumProgram(provider);
11708
12202
  const compDefOffsetBuffer = Buffer.alloc(4);
@@ -11804,35 +12298,78 @@ async function signAndSendWithBlockhash(provider, tx, block) {
11804
12298
  tx.lastValidBlockHeight = block.lastValidBlockHeight;
11805
12299
  return provider.sendAndConfirm(tx, [], { commitment: 'confirmed' });
11806
12300
  }
12301
+ /**
12302
+ * Returns the base seed for an Arcium account, given its name.
12303
+ * @param accName - The name of the account.
12304
+ * @returns The base seed as a Uint8Array.
12305
+ */
11807
12306
  function getArciumAccountBaseSeed(accName) {
11808
12307
  return Buffer.from(accName, 'utf-8');
11809
12308
  }
12309
+ /**
12310
+ * Computes the offset for a computation definition account, based on the circuit name.
12311
+ * @param circuitName - The name of the circuit.
12312
+ * @returns The offset as a 4-byte Uint8Array.
12313
+ */
11810
12314
  function getCompDefAccOffset(circuitName) {
11811
12315
  const hash = new Uint8Array(sha256([Buffer.from(circuitName, 'utf-8')]));
11812
12316
  return hash.slice(0, 4);
11813
12317
  }
12318
+ /**
12319
+ * Returns an Anchor program instance for the Arcium program.
12320
+ * @param provider - The Anchor provider to use.
12321
+ * @returns The Anchor program instance for Arcium.
12322
+ */
11814
12323
  function getArciumProgram(provider) {
11815
12324
  return new Program(ARCIUM_IDL, provider);
11816
12325
  }
12326
+ /**
12327
+ * Returns a read-only Anchor program instance for the Arcium program.
12328
+ * @param provider - The Anchor provider to use.
12329
+ * @returns The Anchor program instance for Arcium.
12330
+ */
11817
12331
  function getArciumProgramReadonly(provider) {
11818
12332
  return new Program(ARCIUM_IDL, provider);
11819
12333
  }
12334
+ /**
12335
+ * Returns the PDA (program-derived address) for an ArxNode account given the program ID and node offset.
12336
+ * @param arciumProgramID - The public key of the Arcium program.
12337
+ * @param nodeOffset - The offset of the node.
12338
+ * @returns The PDA for the ArxNode account.
12339
+ */
11820
12340
  function getArxAccPDA(arciumProgramID, nodeOffset) {
11821
12341
  const nodeOffsetBuffer = Buffer.alloc(4);
11822
12342
  nodeOffsetBuffer.writeUInt32LE(nodeOffset, 0);
11823
12343
  return anchor.web3.PublicKey.findProgramAddressSync([Buffer.from('ArxNode', 'utf-8'), nodeOffsetBuffer], arciumProgramID)[0];
11824
12344
  }
12345
+ /**
12346
+ * Returns the public key and offset for a computation definition account, given the circuit name and MXE program ID.
12347
+ * @param circuitName - The name of the circuit.
12348
+ * @param mxeProgramID - The public key of the MXE program.
12349
+ * @returns An object containing the public key and offset for the computation definition account.
12350
+ */
11825
12351
  function getCompDefAccInfo(circuitName, mxeProgramID) {
11826
12352
  const offset = getCompDefAccOffset(circuitName);
11827
12353
  const pda = getCompDefAccPDA(getArciumProgAddress(), mxeProgramID, offset);
11828
12354
  return { pubkey: pda, offset: Buffer.from(offset).readUInt32LE(0) };
11829
12355
  }
12356
+ /**
12357
+ * Returns the PDA for a computation definition account, given the program ID, MXE program ID, and offset.
12358
+ * @param arciumProgramID - The public key of the Arcium program.
12359
+ * @param mxeProgramID - The public key of the MXE program.
12360
+ * @param offset - The offset as a Uint8Array.
12361
+ * @returns The PDA for the computation definition account.
12362
+ */
11830
12363
  function getCompDefAccPDA(arciumProgramID, mxeProgramID, offset) {
11831
12364
  return anchor.web3.PublicKey.findProgramAddressSync([Buffer.from('ComputationDefinitionAccount', 'utf-8'), mxeProgramID.toBuffer(), offset], arciumProgramID)[0];
11832
12365
  }
11833
12366
 
11834
- // Reads local Arcium env information.
11835
- // Only available in Node.js and when testing locally.
12367
+ /**
12368
+ * Reads local Arcium environment information from environment variables.
12369
+ * Only available in Node.js and when testing locally.
12370
+ * @returns The local Arcium environment configuration.
12371
+ * @throws Error if called in a browser or if required environment variables are missing or invalid.
12372
+ */
11836
12373
  function getArciumEnv() {
11837
12374
  if (isBrowser()) {
11838
12375
  throw new Error('Arcium local env is not available in browser.');
@@ -12090,12 +12627,29 @@ class LogScanner {
12090
12627
  }
12091
12628
  }
12092
12629
 
12630
+ /**
12631
+ * Waits for the finalization of a computation by listening for the finalizeComputationEvent.
12632
+ * Resolves with the transaction signature once the computation is finalized.
12633
+ * @param provider - The Anchor provider to use for event listening.
12634
+ * @param computationOffset - The offset of the computation to wait for.
12635
+ * @param mxeProgramId - The public key of the MXE program.
12636
+ * @param commitment - (Optional) The desired finality/commitment level (default: 'confirmed').
12637
+ * @returns The transaction signature of the finalization event.
12638
+ */
12093
12639
  async function awaitComputationFinalization(provider, computationOffset, mxeProgramId, commitment = 'confirmed') {
12094
12640
  const arciumProgram = getArciumProgram(provider);
12095
12641
  const eventListener = new EventManager(arciumProgram.programId, provider, arciumProgram.coder);
12096
12642
  const finalizeComp = await awaitEvent(eventListener, 'finalizeComputationEvent', (e) => mxeProgramId.equals(e.mxeProgramId) && e.computationOffset.eq(computationOffset), commitment);
12097
12643
  return finalizeComp.sig;
12098
12644
  }
12645
+ /**
12646
+ * Waits for a specific event to occur, matching a custom check, and returns the event and its signature.
12647
+ * @param eventListener - The EventManager instance to use for listening.
12648
+ * @param eventName - The name of the event to listen for.
12649
+ * @param eventCheck - A predicate function to check if the event matches the desired criteria.
12650
+ * @param commitment - (Optional) The desired finality/commitment level (default: 'confirmed').
12651
+ * @returns An object containing the event and its transaction signature.
12652
+ */
12099
12653
  async function awaitEvent(eventListener, eventName, eventCheck, commitment = 'confirmed') {
12100
12654
  const foundEvent = await new Promise((res) => {
12101
12655
  const listenerId = eventListener.addEventListener(eventName, (event, _slot, signature) => {
@@ -12107,54 +12661,108 @@ async function awaitEvent(eventListener, eventName, eventCheck, commitment = 'co
12107
12661
  return { event: foundEvent[0], sig: foundEvent[1] };
12108
12662
  }
12109
12663
 
12664
+ /**
12665
+ * Returns the public key of the deployed Arcium program on Solana.
12666
+ * @returns The Arcium program's public key.
12667
+ */
12110
12668
  function getArciumProgramId() {
12111
12669
  return new PublicKey('BKck65TgoKRokMjQM3datB9oRwJ8rAj2jxPXvHXUvcL6');
12112
12670
  }
12113
- function getComputationAcc(mxeProgramId, offset) {
12671
+ /**
12672
+ * Derives the computation account address for a given MXE program ID and offset.
12673
+ * @param mxeProgramId - The public key of the MXE program.
12674
+ * @param offset - The computation offset as an anchor.BN.
12675
+ * @returns The derived computation account public key.
12676
+ */
12677
+ function getComputationAccAddress(mxeProgramId, offset) {
12114
12678
  const seeds = [Buffer.from(COMPUTATION_ACC_SEED), mxeProgramId.toBuffer(), offset.toArrayLike(Buffer, 'le', 8)];
12115
12679
  return generateArciumPDAFrom(seeds)[0];
12116
12680
  }
12117
- function getMempoolAcc(mxeProgramId) {
12681
+ /**
12682
+ * Derives the mempool account address for a given MXE program ID.
12683
+ * @param mxeProgramId - The public key of the MXE program.
12684
+ * @returns The derived mempool account public key.
12685
+ */
12686
+ function getMempoolAccAddress(mxeProgramId) {
12118
12687
  const seeds = [Buffer.from(MEMPOOL_ACC_SEED), mxeProgramId.toBuffer()];
12119
12688
  return generateArciumPDAFrom(seeds)[0];
12120
12689
  }
12121
- function getExecutingPoolAcc(mxeProgramId) {
12690
+ /**
12691
+ * Derives the executing pool account address for a given MXE program ID.
12692
+ * @param mxeProgramId - The public key of the MXE program.
12693
+ * @returns The derived executing pool account public key.
12694
+ */
12695
+ function getExecutingPoolAccAddress(mxeProgramId) {
12122
12696
  const seeds = [Buffer.from(EXEC_POOL_ACC_SEED), mxeProgramId.toBuffer()];
12123
12697
  return generateArciumPDAFrom(seeds)[0];
12124
12698
  }
12125
- function getStakingPoolAcc() {
12699
+ /**
12700
+ * Derives the staking pool account address.
12701
+ * @returns The derived staking pool account public key.
12702
+ */
12703
+ function getStakingPoolAccAddress() {
12126
12704
  const seeds = [Buffer.from(POOL_ACC_SEED)];
12127
12705
  return generateArciumPDAFrom(seeds)[0];
12128
12706
  }
12129
- function getClockAcc() {
12707
+ /**
12708
+ * Derives the clock account address.
12709
+ * @returns The derived clock account public key.
12710
+ */
12711
+ function getClockAccAddress() {
12130
12712
  const seeds = [Buffer.from(CLOCK_ACC_SEED)];
12131
12713
  return generateArciumPDAFrom(seeds)[0];
12132
12714
  }
12133
- function getClusterAcc(offset) {
12715
+ /**
12716
+ * Derives the cluster account address for a given offset.
12717
+ * @param offset - The cluster offset as a number.
12718
+ * @returns The derived cluster account public key.
12719
+ */
12720
+ function getClusterAccAddress(offset) {
12134
12721
  const offsetBuffer = Buffer.alloc(4);
12135
12722
  offsetBuffer.writeUInt32LE(offset, 0);
12136
12723
  const seeds = [Buffer.from(CLUSTER_ACC_SEED), offsetBuffer];
12137
12724
  return generateArciumPDAFrom(seeds)[0];
12138
12725
  }
12139
- function getArxNodeAcc(offset) {
12726
+ /**
12727
+ * Derives the ArxNode account address for a given offset.
12728
+ * @param offset - The ArxNode offset as a number.
12729
+ * @returns The derived ArxNode account public key.
12730
+ */
12731
+ function getArxNodeAccAddress(offset) {
12140
12732
  const offsetBuffer = Buffer.alloc(4);
12141
12733
  offsetBuffer.writeUInt32LE(offset, 0);
12142
12734
  const seeds = [Buffer.from(ARX_NODE_ACC_SEED), offsetBuffer];
12143
12735
  return generateArciumPDAFrom(seeds)[0];
12144
12736
  }
12145
- function getMXEAccAcc(mxeProgramId) {
12737
+ /**
12738
+ * Derives the MXE account address for a given MXE program ID.
12739
+ * @param mxeProgramId - The public key of the MXE program.
12740
+ * @returns The derived MXE account public key.
12741
+ */
12742
+ function getMXEAccAddress(mxeProgramId) {
12146
12743
  const seeds = [Buffer.from(MXE_ACC_ACC_SEED), mxeProgramId.toBuffer()];
12147
12744
  return generateArciumPDAFrom(seeds)[0];
12148
12745
  }
12149
- function getCompDefAcc(mxeProgramId, offset) {
12746
+ /**
12747
+ * Derives the computation definition account address for a given MXE program ID and offset.
12748
+ * @param mxeProgramId - The public key of the MXE program.
12749
+ * @param offset - The computation definition offset as a number.
12750
+ * @returns The derived computation definition account public key.
12751
+ */
12752
+ function getCompDefAccAddress(mxeProgramId, offset) {
12150
12753
  const offsetBuffer = Buffer.alloc(4);
12151
12754
  offsetBuffer.writeUInt32LE(offset, 0);
12152
12755
  const seeds = [Buffer.from(COMP_DEF_ACC_SEED), mxeProgramId.toBuffer(), offsetBuffer];
12153
12756
  return generateArciumPDAFrom(seeds)[0];
12154
12757
  }
12758
+ /**
12759
+ * Generates a program-derived address (PDA) from the provided seeds and the Arcium program ID.
12760
+ * @param seeds - An array of Buffer seeds used for PDA derivation.
12761
+ * @returns A tuple containing the derived public key and the bump seed.
12762
+ */
12155
12763
  function generateArciumPDAFrom(seeds) {
12156
12764
  const programId = getArciumProgramId();
12157
12765
  return PublicKey.findProgramAddressSync(seeds, programId);
12158
12766
  }
12159
12767
 
12160
- export { ARCIUM_ADDR, ARCIUM_IDL, CURVE25519_BASE_FIELD, CURVE25519_SCALAR_FIELD_MODULUS, DOUBLE_PRECISION_MANTISSA, Matrix, RescueCipher, RescueDesc, RescuePrimeHash, awaitComputationFinalization, buildFinalizeCompDefTx, deserializeLE, encodeAsRescueEncryptable, encryptForDA, genRawShares, generateRandomFieldElem, getArciumAccountBaseSeed, getArciumEnv, getArciumProgAddress, getArciumProgram, getArciumProgramId, getArciumProgramReadonly, getArxNodeAcc, getClockAcc, getClusterAcc, getClusterDAInfo, getCompDefAcc, getCompDefAccOffset, getComputationAcc, getEncryptionKey, getExecutingPoolAcc, getExecutingPoolAccData, getMXEAccAcc, getMempoolAcc, getMempoolAccData, getStakingPoolAcc, positiveModulo, randMatrix, secretShareInputs, secretShareValue, serializeLE, sha256, toVec, uploadCircuit };
12768
+ export { ARCIUM_ADDR, ARCIUM_IDL, Aes128Cipher, Aes192Cipher, Aes256Cipher, CURVE25519_BASE_FIELD, CURVE25519_SCALAR_FIELD_MODULUS, DOUBLE_PRECISION_MANTISSA, Matrix, RescueCipher, RescueDesc, RescuePrimeHash, arcisEd25519, awaitComputationFinalization, buildFinalizeCompDefTx, deserializeLE, encodeAsRescueEncryptable, encryptForDA, genRawShares, generateRandomFieldElem, getArciumAccountBaseSeed, getArciumEnv, getArciumProgAddress, getArciumProgram, getArciumProgramId, getArciumProgramReadonly, getArxNodeAccAddress, getClockAccAddress, getClusterAccAddress, getClusterDAInfo, getCompDefAccAddress, getCompDefAccOffset, getComputationAccAddress, getEncryptionKey, getExecutingPoolAccAddress, getExecutingPoolAccData, getMXEAccAddress, getMempoolAccAddress, getMempoolAccData, getStakingPoolAccAddress, positiveModulo, randMatrix, secretShareInputs, secretShareValue, serializeLE, sha256, toVec, uploadCircuit };