It initializes the tree with an hash function, the depth, the zero value to use for zeroes +and the arity (i.e. the number of children for each node). It also takes an optional parameter +to initialize the tree with a list of leaves.
+The hash function used to create nodes.
+The tree depth.
+The zero value used to create zeroes.
+The number of children for each node.
+The list of initial leaves.
+Private
Readonly
_arityThe number of children per node.
+Private
Readonly
_depthThe depth of the tree, which is the number of edges from the node to the +tree's root node.
+Private
Readonly
_hashThe hash function used to compute the tree nodes.
+Private
Readonly
_nodesThe matrix where all the tree nodes are stored. The first index indicates +the level of the tree, while the second index represents the node's +position within that specific level.
+Private
Readonly
_zeroesA list of zero values calculated during the initialization of the tree. +The list contains one value for each level of the tree, and the value for +a given level is equal to the hash of the previous level's value. +The first value is the zero hash provided by the user. +These values are used to calculate the hash of a node in case some of its +children are missing.
+The number of children per node.
+The number of children per node.
+The depth of the tree, which equals the number of levels - 1.
+The depth of the tree.
+The leaves of the tree. They can be retrieved from the first +level of the tree using IMT#_nodes. The returned +value is a copy of the array and not the original object.
+The list of tree leaves.
+The root of the tree. This value doesn't need to be stored as +it is always the first and unique element of the last level of the tree. +Its value can be retrieved in IMT#_nodes.
+The root hash of the tree.
+The list of zero values calculated during the initialization of the tree.
+The list of pre-computed zeroes.
+It creates a IMTMerkleProof for a leaf of the tree. +That proof can be verified by this tree using the same hash function.
+The index of the leaf for which a Merkle proof will be generated.
+The Merkle proof of the leaf.
+The leaves are inserted incrementally. If 'i' is the index of the last +leaf, the new one will be inserted at position 'i + 1'. Every time a +new leaf is inserted, the nodes that separate the new leaf from the root +of the tree are created or updated if they already exist, from bottom to top. +When a node has only one child (the left one), its value is the hash of that +node and the zero value of that level. Otherwise, the hash of the children +is calculated.
+The new leaf to be inserted in the tree.
+It updates a leaf in the tree. It's very similar to the IMT#insert function.
+The index of the leaf to be updated.
+The new leaf to be inserted.
+It verifies a IMTMerkleProof to confirm that a leaf indeed
+belongs to a tree. Does not verify that the node belongs to this
+tree in particular. Equivalent to IMT.verifyProof(proof, this._hash)
.
The Merkle tree proof.
+True if the leaf is part of the tree, and false otherwise.
+Static
verifyIt verifies a IMTMerkleProof to confirm that a leaf indeed +belongs to a tree.
+The Merkle tree proof.
+The hash function used to compute the tree nodes.
+True if the leaf is part of the tree, and false otherwise.
+The LeanIMT is an optimized binary version of the IMT. +This implementation exclusively supports binary trees, eliminates the use of +zeroes, and the tree's LeanIMT#depth is dynamic. When a node doesn't have the right child, +instead of using a zero hash as in the IMT, the node's value becomes that +of its left child. Furthermore, rather than utilizing a static tree depth, +it is updated based on the number of LeanIMT#leaves in the tree. This approach +results in the calculation of significantly fewer hashes, making the tree more efficient.
+Private
Readonly
_hashThe hash function used to compute the tree nodes.
+Private
_nodesThe matrix where all the tree nodes are stored. The first index indicates +the level of the tree, while the second index represents the node's +position within that specific level. The last level will always contain +a list with a single element, which is the root. +Most of the attributes of this class are getters which can retrieve +their values from this matrix.
+The depth of the tree, which equals the number of levels - 1.
+The depth of the tree.
+The leaves of the tree. They can be retrieved from the first +level of the tree using LeanIMT#_nodes. The returned +value is a copy of the array and not the original object.
+The list of tree leaves.
+The root of the tree. This value doesn't need to be stored as +it is always the first and unique element of the last level of the tree. +Its value can be retrieved in LeanIMT#_nodes.
+The root hash of the tree.
+The size of the tree, which the number of its leaves. +It's the length of the first level's list.
+The number of leaves of the tree.
+It generates a LeanIMTMerkleProof for a leaf of the tree. +That proof can be verified by this tree using the same hash function.
+The index of the leaf for which a Merkle proof will be generated.
+The Merkle proof of the leaf.
+It returns true if the leaf exists, and false otherwise
+A leaf of the tree.
+True if the tree has the leaf, and false otherwise.
+It returns the index of a leaf. If the leaf does not exist it returns -1.
+A leaf of the tree.
+The index of the leaf.
+The leaves are inserted incrementally. If 'i' is the index of the last +leaf, the new one will be inserted at position 'i + 1'. Every time a +new leaf is inserted, the nodes that separate the new leaf from the root +of the tree are created or updated if they already exist, from bottom to top. +When a node has only one child (the left one), its value takes on the value +of the child. Otherwise, the hash of the children is calculated.
+The new leaf to be inserted in the tree.
+This function is useful when you want to insert N leaves all at once. +It is more efficient than using the LeanIMT#insert method N times because it +significantly reduces the number of cases where a node has only one +child, which is a common occurrence in gradual insertion.
+The list of leaves to be inserted.
+It updates a leaf in the tree. It's very similar to the LeanIMT#insert function.
+The index of the leaf to be updated.
+The new leaf to be inserted.
+Updates m leaves all at once. +It is more efficient than using the LeanIMT#update method m times because it +prevents updating middle nodes several times. This would happen when updating leaves +with common ancestors. The naive approach of calling 'update' m times has complexity +O(mlog(n)) (where n is the number of leaves of the tree), which ends up in +O(nlog(n)) when m ~ n. With this new approach, this ends up being O(n) because every +node is updated at most once and there are around 2*n nodes in the tree.
+The list of indices of the respective leaves.
+The list of leaves to be updated.
+It verifies a LeanIMTMerkleProof to confirm that a leaf indeed
+belongs to a tree. Does not verify that the node belongs to this
+tree in particular. Equivalent to
+LeanIMT.verifyProof(proof, this._hash)
.
The Merkle tree proof.
+True if the leaf is part of the tree, and false otherwise.
+Static
importIt imports an entire tree by initializing the nodes without calculating +any hashes. Note that it is crucial to ensure the integrity of the tree +before or after importing it. If the map function is not defined, node +values will be converted to bigints by default.
+The hash function used to create nodes.
+The stringified JSON of the tree.
+Optional
map: ((value) => N)A function to map each node of the tree and convert their types.
+A LeanIMT instance.
+Static
verifyIt verifies a LeanIMTMerkleProof to confirm that a leaf indeed +belongs to a tree.
+The Merkle tree proof.
+True if the leaf is part of the tree, and false otherwise.
+SparseMerkleTree class provides all the functions to create a sparse Merkle tree
+and to take advantage of its features: SMT.add
, SMT.get
,
+SMT.update
, SMT.delete
, SMT.createProof
,
+SMT.verifyProof
.
+To better understand the code below it may be useful to describe the terminology used:
H(x, y)
);H(x, y, 1)
);H(0,0) = 0
;Initializes the SparseMerkleTree attributes.
+Hash function used to hash the child nodes.
+BigInt type enabling.
+Private
bigPrivate
entryPrivate
hashPrivate
nodesPrivate
zeroPrivate
addPrivate
calculatePrivate
checkChecks the parameter type.
+The parameter to check.
+Creates a proof to prove the membership or the non-membership +of a tree entry.
+A key of an existing or a non-existing entry.
+The membership or the non-membership proof.
+Deletes an entry in the tree. Also in this case all the hashes of +the nodes in the path of the entry are updated with a bottom-up approach.
+The key of the entry.
+Private
deletePrivate
isChecks if a node is a leaf node.
+A node of the tree.
+True if the node is a leaf, false otherwise.
+Private
retrieveSearches for an entry in the tree. If the key passed as parameter exists in +the tree, the function returns the entry, otherwise it returns the entry +with only the key, and when there is another existing entry +in the same path it returns also this entry as 'matching entry'. +In any case the function returns the siblings of the path.
+The key of the entry to search for.
+The entry response.
+Verifies a membership or a non-membership proof.
+The proof to verify.
+True if the proof is valid, false otherwise.
+F1Field +Represents a finite field of order 'order' providing arithmetic operations under modulus. +This class includes operations such as addition, subtraction, multiplication, division, +and inversion, all performed modulo the field's order. It's designed to work with bigints, +supporting large numbers for cryptographic purposes and other applications requiring +modular arithmetic. +Note that the outputs of the functions will always be within the field if and only if +the input values are within the field. Devs need to make sure of that.
+Half the order of the field, used for certain comparisons.
+The scalar value -1 in the field, represented positively.
+The order of the finite field (i.e., the modulus).
+Represents the scalar value 1 in the field.
+Represents the scalar value 0 in the field.
+Checks if two bigint values are equal within the context of the field. +It ensures the result is within the field if and only if the input values are within the field.
+The first value to compare.
+The second value to compare.
+True if 'a' equals 'b', false otherwise.
+Compares two bigint values to determine if the first is greater than or equal to the second, +considering the field's modular context. +It ensures the result is within the field if and only if the input values are within the field.
+The first value to compare.
+The second value to compare.
+True if 'a' is greater than or equal to 'b', false otherwise.
+Computes the multiplicative inverse of a given value within the field. +This method uses the Extended Euclidean Algorithm to find the inverse, +ensuring the result is always a positive value less than the field's order. +If the input value is zero, which has no inverse, an error is thrown.
+The value for which to compute the inverse.
+The multiplicative inverse of 'a' modulo the field's order.
+if 'a' is zero.
+Compares two bigint values to determine if the first is less than the second, +taking into account the field's order for modular comparison. +It ensures the result is within the field if and only if the input values are within the field.
+The first value to compare.
+The second value to compare.
+True if 'a' is less than 'b', false otherwise.
+Computes the negation of a bigint value within the field. +The result is the modular additive inverse that, when added to the original value, +yields zero in the field's modulus. +It ensures the result is within the field if and only if the input values are within the field.
+The value to negate.
+The negation of 'a' modulo the field's order.
+Raises a base to an exponent within the field, efficiently computing
+scalar exponentiation using the square-and-multiply algorithm.
+Supports both positive and negative exponents through the use of the inv
method for negatives.
The base to be exponentiated.
+The exponent.
+The result of raising 'base' to the power 'e' modulo the field's order.
+Squares a bigint value within the field. +This is a specific case of multiplication where the value is multiplied by itself, +optimized for performance where applicable. +It ensures the result is within the field if and only if the input values are within the field.
+The value to square.
+The square of 'a' modulo the field's order.
+Subtracts one bigint from another under modulus. +It ensures the result is within the field if and only if the input values are within the field.
+The value from which to subtract.
+The value to be subtracted.
+The difference of 'a' and 'b' modulo the field's order.
+Performs point addition on the Baby Jubjub elliptic curve, +calculating a third point from two given points. +Let P1 = (x1, y1) and P2 = (x2, y2) be two arbitrary points of the curve. +Then P1 + P2 = (x3, y3) is calculated in the following way: +x3 = (x1y2 + y1x2)/(1 + dx1x2y1y2) +y3 = (y1y2 - ax1x2)/(1 - dx1x2y1*y2)
+Resultant third point on the curve.
+Determines if a given point lies on the Baby Jubjub elliptic curve by verifying the curve equation.
+This function checks if the point satisfies the curve equation ax^2 + y^2 = 1 + dx^2y^2
.
The point to check, represented as a pair of bigint values.
+True if the point is on the curve, otherwise false.
+Performs a scalar multiplication by starting from the 'base' point and 'adding' +it to itself 'e' times.
+The base point used as a starting point.
+A secret number representing the private key.
+The resulting point representing the public key.
+Packs a point on the Baby Jubjub elliptic curve into a bigint. +This process involves converting the y-coordinate to a buffer and conditionally modifying the last byte +to encode the sign of the x-coordinate, following a specific compact representation format.
+The point to be packed, consisting of x and y coordinates.
+The packed representation of the point as a bigint.
+Unpacks a bigint back into a point on the Baby Jubjub elliptic curve, reversing the packing process. +This involves interpreting the bigint as the y-coordinate and extracting the sign of the x-coordinate +from the encoded format. The function then calculates the x-coordinate using the curve equation.
+The packed point as a bigint.
+The unpacked point as a pair of bigint values, or null if the point is invalid.
+Derives a public key from a given private key using the +Jubjub elliptic curve. +This function utilizes the Baby Jubjub elliptic curve for cryptographic operations. +The private key should be securely stored and managed, and it should never be exposed +or transmitted in an unsecured manner.
+The private key must be an instance of Buffer, Uint8Array or a string. The input will be used to +generate entropy and there is no limit in size. +The string is used as a set of raw bytes (in UTF-8) and is typically used to pass passwords or secret messages. +If you want to pass a bigint, a number or a hexadecimal, be sure to convert them to one of the supported types first. +The 'conversions' module in @zk-kit/utils provides a set of functions that may be useful in case you need to convert types.
+The private key used for generating the public key.
+The derived public key.
+Derives a public key from a given private key using the +Jubjub elliptic curve. +This function utilizes the Baby Jubjub elliptic curve for cryptographic operations. +The private key should be securely stored and managed, and it should never be exposed +or transmitted in an unsecured manner.
+The private key must be an instance of Buffer, Uint8Array or a string. The input will be used to +generate entropy and there is no limit in size. +The string is used as a set of raw bytes (in UTF-8) and is typically used to pass passwords or secret messages. +If you want to pass a bigint, a number or a hexadecimal, be sure to convert them to one of the supported types first. +The 'conversions' module in @zk-kit/utils provides a set of functions that may be useful in case you need to convert types.
+The private key used for generating the public key.
+The derived public key.
+Converts a given public key into a packed (compressed) string format for efficient transmission and storage. +This method ensures the public key is valid and within the Baby Jubjub curve before packing.
+The public key to be packed.
+A string representation of the packed public key.
+Packs an EdDSA signature into a buffer of 64 bytes for efficient storage. +Use unpackSignature to reverse the process without needing to know +the details of the format.
+The buffer contains the R8 point packed int 32 bytes (via +packSignature) followed by the S scalar. All encodings are +little-endian.
+the signature to pack
+a 64 byte buffer containing the packed signature
+Signs a message using the provided private key, employing Poseidon hashing and +EdDSA with the Baby Jubjub elliptic curve.
+The private key must be an instance of Buffer, Uint8Array or a string. The input will be used to +generate entropy and there is no limit in size. +The string is used as a set of raw bytes (in UTF-8) and is typically used to pass passwords or secret messages. +If you want to pass a bigint, a number or a hexadecimal, be sure to convert them to one of the supported types first. +The 'conversions' module in @zk-kit/utils provides a set of functions that may be useful in case you need to convert types.
+The private key used to sign the message.
+The message to be signed.
+The signature object, containing properties relevant to EdDSA signatures, such as 'R8' and 'S' values.
+Unpacks a public key from its packed string representation back to its original point form on the Baby Jubjub curve. +This function checks for the validity of the input format before attempting to unpack.
+The packed public key as a bignumberish.
+The unpacked public key as a point.
+Unpacks a signature produced by packSignature. See that function +for the details of the format.
+the 64 byte buffer to unpack
+a Signature with numbers in string form
+Verifies an EdDSA signature using the Baby Jubjub elliptic curve and Poseidon hash function.
+The original message that was be signed.
+The EdDSA signature to be verified.
+The public key associated with the private key used to sign the message.
+Returns true if the signature is valid and corresponds to the message and public key, false otherwise.
+LazyTowerHashChainProofBuilder is a TypeScript implementation of LazyTower to generate proofs of membership.
+Height of tower of the proving circuit. It can be less than the H in the contract.
+Width of tower.
+A hash function which supports 2 input values.
+Adds a new item in the LazyTower.
+Item to be added.
+Builds a proof of membership.
+Index of the proof's item.
+Proof object.
+Returns the index of a item. If the item does not exist it returns -1.
+Added item.
+Index of the item.
+Function to apply unary or binary operators to boolean values.
+Logical operators supported: and
, or
, not
, xor
.
Operator to apply.
+First boolean value.
+Optional
b: booleanSecond boolean value (optional, only used for binary operators).
+The boolean value after applying the operator.
+// Example usage:
import { applyOperator } from "@zk-kit/logical-expressions"
// Unary operator
const result1 = applyOperator("not", true)
console.log(result1) // Output: false
// Binary operator
const result2 = applyOperator("and", true, false)
console.log(result2) // Output: false
+
+Function to evaluate a tokenized expression. +This algorithm is an adaptation of the +Shunting Yard +algorithm to evaluate expressions with logical operators.
+There is no need to verify the correctness of the logical expression +before calling the evaluate function, as this will be checked during +the evaluation. If the expression is incorrect, an error will be thrown automatically.
+Example of correct logical expression: "true and false"
.
Example of incorrect logical expression: "true true and false"
.
Logical operators supported: and
, or
, not
, xor
.
+All other existing logical operators (nand
, nor
, xnor
)
+can be generated using the supported logical operators.
Tokens of the expression. +The tokens can be boolean values, logical operators or parentheses.
+The boolean value after evaluating the expression.
+// Example usage:
import { evaluate } from "@zk-kit/logical-expressions"
const expression = ["true", "and", "false"]
const result = evaluate(expression)
console.log(result) // Output: false
+
+Function to determine the precedence of operators. +Unary operators have higher precedence. +Binary operators have the same precedence.
+Operator to check the precedence.
+The precedence of the operator or 0 if +the operator is not supported
+// Example usage:
import { precedence } from "@zk-kit/logical-expressions"
const result = precedence("and")
console.log(result) // Output: 1
+
+Tokenization function to split the expression into meaningful tokens.
+The expression to tokenize.
+A list with the tokens of the expression.
+// Example usage:
import { tokenize } from "@zk-kit/logical-expressions"
const expression = "true and false or ( true and true )"
const tokens = tokenize(expression)
console.log(tokens)
// Output: ["true", "and", "false", "or", "(", "true", "and", "true", ")"]
+
+Decrypt some ciphertext using poseidon encryption
+the ciphertext to decrypt
+the key to decrypt with
+the nonce used to encrypt
+the length of the plaintext
+the plaintext
+Decrypt some ciphertext using poseidon encryption
+the ciphertext to decrypt
+the key to decrypt with
+the nonce used to encrypt
+the length of the plaintext
+the plaintext
+Do not throw if the plaintext is invalid
+Encrypt some plaintext using poseidon encryption
+the message to encrypt
+the key to encrypt with
+the nonce to avoid replay attacks
+the ciphertext
+Given an input containing string values, convert them +to bigint
+the input to convert
+the input with string values converted to bigint
+Creates a zero-knowledge proof to prove that you have the preimages of a hash, +without disclosing the actual preimages themselves. +The use of a scope parameter helps ensure the uniqueness +and non-reusability of the proofs, enhancing security in applications like +blockchain transactions or private data verification. +If, for example, this package were used with Semaphore to demonstrate possession +of a Semaphore identity of a group of voters, the scope could be the poll's ID.
+The preimages of the hash.
+A public value used to contextualize the cryptographic proof +and calculate the nullifier.
+Optional
snarkArtifacts: SnarkArtifactsThe Snark artifacts (wasm and zkey files) generated in +a trusted setup of the circuit are necessary to generate valid proofs
+The Poseidon zero-knowledge proof.
+Verifies that a Poseidon proof is valid.
+PoseidonProof
+True if the proof is valid, false otherwise.
+Converts a base64 string to bytes (i.e. a buffer). This function does not check +if the input value is a valid base64 string. If there are unsupported characters +they will be ignored.
+The base64 string to convert.
+The converted buffer.
+Converts a base64 string to text (utf8). This function does not check +if the input value is a valid base64 string. If there are unsupported characters +they could be ignored and the result may be unexpected.
+The base64 string to convert.
+The converted text.
+Converts a bigint to a buffer and fills with zeros if a valid
+size (i.e. number of bytes) is specified. If the size is not defined,
+it gets the size from the given bigint. If the specified size is smaller than
+the size of the bigint (i.e. minSize
), an error is thrown.
+It uses big-endian byte order.
The bigint to convert.
+Optional
size: numberThe number of bytes of the buffer to return.
+The buffer representation of the bigint.
+Converts a buffer of bytes to a bigint using big-endian byte order. +It accepts 'Buffer' or 'Uint8Array'.
+The buffer to convert.
+The bigint representation of the buffer's contents.
+Converts a BigNumberish type to a bigint. If the input is already a bigint, +the return value will be the bigint itself, otherwise it will be converted +to a bigint using big-endian byte order.
+The BigNumberish value to convert.
+The bigint representation of the BigNumberish value.
+Converts a BigNumberish type to a buffer. If the input is already a buffer, +the return value will be the buffer itself, otherwise it will be converted +to a buffer using big-endian byte order.
+The BigNumberish value to convert.
+The buffer representation of the BigNumberish value.
+Converts bytes to a base64 string. It accepts 'Buffer' or 'Uint8Array'.
+The bytes to convert.
+The converted base64 string.
+Converts a buffer to a bigint. Alias for beBufferToBigInt.
+The buffer to convert.
+The bigint representation of the buffer's contents.
+Converts a buffer to a hexadecimal string. It accepts 'Buffer' or 'Uint8Array'. +The hexadecimal string will not start with '0x' or '0X'. It keeps the bytes in the same order.
+The buffer to convert.
+The converted hexadecimal string.
+Converts a hexadecimal string to a bigint. The input is interpreted as hexadecimal +with or without a '0x' prefix. It uses big-endian byte order.
+The hexadecimal string to convert.
+The bigint representation of the hexadecimal string.
+Converts an hexadecimal string to a buffer. The hexadecimal string +should not start with '0x' or '0X'. It keeps the bytes in the same order.
+The hexadecimal string to convert.
+The buffer representation of the hexadecimal string.
+Converts a bigint to a buffer and fills with zeros if a valid
+size (i.e. number of bytes) is specified. If the size is not defined,
+it gets the size from the given bigint. If the specified size is smaller than
+the size of the bigint (i.e. minSize
), an error is thrown.
+It uses little-endian byte order.
The bigint to convert.
+Optional
size: numberThe number of bytes of the buffer to return.
+The buffer representation of the bigint in little-endian.
+Converts a buffer to a bigint using little-endian byte order. +It accepts 'Buffer' or 'Uint8Array'.
+The buffer to convert.
+The bigint representation of the buffer's contents in little-endian.
+The parameter value.
+The parameter name.
+Throws a type error if the parameter value is not a Buffer.
+The parameter value.
+The parameter name.
+A boolean to include or not a '0x' or '0X' prefix.
+Throws a type error if the parameter value is not a hexadecimal string. +If 'prefix' is 'true', the string must start with '0x' or '0X' followed by one or more +hexadecimal digits (0-9, a-f, A-F), otherwise no prefix is expected. 'prefix' is optional and +if its value it is not explicitly defined it will be set to 'true' by default.
+The parameter value.
+The parameter name.
+Throws a type error if the parameter value type is not part of the list of types.
+Packs a Snarkjs Groth16 proof into a single list usable as calldata in Solidity (public signals are not included).
+The Groth16 proof generated with SnarkJS.
+Solidity calldata.
+Unpacks a PackedGroth16Proof Solidity calldata into its original form which is a SnarkJS Groth16 proof.
+Solidity calldata.
+The Groth16 proof compatible with SnarkJS.
+Converts a bigint scalar value into an array of bits, represented as numbers. +This function is particularly useful for examining the binary structure of bigints, +which can be necessary for bit manipulation and understanding the representation +of numbers at a lower level.
+The bigint scalar value to convert into bits.
+An array of numbers representing the bits of 'n', starting from the least significant bit.
+Performs a bitwise right shift on a bigint scalar value. +This operation is equivalent to dividing by 2^n, but it operates directly +on the binary representation, making it efficient for certain types of calculations.
+The bigint scalar value to shift.
+The number of bits to shift 'a' by.
+The result of shifting 'a' right by 'n' bits.
+Checks if the given value can be considered as BigNumberish. +A value is considered BigNumberish if it meets +any of the following conditions: it's a number, a bigint, a string +that can be converted to a bigint, a hexadecimal +string, or a Buffer object.
+The value to check.
+Checks if a string is a valid hexadecimal string representation. +If 'prefix' is 'true', the string must start with '0x' or '0X' followed by one or more +hexadecimal digits (0-9, a-f, A-F), otherwise no prefix is expected. 'prefix' is optional and +if its value it is not explicitly defined it will be set to 'true' by default.
+The string to be tested.
+A boolean to include or not a '0x' or '0X' prefix.
+Returns true if the type is being supported by this utility +functions, false otherwise.
+The type to be checked.
+Returns true if the value type is the same as the type passed +as the second parameter, false otherwise.
+The expected type.
++
+ + + + + + + + + + + + + + + + + + + + + +
+ +ZK-Kit is a set of libraries (algorithms or utility functions) that can be reused in different projects and zero-knowledge protocols, making it easier for developers to access user-friendly, tested, and documented code for common tasks. ZK-Kit provides different repositories for each language - this one contains JavaScript code only. | +
---|
♚ Yarn workspaces: minimal monorepo package management (yarn
, yarn build
, yarn docs
)
♛ Conventional Commits: human and machine readable meaning to commit messages (yarn commit
)
♜ Jest: tests and test coverage for all libraries (yarn test:libraries
)
♞ ESLint, Prettier: code quality and formatting (yarn prettier
& yarn lint
)
♝ Typedocs: documentation generator for TypeScript (yarn docs
)
♟ Benny: simple benchmarking framework for JavaScript/TypeScript (yarn benchmarks
)
♟ Github actions: software workflows for automatic testing, documentation deploy and code quality checks
Package | +Version | +Downloads | +Size | +Audited | + +
---|---|---|---|---|
+ + @zk-kit/eddsa-poseidon + + + (docs) + + | ++ + + + + | ++ + + + + | ++ + + + + | ++ + ✔️ + + | +
+ + @zk-kit/poseidon-cipher + + + (docs) + + | ++ + + + + | ++ + + + + | ++ + + + + | ++ ❌ + | +
+ + @zk-kit/baby-jubjub + + + (docs) + + | ++ + + + + | ++ + + + + | ++ + + + + | ++ + ✔️ + + | +
+ + @zk-kit/utils + + + (docs) + + | ++ + + + + | ++ + + + + | ++ + + + + | ++ + ✔️ + + | +
+ + @zk-kit/imt + + + (docs) + + | ++ + + + + | ++ + + + + | ++ + + + + | ++ ❌ + | +
+ + @zk-kit/lean-imt + + + (docs) + + | ++ + + + + | ++ + + + + | ++ + + + + | ++ + ✔️ + + | +
+ + @zk-kit/smt + + + (docs) + + | ++ + + + + | ++ + + + + | ++ + + + + | ++ ❌ + | +
+ + @zk-kit/poseidon-proof + + + (docs) + + | ++ + + + + | ++ + + + + | ++ + + + + | ++ ❌ + | +
+ + @zk-kit/logical-expressions + + + (docs) + + | ++ + + + + | ++ + + + + | ++ + + + + | ++ ❌ + | +
Clone this repository:
+git clone https://github.com/privacy-scaling-explorations/zk-kit.git
+
+and install the dependencies:
+cd zk-kit && yarn
+
+Run ESLint to analyze the code and catch bugs:
+yarn lint
+
+Run Prettier to check formatting rules:
+yarn format
+
+or to automatically format the code:
+yarn format:write
+
+ZK-Kit uses conventional commits. A command line utility to commit using the correct syntax can be used by running:
+yarn commit
+
+It will also automatically check that the modified files comply with ESLint and Prettier rules.
+Test the code:
+yarn test
+
+Build all the packages:
+yarn build
+
+A dist
folder will be created inside each JavaScript package.
Generate a documentation website for each package:
+yarn docs
+
+The output will be placed on the docs
folder.
yarn version:bump <package-name> <version>
# e.g. yarn version:bump utils 2.0.0
+
+This step creates a commit and a git tag.
+git push origin main
+
+git push origin <package-name>-<version>
# e.g. git push origin utils-v2.0.0
+
+After pushing the new git tag, a workflow will be triggered and will publish the package on npm and release a new version on Github with its changelogs automatically.
+ZK-kit provides a set of pre-configured development tools. All you have to deal with is your own code, testing and documentation. To create a package follow these steps:
+README.md
and package.json
files with your package name:cd zk-kit
cp -r packages/smt packages/my-package
cd packages/my-package && rm -fr node_modules dist
grep -r -l "smt" . | xargs sed -i 's/smt/my-package/'
# Update the remaining description/usage sections, and write your code in the src & tests folders!
+
+You can see some examples in the benchmarks
folder. All you have to do is create a file that exports a function to run your benchmark in that folder and add that function to the index.ts
file. The yarn benchmarks
command can be run with no parameters (it will run all the benchmarks), or you can specify the name of your benchmark file to run just that. When you run the command it will create a benchmarks/results
folder with your results.
Incremental: Ideal for applications where you frequently add new elements and need to update the tree efficiently.
+Lean Incremental: A more memory-efficient version of the incremental Merkle tree.
+Sparse: Particularly useful when you need proof of non-membership.
+Type | +Library Name | +Main Feature | +Used by | +
---|---|---|---|
Incremental | +@zk-kit/imt | +Fastest for incremental updates. | +Semaphore V3, Worldcoin | +
Lean Incremental | +@zk-kit/lean-imt | +Optimized for lightweight environments. | +Semaphore V4, Zupass | +
Sparse | +@zk-kit/smt | +Handles very large sets efficiently. | +Iden3 | +
Following benchmarks data of zk-kit Merkle Trees implementations:
+8 leafs | +insert | +delete | +update | +generate proof | +verify proof | +
---|---|---|---|---|---|
fastest | +IMT | +IMT ~ SparseMT | +LeanIMT | +LeanIMT | +IMT | +
slowest | +LeanIMT | +IMT ~ SparseMT | +IMT | +SparseMT | +SparseMT | +
128 leafs | +insert | +delete | +update | +generate proof | +verify proof | +
---|---|---|---|---|---|
fastest | +IMT | +SparseMT | +LeanIMT | +LeanIMT | +SparseMT | +
slowest | +LeanIMT | +IMT | +IMT | +IMT | +IMT | +
1024 leafs | +insert | +delete | +update | +generate proof | +verify proof | +
---|---|---|---|---|---|
fastest | +SparseMT | +SparseMT | +LeanIMT | +LeanIMT | +SparseMT | +
slowest | +LeanIMT | +IMT | +IMT | +IMT | +IMT | +
From the benchmark data we can take another criteria to evaluate which Merkle tree should be used:
+Optional
matchingReadonly
BYTES_The size in bytes of each element in the array.
+Readonly
[toReadonly
bufferThe ArrayBuffer instance referenced by the array.
+Readonly
byteThe length in bytes of the array.
+Readonly
byteThe offset in bytes of the array.
+Readonly
lengthThe length of the array.
+Compares buf
with target
and returns a number indicating whether buf
comes before, after, or is the same as target
in sort order.
+Comparison is based on the actual sequence of bytes in each Buffer
.
0
is returned if target
is the same as buf
1
is returned if target
should come beforebuf
when sorted.-1
is returned if target
should come afterbuf
when sorted.import { Buffer } from 'node:buffer';
const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('BCD');
const buf3 = Buffer.from('ABCD');
console.log(buf1.compare(buf1));
// Prints: 0
console.log(buf1.compare(buf2));
// Prints: -1
console.log(buf1.compare(buf3));
// Prints: -1
console.log(buf2.compare(buf1));
// Prints: 1
console.log(buf2.compare(buf3));
// Prints: 1
console.log([buf1, buf2, buf3].sort(Buffer.compare));
// Prints: [ <Buffer 41 42 43>, <Buffer 41 42 43 44>, <Buffer 42 43 44> ]
// (This result is equal to: [buf1, buf3, buf2].)
+
+The optional targetStart
, targetEnd
, sourceStart
, and sourceEnd
arguments can be used to limit the comparison to specific ranges within target
and buf
respectively.
import { Buffer } from 'node:buffer';
const buf1 = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9]);
const buf2 = Buffer.from([5, 6, 7, 8, 9, 1, 2, 3, 4]);
console.log(buf1.compare(buf2, 5, 9, 0, 4));
// Prints: 0
console.log(buf1.compare(buf2, 0, 6, 4));
// Prints: -1
console.log(buf1.compare(buf2, 5, 6, 5));
// Prints: 1
+
+ERR_OUT_OF_RANGE
is thrown if targetStart < 0
, sourceStart < 0
, targetEnd > target.byteLength
, or sourceEnd > source.byteLength
.
A Buffer
or Uint8Array with which to compare buf
.
Optional
targetStart: numberThe offset within target
at which to begin comparison.
Optional
targetEnd: numberThe offset within target
at which to end comparison (not inclusive).
Optional
sourceStart: numberThe offset within buf
at which to begin comparison.
Optional
sourceEnd: numberThe offset within buf
at which to end comparison (not inclusive).
v0.11.13
+Copies data from a region of buf
to a region in target
, even if the target
memory region overlaps with buf
.
TypedArray.prototype.set()
performs the same operation, and is available
+for all TypedArrays, including Node.js Buffer
s, although it takes
+different function arguments.
import { Buffer } from 'node:buffer';
// Create two `Buffer` instances.
const buf1 = Buffer.allocUnsafe(26);
const buf2 = Buffer.allocUnsafe(26).fill('!');
for (let i = 0; i < 26; i++) {
// 97 is the decimal ASCII value for 'a'.
buf1[i] = i + 97;
}
// Copy `buf1` bytes 16 through 19 into `buf2` starting at byte 8 of `buf2`.
buf1.copy(buf2, 8, 16, 20);
// This is equivalent to:
// buf2.set(buf1.subarray(16, 20), 8);
console.log(buf2.toString('ascii', 0, 25));
// Prints: !!!!!!!!qrst!!!!!!!!!!!!!
+
+import { Buffer } from 'node:buffer';
// Create a `Buffer` and copy data from one region to an overlapping region
// within the same `Buffer`.
const buf = Buffer.allocUnsafe(26);
for (let i = 0; i < 26; i++) {
// 97 is the decimal ASCII value for 'a'.
buf[i] = i + 97;
}
buf.copy(buf, 0, 4, 10);
console.log(buf.toString());
// Prints: efghijghijklmnopqrstuvwxyz
+
+A Buffer
or Uint8Array to copy into.
Optional
targetStart: numberThe offset within target
at which to begin writing.
Optional
sourceStart: numberThe offset within buf
from which to begin copying.
Optional
sourceEnd: numberThe offset within buf
at which to stop copying (not inclusive).
The number of bytes copied.
+v0.1.90
+Returns the this object after copying a section of the array identified by start and end +to the same array starting at position target
+If target is negative, it is treated as length+target where length is the +length of the array.
+If start is negative, it is treated as length+start. If end is negative, it +is treated as length+end.
+Optional
end: numberIf not specified, length of the this object is used as its default value.
+Returns true
if both buf
and otherBuffer
have exactly the same bytes,false
otherwise. Equivalent to buf.compare(otherBuffer) === 0
.
import { Buffer } from 'node:buffer';
const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('414243', 'hex');
const buf3 = Buffer.from('ABCD');
console.log(buf1.equals(buf2));
// Prints: true
console.log(buf1.equals(buf3));
// Prints: false
+
+A Buffer
or Uint8Array with which to compare buf
.
v0.11.13
+Determines whether all the members of an array satisfy the specified test.
+A function that accepts up to three arguments. The every method calls +the predicate function for each element in the array until the predicate returns a value +which is coercible to the Boolean value false, or until the end of the array.
+Optional
thisArg: anyAn object to which the this keyword can refer in the predicate function. +If thisArg is omitted, undefined is used as the this value.
+Fills buf
with the specified value
. If the offset
and end
are not given,
+the entire buf
will be filled:
import { Buffer } from 'node:buffer';
// Fill a `Buffer` with the ASCII character 'h'.
const b = Buffer.allocUnsafe(50).fill('h');
console.log(b.toString());
// Prints: hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
// Fill a buffer with empty string
const c = Buffer.allocUnsafe(5).fill('');
console.log(c.fill(''));
// Prints: <Buffer 00 00 00 00 00>
+
+value
is coerced to a uint32
value if it is not a string, Buffer
, or
+integer. If the resulting integer is greater than 255
(decimal), buf
will be
+filled with value & 255
.
If the final write of a fill()
operation falls on a multi-byte character,
+then only the bytes of that character that fit into buf
are written:
import { Buffer } from 'node:buffer';
// Fill a `Buffer` with character that takes up two bytes in UTF-8.
console.log(Buffer.allocUnsafe(5).fill('\u0222'));
// Prints: <Buffer c8 a2 c8 a2 c8>
+
+If value
contains invalid characters, it is truncated; if no valid
+fill data remains, an exception is thrown:
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(5);
console.log(buf.fill('a'));
// Prints: <Buffer 61 61 61 61 61>
console.log(buf.fill('aazz', 'hex'));
// Prints: <Buffer aa aa aa aa aa>
console.log(buf.fill('zz', 'hex'));
// Throws an exception.
+
+The value with which to fill buf
. Empty value (string, Uint8Array, Buffer) is coerced to 0
.
Optional
offset: numberNumber of bytes to skip before starting to fill buf
.
Optional
end: numberWhere to stop filling buf
(not inclusive).
Optional
encoding: BufferEncodingThe encoding for value
if value
is a string.
A reference to buf
.
v0.5.0
+Returns the elements of an array that meet the condition specified in a callback function.
+A function that accepts up to three arguments. The filter method calls +the predicate function one time for each element in the array.
+Optional
thisArg: anyAn object to which the this keyword can refer in the predicate function. +If thisArg is omitted, undefined is used as the this value.
+Returns the value of the first element in the array where predicate is true, and undefined +otherwise.
+find calls predicate once for each element of the array, in ascending +order, until it finds one where predicate returns true. If such an element is found, find +immediately returns that element value. Otherwise, find returns undefined.
+Optional
thisArg: anyIf provided, it will be used as the this value for each invocation of +predicate. If it is not provided, undefined is used instead.
+Returns the index of the first element in the array where predicate is true, and -1 +otherwise.
+find calls predicate once for each element of the array, in ascending +order, until it finds one where predicate returns true. If such an element is found, +findIndex immediately returns that element index. Otherwise, findIndex returns -1.
+Optional
thisArg: anyIf provided, it will be used as the this value for each invocation of +predicate. If it is not provided, undefined is used instead.
+Performs the specified action for each element in an array.
+A function that accepts up to three arguments. forEach calls the +callbackfn function one time for each element in the array.
+Optional
thisArg: anyAn object to which the this keyword can refer in the callbackfn function. +If thisArg is omitted, undefined is used as the this value.
+Equivalent to buf.indexOf() !== -1
.
import { Buffer } from 'node:buffer';
const buf = Buffer.from('this is a buffer');
console.log(buf.includes('this'));
// Prints: true
console.log(buf.includes('is'));
// Prints: true
console.log(buf.includes(Buffer.from('a buffer')));
// Prints: true
console.log(buf.includes(97));
// Prints: true (97 is the decimal ASCII value for 'a')
console.log(buf.includes(Buffer.from('a buffer example')));
// Prints: false
console.log(buf.includes(Buffer.from('a buffer example').slice(0, 8)));
// Prints: true
console.log(buf.includes('this', 4));
// Prints: false
+
+What to search for.
+Optional
byteOffset: numberWhere to begin searching in buf
. If negative, then offset is calculated from the end of buf
.
Optional
encoding: BufferEncodingIf value
is a string, this is its encoding.
true
if value
was found in buf
, false
otherwise.
v5.3.0
+If value
is:
value
is interpreted according to the character encoding in encoding
.Buffer
or Uint8Array
, value
will be used in its entirety.
+To compare a partial Buffer
, use buf.subarray
.value
will be interpreted as an unsigned 8-bit integer
+value between 0
and 255
.import { Buffer } from 'node:buffer';
const buf = Buffer.from('this is a buffer');
console.log(buf.indexOf('this'));
// Prints: 0
console.log(buf.indexOf('is'));
// Prints: 2
console.log(buf.indexOf(Buffer.from('a buffer')));
// Prints: 8
console.log(buf.indexOf(97));
// Prints: 8 (97 is the decimal ASCII value for 'a')
console.log(buf.indexOf(Buffer.from('a buffer example')));
// Prints: -1
console.log(buf.indexOf(Buffer.from('a buffer example').slice(0, 8)));
// Prints: 8
const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'utf16le');
console.log(utf16Buffer.indexOf('\u03a3', 0, 'utf16le'));
// Prints: 4
console.log(utf16Buffer.indexOf('\u03a3', -4, 'utf16le'));
// Prints: 6
+
+If value
is not a string, number, or Buffer
, this method will throw a TypeError
. If value
is a number, it will be coerced to a valid byte value,
+an integer between 0 and 255.
If byteOffset
is not a number, it will be coerced to a number. If the result
+of coercion is NaN
or 0
, then the entire buffer will be searched. This
+behavior matches String.prototype.indexOf()
.
import { Buffer } from 'node:buffer';
const b = Buffer.from('abcdef');
// Passing a value that's a number, but not a valid byte.
// Prints: 2, equivalent to searching for 99 or 'c'.
console.log(b.indexOf(99.9));
console.log(b.indexOf(256 + 99));
// Passing a byteOffset that coerces to NaN or 0.
// Prints: 1, searching the whole buffer.
console.log(b.indexOf('b', undefined));
console.log(b.indexOf('b', {}));
console.log(b.indexOf('b', null));
console.log(b.indexOf('b', []));
+
+If value
is an empty string or empty Buffer
and byteOffset
is less
+than buf.length
, byteOffset
will be returned. If value
is empty andbyteOffset
is at least buf.length
, buf.length
will be returned.
What to search for.
+Optional
byteOffset: numberWhere to begin searching in buf
. If negative, then offset is calculated from the end of buf
.
Optional
encoding: BufferEncodingIf value
is a string, this is the encoding used to determine the binary representation of the string that will be searched for in buf
.
The index of the first occurrence of value
in buf
, or -1
if buf
does not contain value
.
v1.5.0
+Adds all the elements of an array separated by the specified separator string.
+Optional
separator: stringA string used to separate one element of an array from the next in the +resulting String. If omitted, the array elements are separated with a comma.
+Identical to buf.indexOf()
, except the last occurrence of value
is found
+rather than the first occurrence.
import { Buffer } from 'node:buffer';
const buf = Buffer.from('this buffer is a buffer');
console.log(buf.lastIndexOf('this'));
// Prints: 0
console.log(buf.lastIndexOf('buffer'));
// Prints: 17
console.log(buf.lastIndexOf(Buffer.from('buffer')));
// Prints: 17
console.log(buf.lastIndexOf(97));
// Prints: 15 (97 is the decimal ASCII value for 'a')
console.log(buf.lastIndexOf(Buffer.from('yolo')));
// Prints: -1
console.log(buf.lastIndexOf('buffer', 5));
// Prints: 5
console.log(buf.lastIndexOf('buffer', 4));
// Prints: -1
const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'utf16le');
console.log(utf16Buffer.lastIndexOf('\u03a3', undefined, 'utf16le'));
// Prints: 6
console.log(utf16Buffer.lastIndexOf('\u03a3', -5, 'utf16le'));
// Prints: 4
+
+If value
is not a string, number, or Buffer
, this method will throw a TypeError
. If value
is a number, it will be coerced to a valid byte value,
+an integer between 0 and 255.
If byteOffset
is not a number, it will be coerced to a number. Any arguments
+that coerce to NaN
, like {}
or undefined
, will search the whole buffer.
+This behavior matches String.prototype.lastIndexOf()
.
import { Buffer } from 'node:buffer';
const b = Buffer.from('abcdef');
// Passing a value that's a number, but not a valid byte.
// Prints: 2, equivalent to searching for 99 or 'c'.
console.log(b.lastIndexOf(99.9));
console.log(b.lastIndexOf(256 + 99));
// Passing a byteOffset that coerces to NaN.
// Prints: 1, searching the whole buffer.
console.log(b.lastIndexOf('b', undefined));
console.log(b.lastIndexOf('b', {}));
// Passing a byteOffset that coerces to 0.
// Prints: -1, equivalent to passing 0.
console.log(b.lastIndexOf('b', null));
console.log(b.lastIndexOf('b', []));
+
+If value
is an empty string or empty Buffer
, byteOffset
will be returned.
What to search for.
+Optional
byteOffset: numberWhere to begin searching in buf
. If negative, then offset is calculated from the end of buf
.
Optional
encoding: BufferEncodingIf value
is a string, this is the encoding used to determine the binary representation of the string that will be searched for in buf
.
The index of the last occurrence of value
in buf
, or -1
if buf
does not contain value
.
v6.0.0
+Calls a defined callback function on each element of an array, and returns an array that +contains the results.
+A function that accepts up to three arguments. The map method calls the +callbackfn function one time for each element in the array.
+Optional
thisArg: anyAn object to which the this keyword can refer in the callbackfn function. +If thisArg is omitted, undefined is used as the this value.
+Reads a signed, big-endian 64-bit integer from buf
at the specified offset
.
Integers read from a Buffer
are interpreted as two's complement signed
+values.
Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy: 0 <= offset <= buf.length - 8
.
v12.0.0, v10.20.0
+Reads a signed, little-endian 64-bit integer from buf
at the specifiedoffset
.
Integers read from a Buffer
are interpreted as two's complement signed
+values.
Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy: 0 <= offset <= buf.length - 8
.
v12.0.0, v10.20.0
+Reads an unsigned, big-endian 64-bit integer from buf
at the specifiedoffset
.
This function is also available under the readBigUint64BE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]);
console.log(buf.readBigUInt64BE(0));
// Prints: 4294967295n
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy: 0 <= offset <= buf.length - 8
.
v12.0.0, v10.20.0
+Reads an unsigned, little-endian 64-bit integer from buf
at the specifiedoffset
.
This function is also available under the readBigUint64LE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]);
console.log(buf.readBigUInt64LE(0));
// Prints: 18446744069414584320n
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy: 0 <= offset <= buf.length - 8
.
v12.0.0, v10.20.0
+Reads a 64-bit, big-endian double from buf
at the specified offset
.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
console.log(buf.readDoubleBE(0));
// Prints: 8.20788039913184e-304
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 8
.
v0.11.15
+Reads a 64-bit, little-endian double from buf
at the specified offset
.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
console.log(buf.readDoubleLE(0));
// Prints: 5.447603722011605e-270
console.log(buf.readDoubleLE(1));
// Throws ERR_OUT_OF_RANGE.
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 8
.
v0.11.15
+Reads a 32-bit, big-endian float from buf
at the specified offset
.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([1, 2, 3, 4]);
console.log(buf.readFloatBE(0));
// Prints: 2.387939260590663e-38
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 4
.
v0.11.15
+Reads a 32-bit, little-endian float from buf
at the specified offset
.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([1, 2, 3, 4]);
console.log(buf.readFloatLE(0));
// Prints: 1.539989614439558e-36
console.log(buf.readFloatLE(1));
// Throws ERR_OUT_OF_RANGE.
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 4
.
v0.11.15
+Reads a signed, big-endian 16-bit integer from buf
at the specified offset
.
Integers read from a Buffer
are interpreted as two's complement signed values.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0, 5]);
console.log(buf.readInt16BE(0));
// Prints: 5
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 2
.
v0.5.5
+Reads a signed, little-endian 16-bit integer from buf
at the specifiedoffset
.
Integers read from a Buffer
are interpreted as two's complement signed values.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0, 5]);
console.log(buf.readInt16LE(0));
// Prints: 1280
console.log(buf.readInt16LE(1));
// Throws ERR_OUT_OF_RANGE.
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 2
.
v0.5.5
+Reads a signed, big-endian 32-bit integer from buf
at the specified offset
.
Integers read from a Buffer
are interpreted as two's complement signed values.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0, 0, 0, 5]);
console.log(buf.readInt32BE(0));
// Prints: 5
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 4
.
v0.5.5
+Reads a signed, little-endian 32-bit integer from buf
at the specifiedoffset
.
Integers read from a Buffer
are interpreted as two's complement signed values.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0, 0, 0, 5]);
console.log(buf.readInt32LE(0));
// Prints: 83886080
console.log(buf.readInt32LE(1));
// Throws ERR_OUT_OF_RANGE.
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 4
.
v0.5.5
+Reads a signed 8-bit integer from buf
at the specified offset
.
Integers read from a Buffer
are interpreted as two's complement signed values.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([-1, 5]);
console.log(buf.readInt8(0));
// Prints: -1
console.log(buf.readInt8(1));
// Prints: 5
console.log(buf.readInt8(2));
// Throws ERR_OUT_OF_RANGE.
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 1
.
v0.5.0
+Reads byteLength
number of bytes from buf
at the specified offset
and interprets the result as a big-endian, two's complement signed value
+supporting up to 48 bits of accuracy.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
console.log(buf.readIntBE(0, 6).toString(16));
// Prints: 1234567890ab
console.log(buf.readIntBE(1, 6).toString(16));
// Throws ERR_OUT_OF_RANGE.
console.log(buf.readIntBE(1, 0).toString(16));
// Throws ERR_OUT_OF_RANGE.
+
+Number of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - byteLength
.
Number of bytes to read. Must satisfy 0 < byteLength <= 6
.
v0.11.15
+Reads byteLength
number of bytes from buf
at the specified offset
and interprets the result as a little-endian, two's complement signed value
+supporting up to 48 bits of accuracy.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
console.log(buf.readIntLE(0, 6).toString(16));
// Prints: -546f87a9cbee
+
+Number of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - byteLength
.
Number of bytes to read. Must satisfy 0 < byteLength <= 6
.
v0.11.15
+Reads an unsigned, big-endian 16-bit integer from buf
at the specifiedoffset
.
This function is also available under the readUint16BE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0x12, 0x34, 0x56]);
console.log(buf.readUInt16BE(0).toString(16));
// Prints: 1234
console.log(buf.readUInt16BE(1).toString(16));
// Prints: 3456
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 2
.
v0.5.5
+Reads an unsigned, little-endian 16-bit integer from buf
at the specified offset
.
This function is also available under the readUint16LE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0x12, 0x34, 0x56]);
console.log(buf.readUInt16LE(0).toString(16));
// Prints: 3412
console.log(buf.readUInt16LE(1).toString(16));
// Prints: 5634
console.log(buf.readUInt16LE(2).toString(16));
// Throws ERR_OUT_OF_RANGE.
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 2
.
v0.5.5
+Reads an unsigned, big-endian 32-bit integer from buf
at the specifiedoffset
.
This function is also available under the readUint32BE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78]);
console.log(buf.readUInt32BE(0).toString(16));
// Prints: 12345678
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 4
.
v0.5.5
+Reads an unsigned, little-endian 32-bit integer from buf
at the specifiedoffset
.
This function is also available under the readUint32LE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78]);
console.log(buf.readUInt32LE(0).toString(16));
// Prints: 78563412
console.log(buf.readUInt32LE(1).toString(16));
// Throws ERR_OUT_OF_RANGE.
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 4
.
v0.5.5
+Reads an unsigned 8-bit integer from buf
at the specified offset
.
This function is also available under the readUint8
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([1, -2]);
console.log(buf.readUInt8(0));
// Prints: 1
console.log(buf.readUInt8(1));
// Prints: 254
console.log(buf.readUInt8(2));
// Throws ERR_OUT_OF_RANGE.
+
+Optional
offset: numberNumber of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - 1
.
v0.5.0
+Reads byteLength
number of bytes from buf
at the specified offset
and interprets the result as an unsigned big-endian integer supporting
+up to 48 bits of accuracy.
This function is also available under the readUintBE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
console.log(buf.readUIntBE(0, 6).toString(16));
// Prints: 1234567890ab
console.log(buf.readUIntBE(1, 6).toString(16));
// Throws ERR_OUT_OF_RANGE.
+
+Number of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - byteLength
.
Number of bytes to read. Must satisfy 0 < byteLength <= 6
.
v0.11.15
+Reads byteLength
number of bytes from buf
at the specified offset
and interprets the result as an unsigned, little-endian integer supporting
+up to 48 bits of accuracy.
This function is also available under the readUintLE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0x12, 0x34, 0x56, 0x78, 0x90, 0xab]);
console.log(buf.readUIntLE(0, 6).toString(16));
// Prints: ab9078563412
+
+Number of bytes to skip before starting to read. Must satisfy 0 <= offset <= buf.length - byteLength
.
Number of bytes to read. Must satisfy 0 < byteLength <= 6
.
v0.11.15
+Calls the specified callback function for all the elements in an array. The return value of +the callback function is the accumulated result, and is provided as an argument in the next +call to the callback function.
+A function that accepts up to four arguments. The reduce method calls the +callbackfn function one time for each element in the array.
+Calls the specified callback function for all the elements in an array. The return value of +the callback function is the accumulated result, and is provided as an argument in the next +call to the callback function.
+A function that accepts up to four arguments. The reduce method calls the +callbackfn function one time for each element in the array.
+If initialValue is specified, it is used as the initial value to start +the accumulation. The first call to the callbackfn function provides this value as an argument +instead of an array value.
+Calls the specified callback function for all the elements in an array, in descending order. +The return value of the callback function is the accumulated result, and is provided as an +argument in the next call to the callback function.
+A function that accepts up to four arguments. The reduceRight method calls +the callbackfn function one time for each element in the array.
+Calls the specified callback function for all the elements in an array, in descending order. +The return value of the callback function is the accumulated result, and is provided as an +argument in the next call to the callback function.
+A function that accepts up to four arguments. The reduceRight method calls +the callbackfn function one time for each element in the array.
+If initialValue is specified, it is used as the initial value to start +the accumulation. The first call to the callbackfn function provides this value as an argument +instead of an array value.
+Returns a new Buffer
that references the same memory as the original, but
+offset and cropped by the start
and end
indices.
This method is not compatible with the Uint8Array.prototype.slice()
,
+which is a superclass of Buffer
. To copy the slice, useUint8Array.prototype.slice()
.
import { Buffer } from 'node:buffer';
const buf = Buffer.from('buffer');
const copiedBuf = Uint8Array.prototype.slice.call(buf);
copiedBuf[0]++;
console.log(copiedBuf.toString());
// Prints: cuffer
console.log(buf.toString());
// Prints: buffer
// With buf.slice(), the original buffer is modified.
const notReallyCopiedBuf = buf.slice();
notReallyCopiedBuf[0]++;
console.log(notReallyCopiedBuf.toString());
// Prints: cuffer
console.log(buf.toString());
// Also prints: cuffer (!)
+
+Optional
start: numberWhere the new Buffer
will start.
Optional
end: numberWhere the new Buffer
will end (not inclusive).
v0.3.0
+Use subarray
instead.
Determines whether the specified callback function returns true for any element of an array.
+A function that accepts up to three arguments. The some method calls +the predicate function for each element in the array until the predicate returns a value +which is coercible to the Boolean value true, or until the end of the array.
+Optional
thisArg: anyAn object to which the this keyword can refer in the predicate function. +If thisArg is omitted, undefined is used as the this value.
+Sorts an array.
+Optional
compareFn: ((a, b) => number)Function used to determine the order of the elements. It is expected to return +a negative value if first argument is less than second argument, zero if they're equal and a positive +value otherwise. If omitted, the elements are sorted in ascending order.
+[11,2,22,1].sort((a, b) => a - b)
+
+Returns a new Buffer
that references the same memory as the original, but
+offset and cropped by the start
and end
indices.
Specifying end
greater than buf.length
will return the same result as
+that of end
equal to buf.length
.
This method is inherited from TypedArray.prototype.subarray()
.
Modifying the new Buffer
slice will modify the memory in the original Buffer
because the allocated memory of the two objects overlap.
import { Buffer } from 'node:buffer';
// Create a `Buffer` with the ASCII alphabet, take a slice, and modify one byte
// from the original `Buffer`.
const buf1 = Buffer.allocUnsafe(26);
for (let i = 0; i < 26; i++) {
// 97 is the decimal ASCII value for 'a'.
buf1[i] = i + 97;
}
const buf2 = buf1.subarray(0, 3);
console.log(buf2.toString('ascii', 0, buf2.length));
// Prints: abc
buf1[0] = 33;
console.log(buf2.toString('ascii', 0, buf2.length));
// Prints: !bc
+
+Specifying negative indexes causes the slice to be generated relative to the
+end of buf
rather than the beginning.
import { Buffer } from 'node:buffer';
const buf = Buffer.from('buffer');
console.log(buf.subarray(-6, -1).toString());
// Prints: buffe
// (Equivalent to buf.subarray(0, 5).)
console.log(buf.subarray(-6, -2).toString());
// Prints: buff
// (Equivalent to buf.subarray(0, 4).)
console.log(buf.subarray(-5, -2).toString());
// Prints: uff
// (Equivalent to buf.subarray(1, 4).)
+
+Optional
start: numberWhere the new Buffer
will start.
Optional
end: numberWhere the new Buffer
will end (not inclusive).
v3.0.0
+Interprets buf
as an array of unsigned 16-bit integers and swaps the
+byte order in-place. Throws ERR_INVALID_BUFFER_SIZE
if buf.length
is not a multiple of 2.
import { Buffer } from 'node:buffer';
const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
console.log(buf1);
// Prints: <Buffer 01 02 03 04 05 06 07 08>
buf1.swap16();
console.log(buf1);
// Prints: <Buffer 02 01 04 03 06 05 08 07>
const buf2 = Buffer.from([0x1, 0x2, 0x3]);
buf2.swap16();
// Throws ERR_INVALID_BUFFER_SIZE.
+
+One convenient use of buf.swap16()
is to perform a fast in-place conversion
+between UTF-16 little-endian and UTF-16 big-endian:
import { Buffer } from 'node:buffer';
const buf = Buffer.from('This is little-endian UTF-16', 'utf16le');
buf.swap16(); // Convert to big-endian UTF-16 text.
+
+A reference to buf
.
v5.10.0
+Interprets buf
as an array of unsigned 32-bit integers and swaps the
+byte order in-place. Throws ERR_INVALID_BUFFER_SIZE
if buf.length
is not a multiple of 4.
import { Buffer } from 'node:buffer';
const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
console.log(buf1);
// Prints: <Buffer 01 02 03 04 05 06 07 08>
buf1.swap32();
console.log(buf1);
// Prints: <Buffer 04 03 02 01 08 07 06 05>
const buf2 = Buffer.from([0x1, 0x2, 0x3]);
buf2.swap32();
// Throws ERR_INVALID_BUFFER_SIZE.
+
+A reference to buf
.
v5.10.0
+Interprets buf
as an array of 64-bit numbers and swaps byte order in-place.
+Throws ERR_INVALID_BUFFER_SIZE
if buf.length
is not a multiple of 8.
import { Buffer } from 'node:buffer';
const buf1 = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]);
console.log(buf1);
// Prints: <Buffer 01 02 03 04 05 06 07 08>
buf1.swap64();
console.log(buf1);
// Prints: <Buffer 08 07 06 05 04 03 02 01>
const buf2 = Buffer.from([0x1, 0x2, 0x3]);
buf2.swap64();
// Throws ERR_INVALID_BUFFER_SIZE.
+
+A reference to buf
.
v6.3.0
+Returns a JSON representation of buf
. JSON.stringify()
implicitly calls
+this function when stringifying a Buffer
instance.
Buffer.from()
accepts objects in the format returned from this method.
+In particular, Buffer.from(buf.toJSON())
works like Buffer.from(buf)
.
import { Buffer } from 'node:buffer';
const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);
console.log(json);
// Prints: {"type":"Buffer","data":[1,2,3,4,5]}
const copy = JSON.parse(json, (key, value) => {
return value && value.type === 'Buffer' ?
Buffer.from(value) :
value;
});
console.log(copy);
// Prints: <Buffer 01 02 03 04 05>
+
+v0.9.2
+Decodes buf
to a string according to the specified character encoding inencoding
. start
and end
may be passed to decode only a subset of buf
.
If encoding
is 'utf8'
and a byte sequence in the input is not valid UTF-8,
+then each invalid byte is replaced with the replacement character U+FFFD
.
The maximum length of a string instance (in UTF-16 code units) is available +as constants.MAX_STRING_LENGTH.
+import { Buffer } from 'node:buffer';
const buf1 = Buffer.allocUnsafe(26);
for (let i = 0; i < 26; i++) {
// 97 is the decimal ASCII value for 'a'.
buf1[i] = i + 97;
}
console.log(buf1.toString('utf8'));
// Prints: abcdefghijklmnopqrstuvwxyz
console.log(buf1.toString('utf8', 0, 5));
// Prints: abcde
const buf2 = Buffer.from('tést');
console.log(buf2.toString('hex'));
// Prints: 74c3a97374
console.log(buf2.toString('utf8', 0, 3));
// Prints: té
console.log(buf2.toString(undefined, 0, 3));
// Prints: té
+
+Optional
encoding: BufferEncodingThe character encoding to use.
+Optional
start: numberThe byte offset to start decoding at.
+Optional
end: numberThe byte offset to stop decoding at (not inclusive).
+v0.1.90
+Writes string
to buf
at offset
according to the character encoding inencoding
. The length
parameter is the number of bytes to write. If buf
did
+not contain enough space to fit the entire string, only part of string
will be
+written. However, partially encoded characters will not be written.
import { Buffer } from 'node:buffer';
const buf = Buffer.alloc(256);
const len = buf.write('\u00bd + \u00bc = \u00be', 0);
console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`);
// Prints: 12 bytes: ½ + ¼ = ¾
const buffer = Buffer.alloc(10);
const length = buffer.write('abcd', 8);
console.log(`${length} bytes: ${buffer.toString('utf8', 8, 10)}`);
// Prints: 2 bytes : ab
+
+String to write to buf
.
Optional
encoding: BufferEncodingThe character encoding of string
.
Number of bytes written.
+v0.1.90
+Optional
encoding: BufferEncodingOptional
encoding: BufferEncodingWrites value
to buf
at the specified offset
as big-endian.
value
is interpreted and written as a two's complement signed integer.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(8);
buf.writeBigInt64BE(0x0102030405060708n, 0);
console.log(buf);
// Prints: <Buffer 01 02 03 04 05 06 07 08>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy: 0 <= offset <= buf.length - 8
.
offset
plus the number of bytes written.
v12.0.0, v10.20.0
+Writes value
to buf
at the specified offset
as little-endian.
value
is interpreted and written as a two's complement signed integer.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(8);
buf.writeBigInt64LE(0x0102030405060708n, 0);
console.log(buf);
// Prints: <Buffer 08 07 06 05 04 03 02 01>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy: 0 <= offset <= buf.length - 8
.
offset
plus the number of bytes written.
v12.0.0, v10.20.0
+Writes value
to buf
at the specified offset
as big-endian.
This function is also available under the writeBigUint64BE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(8);
buf.writeBigUInt64BE(0xdecafafecacefaden, 0);
console.log(buf);
// Prints: <Buffer de ca fa fe ca ce fa de>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy: 0 <= offset <= buf.length - 8
.
offset
plus the number of bytes written.
v12.0.0, v10.20.0
+Writes value
to buf
at the specified offset
as little-endian
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(8);
buf.writeBigUInt64LE(0xdecafafecacefaden, 0);
console.log(buf);
// Prints: <Buffer de fa ce ca fe fa ca de>
+
+This function is also available under the writeBigUint64LE
alias.
Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy: 0 <= offset <= buf.length - 8
.
offset
plus the number of bytes written.
v12.0.0, v10.20.0
+Writes value
to buf
at the specified offset
as big-endian. The value
must be a JavaScript number. Behavior is undefined when value
is anything
+other than a JavaScript number.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(8);
buf.writeDoubleBE(123.456, 0);
console.log(buf);
// Prints: <Buffer 40 5e dd 2f 1a 9f be 77>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 8
.
offset
plus the number of bytes written.
v0.11.15
+Writes value
to buf
at the specified offset
as little-endian. The value
must be a JavaScript number. Behavior is undefined when value
is anything
+other than a JavaScript number.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(8);
buf.writeDoubleLE(123.456, 0);
console.log(buf);
// Prints: <Buffer 77 be 9f 1a 2f dd 5e 40>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 8
.
offset
plus the number of bytes written.
v0.11.15
+Writes value
to buf
at the specified offset
as big-endian. Behavior is
+undefined when value
is anything other than a JavaScript number.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(4);
buf.writeFloatBE(0xcafebabe, 0);
console.log(buf);
// Prints: <Buffer 4f 4a fe bb>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 4
.
offset
plus the number of bytes written.
v0.11.15
+Writes value
to buf
at the specified offset
as little-endian. Behavior is
+undefined when value
is anything other than a JavaScript number.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(4);
buf.writeFloatLE(0xcafebabe, 0);
console.log(buf);
// Prints: <Buffer bb fe 4a 4f>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 4
.
offset
plus the number of bytes written.
v0.11.15
+Writes value
to buf
at the specified offset
as big-endian. The value
must be a valid signed 16-bit integer. Behavior is undefined when value
is
+anything other than a signed 16-bit integer.
The value
is interpreted and written as a two's complement signed integer.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(2);
buf.writeInt16BE(0x0102, 0);
console.log(buf);
// Prints: <Buffer 01 02>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 2
.
offset
plus the number of bytes written.
v0.5.5
+Writes value
to buf
at the specified offset
as little-endian. The value
must be a valid signed 16-bit integer. Behavior is undefined when value
is
+anything other than a signed 16-bit integer.
The value
is interpreted and written as a two's complement signed integer.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(2);
buf.writeInt16LE(0x0304, 0);
console.log(buf);
// Prints: <Buffer 04 03>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 2
.
offset
plus the number of bytes written.
v0.5.5
+Writes value
to buf
at the specified offset
as big-endian. The value
must be a valid signed 32-bit integer. Behavior is undefined when value
is
+anything other than a signed 32-bit integer.
The value
is interpreted and written as a two's complement signed integer.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(4);
buf.writeInt32BE(0x01020304, 0);
console.log(buf);
// Prints: <Buffer 01 02 03 04>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 4
.
offset
plus the number of bytes written.
v0.5.5
+Writes value
to buf
at the specified offset
as little-endian. The value
must be a valid signed 32-bit integer. Behavior is undefined when value
is
+anything other than a signed 32-bit integer.
The value
is interpreted and written as a two's complement signed integer.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(4);
buf.writeInt32LE(0x05060708, 0);
console.log(buf);
// Prints: <Buffer 08 07 06 05>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 4
.
offset
plus the number of bytes written.
v0.5.5
+Writes value
to buf
at the specified offset
. value
must be a valid
+signed 8-bit integer. Behavior is undefined when value
is anything other than
+a signed 8-bit integer.
value
is interpreted and written as a two's complement signed integer.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(2);
buf.writeInt8(2, 0);
buf.writeInt8(-2, 1);
console.log(buf);
// Prints: <Buffer 02 fe>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 1
.
offset
plus the number of bytes written.
v0.5.0
+Writes byteLength
bytes of value
to buf
at the specified offset
as big-endian. Supports up to 48 bits of accuracy. Behavior is undefined whenvalue
is anything other than a
+signed integer.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(6);
buf.writeIntBE(0x1234567890ab, 0, 6);
console.log(buf);
// Prints: <Buffer 12 34 56 78 90 ab>
+
+Number to be written to buf
.
Number of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - byteLength
.
Number of bytes to write. Must satisfy 0 < byteLength <= 6
.
offset
plus the number of bytes written.
v0.11.15
+Writes byteLength
bytes of value
to buf
at the specified offset
as little-endian. Supports up to 48 bits of accuracy. Behavior is undefined
+when value
is anything other than a signed integer.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(6);
buf.writeIntLE(0x1234567890ab, 0, 6);
console.log(buf);
// Prints: <Buffer ab 90 78 56 34 12>
+
+Number to be written to buf
.
Number of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - byteLength
.
Number of bytes to write. Must satisfy 0 < byteLength <= 6
.
offset
plus the number of bytes written.
v0.11.15
+Writes value
to buf
at the specified offset
as big-endian. The value
must be a valid unsigned 16-bit integer. Behavior is undefined when value
is anything other than an
+unsigned 16-bit integer.
This function is also available under the writeUint16BE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(4);
buf.writeUInt16BE(0xdead, 0);
buf.writeUInt16BE(0xbeef, 2);
console.log(buf);
// Prints: <Buffer de ad be ef>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 2
.
offset
plus the number of bytes written.
v0.5.5
+Writes value
to buf
at the specified offset
as little-endian. The value
must be a valid unsigned 16-bit integer. Behavior is undefined when value
is
+anything other than an unsigned 16-bit integer.
This function is also available under the writeUint16LE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(4);
buf.writeUInt16LE(0xdead, 0);
buf.writeUInt16LE(0xbeef, 2);
console.log(buf);
// Prints: <Buffer ad de ef be>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 2
.
offset
plus the number of bytes written.
v0.5.5
+Writes value
to buf
at the specified offset
as big-endian. The value
must be a valid unsigned 32-bit integer. Behavior is undefined when value
is anything other than an
+unsigned 32-bit integer.
This function is also available under the writeUint32BE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(4);
buf.writeUInt32BE(0xfeedface, 0);
console.log(buf);
// Prints: <Buffer fe ed fa ce>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 4
.
offset
plus the number of bytes written.
v0.5.5
+Writes value
to buf
at the specified offset
as little-endian. The value
must be a valid unsigned 32-bit integer. Behavior is undefined when value
is
+anything other than an unsigned 32-bit integer.
This function is also available under the writeUint32LE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(4);
buf.writeUInt32LE(0xfeedface, 0);
console.log(buf);
// Prints: <Buffer ce fa ed fe>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 4
.
offset
plus the number of bytes written.
v0.5.5
+Writes value
to buf
at the specified offset
. value
must be a
+valid unsigned 8-bit integer. Behavior is undefined when value
is anything
+other than an unsigned 8-bit integer.
This function is also available under the writeUint8
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(4);
buf.writeUInt8(0x3, 0);
buf.writeUInt8(0x4, 1);
buf.writeUInt8(0x23, 2);
buf.writeUInt8(0x42, 3);
console.log(buf);
// Prints: <Buffer 03 04 23 42>
+
+Number to be written to buf
.
Optional
offset: numberNumber of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - 1
.
offset
plus the number of bytes written.
v0.5.0
+Writes byteLength
bytes of value
to buf
at the specified offset
as big-endian. Supports up to 48 bits of accuracy. Behavior is undefined
+when value
is anything other than an unsigned integer.
This function is also available under the writeUintBE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(6);
buf.writeUIntBE(0x1234567890ab, 0, 6);
console.log(buf);
// Prints: <Buffer 12 34 56 78 90 ab>
+
+Number to be written to buf
.
Number of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - byteLength
.
Number of bytes to write. Must satisfy 0 < byteLength <= 6
.
offset
plus the number of bytes written.
v0.5.5
+Writes byteLength
bytes of value
to buf
at the specified offset
as little-endian. Supports up to 48 bits of accuracy. Behavior is undefined
+when value
is anything other than an unsigned integer.
This function is also available under the writeUintLE
alias.
import { Buffer } from 'node:buffer';
const buf = Buffer.allocUnsafe(6);
buf.writeUIntLE(0x1234567890ab, 0, 6);
console.log(buf);
// Prints: <Buffer ab 90 78 56 34 12>
+
+Number to be written to buf
.
Number of bytes to skip before starting to write. Must satisfy 0 <= offset <= buf.length - byteLength
.
Number of bytes to write. Must satisfy 0 < byteLength <= 6
.
offset
plus the number of bytes written.
v0.5.5
++
A JavaScript library for adding points to the Baby Jubjub curve.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +++[!NOTE]
+
This library has been audited as part of the Semaphore V4 PSE audit: https://semaphore.pse.dev/Semaphore_4.0.0_Audit.pdf.
BabyJubJub is an elliptic curve optimized for secure, efficient cryptographic operations in constrained environments like blockchain and zero-knowledge proofs. It's designed for fast, privacy-preserving transactions, balancing cryptographic strength with performance, making it ideal for modern cryptographic solutions.
+Install the @zk-kit/baby-jubjub
package and its peer dependencies with npm:
npm i @zk-kit/baby-jubjub
+
+or yarn:
+yarn add @zk-kit/baby-jubjub
+
+You can also load it using a script
tag using unpkg:
<script src="https://unpkg.com/@zk-kit/baby-jubjub"></script>
+
+or JSDelivr:
+<script src="https://cdn.jsdelivr.net/npm/@zk-kit/baby-jubjub"></script>
+
+import { packPoint, unpackPoint, Base8, mulPointEscalar, Point, addPoint } from "@zk-kit/baby-jubjub"
// Define two points on the BabyJubJub curve.
const p1: Point<bigint> = [BigInt(0), BigInt(1)] // Point at infinity (neutral element).
const p2: Point<bigint> = [BigInt(1), BigInt(0)] // Example point.
// Add the two points on the curve.
const p3 = addPoint(p1, p2)
// Add the result with Base8, another point on the curve, to get a new point.
const secretScalar = addPoint(Base8, p3)
// Multiply the base point by the x-coordinate of the secret scalar to get the public key.
const publicKey = mulPointEscalar(Base8, secretScalar[0])
// Pack the public key into a compressed format.
const packedPoint = packPoint(publicKey)
// Unpack the compressed public key back into its original form.
const unpackedPoint = unpackPoint(packedPoint)
if (unpackedPoint) {
console.log(publicKey[0] === unpackedPoint[0]) // true, checks if x-coordinates match
console.log(publicKey[1] === unpackedPoint[1]) // true, checks if y-coordinates match
}
+
++
A JavaScript EdDSA library for secure signing and verification using Poseidon and the Baby Jubjub elliptic curve.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +This package offers a simplified JavaScript codebase essential for creating and validating digital signatures using EdDSA and Poseidon. It's built upon the Baby Jubjub elliptic curve, ensuring seamless integration with Circom and enhancing the developer experience. | +
---|
++[!NOTE]
+
This library has been audited as part of the Semaphore V4 PSE audit: https://semaphore.pse.dev/Semaphore_4.0.0_Audit.pdf.
👾 Would you like to try it now? Explore it now on Ceditor!
+Install the @zk-kit/eddsa-poseidon
package and its peer dependencies with npm:
npm i @zk-kit/eddsa-poseidon
+
+or yarn:
+yarn add @zk-kit/eddsa-poseidon
+
+You can also load it using a script
tag using unpkg:
<script src="https://unpkg.com/@zk-kit/eddsa-poseidon"></script>
+
+or JSDelivr:
+<script src="https://cdn.jsdelivr.net/npm/@zk-kit/eddsa-poseidon"></script>
+
+The public key is generated using BLAKE by default and BLAKE2 if specified in the import as follows: import { ... } from "@zk-kit/eddsa-poseidon/blake-2b"
.
import {
derivePublicKey,
signMessage,
verifySignature,
deriveSecretScalar,
packPublicKey,
unpackPublicKey
} from "@zk-kit/eddsa-poseidon"
// Your private key (secret).
const privateKey = "secret"
// The message you want to sign.
const message = "message"
// Derive a public key from the private key.
const publicKey = derivePublicKey(privateKey)
/*
[
17191193026255111087474416516591393721975640005415762645730433950079177536248n,
13751717961795090314625781035919035073474308127816403910435238282697898234143n
]
*/
console.log(publicKey)
// Sign the message.
const signature = signMessage(privateKey, message)
/*
{
R8: [
12949573675545142400102669657964360005184873166024880859462384824349649539693n,
18253636630408169174294927826710424418689461166073329946402765380454102840608n
],
S: 701803947557694254685424075312408605924670918868054593580245088593184746870n
}
*/
console.log(signature)
const response = verifySignature(message, signature, publicKey)
// true.
console.log(response)
// Use this value as the input for your Circom circuit.
const secretScalar = deriveSecretScalar(privateKey)
/*
6544992227624943856419766050818315045047569225455760139072025985369615672473
14277921624107172450683599157880963081763136590946434672207840996093731170206
*/
console.log(secretScalar)
// Pack the public key into a compressed format.
const packedPublicKey = packPublicKey(publicKey)
// 52359937820999550851358128406546520360380553803646081112576207882956925379784n
console.log(packedPublicKey)
// Unpack the compressed public key back into its original form.
const unpackedPublicKey = unpackPublicKey(packedPublicKey)
/*
[
17191193026255111087474416516591393721975640005415762645730433950079177536248n,
13751717961795090314625781035919035073474308127816403910435238282697898234143n
]
*/
console.log(unpackedPublicKey)
if (unpackedPublicKey) {
console.log(publicKey[0] === unpackedPublicKey[0]) // true
console.log(publicKey[1] === unpackedPublicKey[1]) // true
}
+
++
Incremental Merkle tree implementation in TypeScript.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +++[!WARNING]
+
If you are looking for the first version of this package, please visit this link.
In this implementation, the tree is built with a predetermined depth, utilizing a list of zeros (one for each level) to hash nodes lacking fully defined children. The tree's branching factor, or the number of children per node, can be customized via the arity parameter. For detailed insights into the implementation specifics, please refer to the technical documentation.
+Install the @zk-kit/imt
package with npm:
npm i @zk-kit/imt --save
+
+or yarn:
+yarn add @zk-kit/imt
+
+You can also load it using a script
tag using unpkg:
<script src="https://unpkg.com/@zk-kit/imt"></script>
+
+or JSDelivr:
+<script src="https://cdn.jsdelivr.net/npm/@zk-kit/imt"></script>
+
+import { IMT } from "@zk-kit/imt"
import { poseidon2 } from "poseidon-lite"
/**
* depth: number of nodes from the leaf to the tree's root node.
* zeroValue: default zero, can vary based on the specific use-case.
* arity: number of children per node (2 = Binary IMT, 5 = Quinary IMT).
*/
const depth = 16
const zeroValue = 0
const arity = 2
/**
* To create an instance of an IMT, you need to provide the hash function
* used to compute the tree nodes, as well as the depth, zeroValue, and arity of the tree.
*/
const tree = new IMT(poseidon2, depth, zeroValue, arity)
// You can also initialize a tree with a given list of leaves.
// const leaves = [1, 2, 3]
// new IMT(poseidon2, depth, zeroValue, arity, leaves)
// Insert (incrementally) a leaf with a value of 1.
tree.insert(1)
// Insert (incrementally) a leaf with a value of 3.
tree.insert(3)
// 6176938709541216276071057251289703345736952331798983957780950682673395007393n.
console.log(tree.root)
/*
[
0,
14744269619966411208579211824598458697587494354926760081771325075741142829156n,
7423237065226347324353380772367382631490014989348495481811164164159255474657n,
11286972368698509976183087595462810875513684078608517520839298933882497716792n,
3607627140608796879659380071776844901612302623152076817094415224584923813162n,
19712377064642672829441595136074946683621277828620209496774504837737984048981n,
20775607673010627194014556968476266066927294572720319469184847051418138353016n,
3396914609616007258851405644437304192397291162432396347162513310381425243293n,
21551820661461729022865262380882070649935529853313286572328683688269863701601n,
6573136701248752079028194407151022595060682063033565181951145966236778420039n,
12413880268183407374852357075976609371175688755676981206018884971008854919922n,
14271763308400718165336499097156975241954733520325982997864342600795471836726n,
20066985985293572387227381049700832219069292839614107140851619262827735677018n,
9394776414966240069580838672673694685292165040808226440647796406499139370960n,
11331146992410411304059858900317123658895005918277453009197229807340014528524n,
15819538789928229930262697811477882737253464456578333862691129291651619515538n
]
*/
console.log(tree.zeroes)
// 2
console.log(tree.arity)
// 16
console.log(tree.depth)
// [1, 3]
console.log(tree.leaves)
// Get the index of the leaf with value 3.
const idx = tree.indexOf(3)
// 1
console.log(idx)
// Update the value of the leaf at position 1 to 2.
tree.update(1, 2)
// [1, 2]
console.log(tree.leaves)
// Delete leaf at position 1.
tree.delete(1)
// [1, 0]
console.log(tree.leaves)
/**
* Compute a Merkle Inclusion Proof (proof of membership) for the leaf with index 1.
* The proof is only valid if the value 1 is found in a leaf of the tree.
*/
const proof = tree.createProof(1)
// true
console.log(tree.verifyProof(proof))
+
++
LazyTower implementation in TypeScript.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +This library has not been audited.
+Install the @zk-kit/lazytower
package with npm:
npm i @zk-kit/lazytower --save
+
+or yarn:
+yarn add @zk-kit/lazytower
+
+You can also load it using a script
tag using unpkg:
<script src="https://unpkg.com/@zk-kit/lazytower/"></script>
+
+or JSDelivr:
+<script src="https://cdn.jsdelivr.net/npm/@zk-kit/lazytower/"></script>
+
+import { LazyTowerHashChainProofBuilder } from "@zk-kit/lazytower"
import { poseidon } from "circomlibjs" // v0.0.8
const H = 10
const W = 4
const pb = LazyTowerHashChainProofBuilder(H, W, poseidon)
for (let i = BigInt(0); i < 150; i += BigInt(1)) {
pb.add(i)
}
const index = pb.indexOf(BigInt(42))
const proof = pb.build(index)
console.log(proof)
+
++
Lean Incremental Merkle tree implementation in TypeScript.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +++[!NOTE]
+
This library has been audited as part of the Semaphore V4 PSE audit: https://semaphore.pse.dev/Semaphore_4.0.0_Audit.pdf.
The LeanIMT is an optimized binary version of the IMT into binary-focused model, eliminating the need for zero values and allowing dynamic depth adjustment. Unlike the IMT, which uses a zero hash for incomplete nodes, the LeanIMT directly adopts the left child's value when a node lacks a right counterpart. The tree's depth dynamically adjusts to the count of leaves, enhancing efficiency by reducing the number of required hash calculations. To understand more about the LeanIMT, take a look at this visual explanation. For detailed insights into the implementation specifics, please refer to the technical documentation.
+Install the @zk-kit/lean-imt
package with npm:
npm i @zk-kit/lean-imt --save
+
+or yarn:
+yarn add @zk-kit/lean-imt
+
+You can also load it using a script
tag using unpkg:
<script src="https://unpkg.com/@zk-kit/lean-imt"></script>
+
+or JSDelivr:
+<script src="https://cdn.jsdelivr.net/npm/@zk-kit/lean-imt"></script>
+
+import { LeanIMT } from "@zk-kit/lean-imt"
import { poseidon2 } from "poseidon-lite"
// Hash function used to compute the tree nodes.
const hash = (a, b) => poseidon2([a, b])
// To create an instance of a LeanIMT, you must provide the hash function.
const tree = new LeanIMT(hash)
// You can also initialize a tree with a given list of leaves.
// const leaves = [1n, 2n, 3n]
// new LeanIMT(hash, leaves)
// LeanIMT is strictly typed. Default type for nodes is 'bigint',
// but you can set your own type.
// new LeanIMT<number>((a, b) => a + b)
// Insert (incrementally) a leaf with a value of 1.
tree.insert(1n)
// [1n]
console.log(tree.leaves)
// Insert (incrementally) a leaf with a value of 3.
tree.insert(3n)
// 21106761926285267690763443010820487107972411248208546226053195422384279971821n
console.log(tree.root)
// 1
console.log(tree.depth)
// 2
console.log(tree.size)
// [1n, 3n]
console.log(tree.leaves)
// Get the index of the leaf with value 3n.
const idx = tree.indexOf(3n)
// 1
console.log(idx)
// Check if the tree contains a leaf with value 4n.
const has = tree.has(4n)
// false
console.log(tree.has(4n))
// Update the value of the leaf at position 1 to 2n.
tree.update(1, 2n)
// [1n, 2n]
console.log(tree.leaves)
// If you want to delete a leaf with LeanIMT you can use the update function with an
// arbitrary value to be used for the removed leaves.
// Update the value of the leaf at position 1 to 0n (deletion).
tree.update(1, 0n)
// [1n, 0n]
console.log(tree.leaves)
// Compute a Merkle Inclusion Proof (proof of membership) for the leaf with index 1.
// The proof is only valid if the value 1 is found in a leaf of the tree.
const proof = tree.generateProof(1)
// true
console.log(tree.verifyProof(proof))
// Export all the tree nodes.
const nodes = tree.export()
// Import the nodes.
const tree2 = LeanIMT.import(hash, nodes)
// Node types are converted from strings to bigints by default.
// The third parameter can be used to convert strings to other types.
// Import the nodes converting their types to numbers.
const tree3 = LeanIMT.import<number>(hash, nodes, Number)
+
++
A library to evaluate logical expressions.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +This library facilitates the work with logical (boolean) expressions. It allows you to tokenize and evaluate any logical expression. It supports the use of parentheses. | +
---|
Install the @zk-kit/logical-expressions
package with npm:
npm i @zk-kit/logical-expressions
+
+or yarn:
+yarn add @zk-kit/logical-expressions
+
+You can also load it using a script
tag using unpkg:
<script src="https://unpkg.com/@zk-kit/logical-expressions"></script>
+
+or JSDelivr:
+<script src="https://cdn.jsdelivr.net/npm/@zk-kit/logical-expressions"></script>
+
+Supported logical operators: and
, or
, not
, xor
.
All other existing logical operators (nand
, nor
, xnor
) can be generated using the supported logical operators.
# tokenize(): string[]
+Tokenizes a logical (boolean) expression. +Splits the expression into meaningful tokens.
+import { tokenize } from "@zk-kit/logical-expressions"
const expression = "true and false or ( true and true )"
const tokens = tokenize(expression)
console.log(tokens)
// Output: ["true", "and", "false", "or", "(", "true", "and", "true", ")"]
+
+# precedence(): number
+Returns the precedence of a logical operator. If the operator is not supported, the precedence will be 0.
+import { precedence } from "@zk-kit/logical-expressions"
const result = precedence("and")
console.log(result) // Output: 1
+
+# applyOperator(): boolean
+Applies unary or binary operators to boolean values.
+import { applyOperator } from "@zk-kit/logical-expressions"
// Unary operator
const result1 = applyOperator("not", true)
console.log(result1) // Output: false
// Binary operator
const result2 = applyOperator("and", true, false)
console.log(result2) // Output: false
+
+# evaluate(): boolean
+Evaluates a tokenized logical (boolean) expression.
+There is no need to verify the correctness of the logical expression before calling the evaluate function, as this will be checked during the evaluation. If the expression is incorrect, an error will be thrown automatically.
+Example of correct logical expression: "true and false"
.
Example of incorrect logical expression: "true true and false"
.
import { evaluate } from "@zk-kit/logical-expressions"
const expression = ["true", "and", "false"]
const result = evaluate(expression)
console.log(result) // Output: false
+
++
Poseidon Hash function Encryption and Decryption implementation in TypeScript.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +This package implements encryption and decryption using the Poseidon hash function. This is a rewrite of the original implementation.
+You can install @zk-kit/poseidon-cipher
package with npm:
npm i @zk-kit/poseidon-cipher --save
+
+or yarn:
+yarn add @zk-kit/poseidon-cipher
+
+You can also load it using a script
tag using unpkg:
<script src="https://unpkg.com/@zk-kit/poseidon-cipher"></script>
+
+or JSDelivr:
+<script src="https://cdn.jsdelivr.net/npm/@zk-kit/poseidon-cipher"></script>
+
+import { poseidonEncrypt, poseidonDecrypt, poseidonDecryptWithoutCheck } from "@zk-kit/poseidon-cipher"
// BabyJubJub random value used as private key.
const privateKey = BigInt("10108149867830299554549347844489388280570828384194562713227904027271736843407")
console.log(privateKey)
// The BabyJubJub public key derived from the private key.
const publicKey = [
BigInt("15100511232447817691325643662379962541629809665246870882117771367990737816375"),
BigInt("16289853525630400225782441139722681929418024277641315637394850958390724375621")
]
/**
[
15100511232447817691325643662379962541629809665246870882117771367990737816375n,
16289853525630400225782441139722681929418024277641315637394850958390724375621n
]
*/
console.log(publicKey)
/**
* The Elliptic-Curve Diffie–Hellman (ECDH) shared key from the private and public key.
* Learn more at https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman.
*/
const encryptionKey = [
BigInt("18215233274609902892566361706948385597370728108990013889912246034099844508236"),
BigInt("14884395706232754242497822954958766875005771827082919466711779658153477561231")
]
/**
[
18215233274609902892566361706948385597370728108990013889912246034099844508236n,
14884395706232754242497822954958766875005771827082919466711779658153477561231n
]
*/
console.log(encryptionKey)
// The plaintext to be encrypted.
const plainText = [BigInt(0), BigInt(1)]
// The unique random value.
const nonce = BigInt(5)
// Compute the encryption.
const encrypted = poseidonEncrypt(plainText, encryptionKey, nonce)
/*
[
13027563531333274777964504528445510545245985419061604793949748860800093661040n,
21542829407417339379457427303368865281142518080970543920113508599380643597111n,
334052772696549592017166610161467257195783602071397160212931200489386609812n,
9075054520224362422769554641603717496449971372103870041485347221024944155182n
]
*/
console.log(encrypted)
// Compute the decryption.
const decrypted = poseidonDecrypt(encrypted, encryptionKey, nonce, plainText.length)
/*
[
0n,
1n
]
*/
console.log(decrypted)
// Compute the decryption without check.
const decryptedWithoutCheck = poseidonDecryptWithoutCheck(encrypted, encryptionKey, nonce, plainText.length)
/*
[
0n,
1n
]
*/
console.log(decryptedWithoutCheck)
+
++
A library to generate and verify Poseidon proofs.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +This zero-knowledge library facilitates the demonstration of having a Poseidon hash pre-image while keeping the pre-image value confidential. Additionally, it offers a mechanism to prevent the same proof from being reused. The circuit that forms the foundation of this library is accessible via this link. | +
---|
Originally developed for integration with Semaphore V4, this library also functions effectively as a standalone tool. Notable use cases in connection with Semaphore can be:
+The Snark artifacts (.wasm
and .zkey
files) can be specified or not in the generate
function parameters and can possibly be downloaded using the following URLs:
++[!WARNING]
+
The Snark artifacts currently used to generate zero-knowledge proofs are the result of an insecure trusted setup, and the library has not yet been audited. Therefore, it is advised not to use it in production.
Install the @zk-kit/poseidon-proof
package:
npm i @zk-kit/poseidon-proof
+
+or yarn:
+yarn add @zk-kit/poseidon-proof
+
+import { generate, verify } from "@zk-kit/poseidon-proof"
// A public value used to contextualize the cryptographic proof and calculate the nullifier.
const scope = "scope"
// The message (preimage) to prove (secret).
const messages = [1, 2]
// Generate the proof.
const fullProof = await generate(messages, scope)
/*
nb. scope, digest and nullifier are always the same - proof is variable.
{
scope: '2',
digest: '13713635907739611880977640264956372443229506353728466835599871320028961887800',
nullifier: '4995263610384888704435371233168916617325583088652670186865584118891394144999',
proof: [
'4344680442683455359115899095464919042642166233886432616638435348359080260980',
'20569010229031596977566212621532395450352277701036306316464269899598925981651',
'19318221594436336163085169568471746851468100277321435282188061183430353155289',
'13863222659316400652438453097923451250965656325472339120118358727133180331649',
'2718553541880998786976126630362604850217726344847462841516918030540821216281',
'11960084231774590415377471656397863783771599717615252119734899677642065267169',
'10666072962579546268534775428261696356732715643486735369393626224913301307278',
'4251217137130113647513155953595492143724626859298741948572817563032672674599'
]
}
*/
console.log(fullProof)
// If not specified, the Snark artifacts are downloaded automatically.
// You can specify them as follows.
// const fullProof = await generate(message, scope, {
// wasm: "<your-path>/poseidon-proof.wasm",
// zkey: "<your-path>/poseidon-proof.zkey"
// })
// Verify the proof.
const response = await verify(fullProof)
// true.
console.log(response)
// Eventually you may want to check the nullifier.
+
+Benchmarks were run on an Intel Core i7-1165G7, 16 GB RAM machine (with two inputs).
+Generate proof | +Verify proof | +Constraints | +
---|---|---|
170ms |
+12ms |
+214 |
+
import { generate, verify } from "@zk-kit/poseidon-proof"
console.time("generate")
const proof = await generate([1, 2], "scope")
console.timeEnd("generate")
console.time("verify")
console.log(await verify(proof))
console.timeEnd("verify")
+
++
Sparse Merkle tree implementation in TypeScript.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +A sparse Merkle tree is a data structure useful for storing a key/value map where every leaf node of the tree contains the cryptographic hash of a key/value pair and every non leaf node contains the concatenated hashes of its child nodes. Sparse Merkle trees provides a secure and efficient verification of large data sets and they are often used in peer-to-peer technologies. This implementation is an optimized version of the traditional sparse Merkle tree and it is based on the concepts expressed in the papers and resources below.
+You can install @zk-kit/smt
package with npm:
npm i @zk-kit/smt --save
+
+or yarn:
+yarn add @zk-kit/smt
+
+You can also load it using a script
tag using unpkg:
<script src="https://unpkg.com/@zk-kit/smt"></script>
+
+or JSDelivr:
+<script src="https://cdn.jsdelivr.net/npm/@zk-kit/smt"></script>
+
+import { ChildNodes, SMT } from "@zk-kit/smt"
import sha256 from "crypto-js/sha256"
import { poseidon2, poseidon3 } from "poseidon-lite"
// Hexadecimal hashes.
const hash = (childNodes: ChildNodes) => sha256(childNodes.join("")).toString()
// Create the SMT with an Hexadecimal (SHA256) hash.
const tree = new SMT(hash)
// 0
console.log(tree.root)
// Big number hashes.
const hash2 = (childNodes) => (childNodes.length === 2 ? poseidon2(childNodes) : poseidon3(childNodes))
// Create the SMT with a BigNumber (Poseidon) hash.
const tree2 = new SMT(hash2, true)
// 0n
console.log(tree2.root)
// Add nodes to the SMT.
tree.add("2b", "44")
tree.add("16", "78")
tree.add("d", "e7")
tree.add("10", "141")
tree.add("20", "340")
// 31ee2a59741c9c32a32d8c7fafe461cca1ccaf5986c2d592586e3e6482a48645
console.log(tree.root)
// Get the value of the leaf.
const value = tree.get("16")
// 78
console.log(value)
// Update the value of the leaf.
tree.update("16", "79")
// 79
console.log(tree.get("16"))
// Delete the leaf.
tree.delete("16")
// undefined
console.log(tree.get("16"))
// Compute the proof of membership for the leaf.
const membershipProof = tree.createProof("2b")
// Compute the proof of membership for a previously deleted leaf.
const nonMembershipProof = tree.createProof("16") // This key has been deleted.
/*
{
entry: [ '2b', '44', '1' ],
matchingEntry: undefined,
siblings: [
'006a0ab15a212e0e0126b81e056b11576628b1ad80792403dbb3a90be2e71d64',
'f786ce5a843614d7da216d95c0087c1eb29244927feeeeeb658aa60cf124cd5e'
],
root: 'c3c023c84afc0a7bab1dbebcef5f7beaf3d6af4af98e8f481620dec052be7d0d',
membership: true
}
*/
console.log(membershipProof)
/*
{
entry: [ '16' ],
matchingEntry: undefined,
siblings: [
'960f23d9fbb44241be53efb7c4d69ac129bb1cb9482dcb6789d3cc7e6de2de2b',
'2a1aef839e68d1bdf43c1b3b1ed9ef16c27162e8a175898c9ac64a679b0fc825'
],
root: 'c3c023c84afc0a7bab1dbebcef5f7beaf3d6af4af98e8f481620dec052be7d0d',
membership: false
}
*/
console.log(nonMembershipProof)
// Verify the proofs.
console.log(tree.verifyProof(membershipProof)) // true
console.log(tree.verifyProof(nonMembershipProof)) // true
+
++
Essential zero-knowledge utility library for JavaScript developers.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +++[!NOTE]
+
This library has been audited as part of the Semaphore V4 PSE audit: https://semaphore.pse.dev/Semaphore_4.0.0_Audit.pdf.
Install the @zk-kit/utils
package and its peer dependencies with npm:
npm i @zk-kit/utils
+
+or yarn:
+yarn add @zk-kit/utils
+
+You can also load it using a script
tag using unpkg:
<script src="https://unpkg.com/@zk-kit/utils"></script>
+
+or JSDelivr:
+<script src="https://cdn.jsdelivr.net/npm/@zk-kit/utils"></script>
+
+// You can import modules from the main bundle.
import { errorHandlers, typeChecks } from "@zk-kit/utils"
// Or by using conditional exports.
import { requireNumber } from "@zk-kit/utils/error-handlers"
import { isNumber } from "@zk-kit/utils/type-checks"
+
+For more information on the functions provided by @zk-kit/utils
, please refer to the documentation.
The Merkle Proof contains the necessary parameters to enable the +verifier to be certain that a leaf belongs to the tree. Given the value +of the leaf and its index, it is possible to traverse the tree by +recalculating the hashes up to the root and using the node siblings. +If the calculated root matches the root in the proof, then the leaf +belongs to the tree. It's important to note that the function used +to generate the proof and the one used to verify it must use the +same hash function.
+It represents a node of the tree, which can be any value.
+The Merkle Proof contains the necessary parameters to enable the +verifier to be certain that a leaf belongs to the tree. Given the value +of the leaf and its index, it is possible to traverse the tree by +recalculating the hashes up to the root and using the node siblings. +If the calculated root matches the root in the proof, then the leaf +belongs to the tree. It's important to note that the function used +to generate the proof and the one used to verify it must use the +same hash function.
+Const
Const
Const
Const
Constants and curve parameters for BabyJubJub elliptic curve operations. +See: https://eips.ethereum.org/EIPS/eip-2494
+Const
Const
Const
Const
Internal
An IMT (aka Incremental Merkle Tree) is a type of data structure used in cryptography and +computer science for efficiently verifying the integrity of a large set of data, +especially in situations where new data is added over time. It is based on the concept +of a Merkle tree, and its key feature is its ability to efficiently update the tree +when new data is added or existing data is modified. +In this implementation, the tree is constructed using a fixed IMT#depth +value, and a list of IMT#zeroes (one for each level) is used to compute the +hash of a node when not all of its children are defined. The number of children for each +node can also be specified with the IMT#arity parameter.
+