Initializes a new instance, deriving necessary cryptographic parameters from the provided private key. +If the private key is not passed as a parameter, a random 32-byte hexadecimal key is generated.
+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 signing and public key derivation.
+Signs a given message using the private key and returns the signature.
+The message to be signed.
+The signature of the message.
+Verifies a signature against a message and the public key stored in this instance.
+The message whose signature is to be verified.
+The signature to be verified.
+True if the signature is valid for the message and public key, false otherwise.
+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.
+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 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. +The tree must be empty before importing.
+The stringified JSON of the tree.
+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.
+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
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 secret scalar from a given EdDSA private key.
+This process involves hashing the private key with Blake1, pruning the resulting hash to retain the lower 32 bytes, +and converting it into a little-endian integer. The use of the secret scalar streamlines the public key generation +process by omitting steps 1, 2, and 3 as outlined in RFC 8032 section 5.1.5, enhancing circuit efficiency and simplicity. +This method is crucial for fixed-base scalar multiplication operations within the correspondent cryptographic circuit. +For detailed steps, see: https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.5. +For example usage in a circuit, see: https://github.com/semaphore-protocol/semaphore/blob/2c144fc9e55b30ad09474aeafa763c4115338409/packages/circuits/semaphore.circom#L21
+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 EdDSA private key for generating the associated public key.
+The derived secret scalar to be used to calculate public key and optimized for circuit calculations.
+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.
+Creates a zero-knowledge proof to prove that you have the pre-image of a Semaphore commitment, +without disclosing the actual preimage itself. +The use of a scope parameter along with a nullifier 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 private key of the commitment.
+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 Eddsa proof is valid.
+The Eddsa zero-knowledge proof.
+True if the proof is valid, false otherwise.
+Creates a Groth16 proof composed of public signals and zero-knowledge parameters.
+Input signals of the circuit.
+WASM file of the circuit.
+ZKey file of the circuit.
+A proof containing public signals and zero-knowledge parameters.
+Verifies if a Groth16 proof is valid or not.
+The verification key used to verify the proof.
+The proof containing public signals and zero-knowledge parameters.
+True if the proof is valid, and 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.
+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 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 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 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.
+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.
+Downloads EdDSA snark artifacts (wasm
and zkey
) files if not already present in OS tmp folder.
{
wasm: "/tmm/@zk-kit/eddsa-artifacts@latest/eddsa.wasm",
zkey: "/tmp/@zk-kit/eddsa-artifacts@latest/eddsa.zkey"
}
+
+Downloads Poseidon snark artifacts (wasm
and zkey
) files if not already present in OS tmp folder.
The number of inputs to hash
+{
wasm: "/tmm/@zk-kit/poseidon-artifacts@latest/poseidon-2.wasm",
zkey: "/tmp/@zk-kit/poseidon-artifacts@latest/poseidon-2.zkey"
}
+
+Downloads Semaphore snark artifacts (wasm
and zkey
) files if not already present in OS tmp folder.
The depth of the tree
+{
wasm: "/tmm/@zk-kit/semaphore-artifacts@latest/semaphore-3.wasm",
zkey: "/tmp/@zk-kit/semaphore-artifacts@latest/semaphore-3.zkey"
}
+
+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.
++
A monorepo of reusable libraries for zero-knowledge technologies.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +ZK-kit is a set of libraries (plugins, 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 libraries for common tasks. | +
---|
♚ 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
)
♜ Mocha: tests for circuits and contracts (yarn test:circuits
, yarn test:contracts
)
♞ 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 | + +
---|---|---|---|
+ + @zk-kit/circuits + + | ++ + + + + | ++ + + + + | ++ |
+ + @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/imt.sol + + | ++ + + + + | ++ + + + + | ++ |
+ + @zk-kit/smt + + + (docs) + + | ++ + + + + | ++ + + + + | ++ + + + + | +
+ + @zk-kit/poseidon-proof + + + (docs) + + | ++ + + + + | ++ + + + + | ++ + + + + | +
+ + @zk-kit/eddsa-proof + + + (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 prettier
+
+or to automatically format the code:
+yarn prettier:write
+
+Semaphore 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 and compile contracts:
+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.
Bump a new version for your package with:
+yarn version:bump <package-name> <version>
# e.g. yarn version:bump utils 2.0.0
+
+It will create a commit and a git tag that you'll need to push on the main branch. A workflow will be triggered and will +publish your 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.
Optional
matching+
A JavaScript library for adding points to the Baby Jubjub curve.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +++[!WARNING]
+
This library has not been audited.
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. | +
---|
++[!WARNING]
+
This library has not been audited.
👾 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>
+
+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
}
+
++
A library to generate and verify EdDSA proofs.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +This zero-knowledge library allows you to prove and verify that you have the private key of a Semaphore identity. It will be mainly used on-chain because you can get the same result off-chain using EdDSA signatures with the @semaphore-protocol/identity package. It facilitates the demonstration of having an EdDSA 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. |
+
---|
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/eddsa-proof
package:
npm i @zk-kit/eddsa-proof
+
+or yarn:
+yarn add @zk-kit/eddsa-proof
+
+import { generate, verify } from "@zk-kit/eddsa-proof"
// Your private key (secret) associated with your commitment.
const privateKey = "secret"
// A public value used to contextualize the cryptographic proof and calculate the nullifier.
const scope = "scope"
// Generate the proof.
const fullProof = await generate(privateKey, scope)
/*
nb. commitment and scope are always the same - proof is variable.
{
commitment: '21756852044673293804725356853298692762259855200429755225624171532449447776732',
scope: '52191664570483756643537362991541193331102618014473399276861326740461293928448',
proof: [
'14987543977537638797613616391807211498102534775759297152458980015937921301475',
'3399335485250714998192957632691923175498432819155620830553382340417897595836',
'458847933923791518779258584891719351511628278818450523853640641455008133942',
'9130558865745328382423837376229933835283742789420937388990076948167771186665',
'2527867303822223913583586720705858457538165210401589969189198821632271648294',
'870032122185130505849909299495220614500026484724112145131565329210361970548',
'7499124546917660821334566902083675362480525785493429715971012094306224236446',
'4681140599918274218600441523225984097742730174371377925026448119492671129895'
]
}
*/
console.log(fullProof)
// If not specified, the Snark artifacts are downloaded automatically.
// You can specify them as follows.
// const fullProof = await generate(privateKey, scope, {
// wasm: "<your-path>/eddsa-proof.wasm",
// zkey: "<your-path>/eddsa-proof.zkey"
// })
// Verify the proof.
const response = await verify(fullProof)
// true.
console.log(response)
+
+Benchmarks were run on an Intel Core i7-1165G7, 16 GB RAM machine.
+Generate proof | +Verify proof | +Constraints | +
---|---|---|
258ms |
+15ms |
+1017 |
+
import { generate, verify } from "@zk-kit/eddsa-proof"
console.time("generate")
const proof = await generate("secret", "scope")
console.timeEnd("generate")
console.time("verify")
console.log(await verify(proof))
console.timeEnd("verify")
+
++
A snippet of SnarkJS code for verifying and generating Groth16 proofs only.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +++[!WARNING]
+
This package is no longer maintained as SnarkJS has integrated most of the above optimizations. Please, consider installing it instead.
This package contains SnarkJS functions for generating and verifying zero knowledge proofs with Groth16 specifically. In addition to the original code it also uses the cached bn128 curve if it already exists, making verification and generation of consecutive proofs faster. |
+
---|
Some advantages of using this package instead of snarkjs
directly are:
buildBn128
function if a bn128
cached curve already exists, making verification and generation of consecutive proofs much faster (e.g. verification seems to be ~9 times faster after the first one).Install the @zk-kit/groth16
package and its peer dependencies with npm:
npm i @zk-kit/groth16
+
+or yarn:
+yarn add @zk-kit/groth16
+
+++[!WARNING]
+
You will need to provide your own circuits here in your specified path. Remember to define your circuit input and rename the files accordingly.
import { prove, verify, buildBn128 } from "@zk-kit/groth16"
// Build the BN128 curve for Groth16.
// https://github.com/iden3/ffjavascript/blob/master/src/wasm_field1.js
await buildBn128() // WasmField1
// Define your circuit input.
// const input = {
// input1: 1,
// input2: 2,
// inputN: "N"
// }
// Compute the proof.
const proof = await prove(input, "<YOUR-PATH>/circuit.zkey", "<YOUR-PATH>/circuit.wasm")
/*
{
proof: {
pi_a: [
'8259885706934172848141475422209230656096448508815982888010519325096632035723',
'3142099172052192611205205328157407975469005554072266974009053708782134081166',
'1'
],
pi_b: [ [Array], [Array], [Array] ],
pi_c: [
'13863804425308906943736719856399634046638544298517159271373916818387594277305',
'21340646707244019956779928177502771923632450548108204371058275686712196195969',
'1'
],
protocol: 'groth16',
curve: 'bn128'
},
publicSignals: [
'527758365153958423212195330785598453331596731388181860789801455413116800554',
'19104626566001952573667666924569656871967113105870778077087237826253896482830',
'122'
]
}
*/
console.log(proof)
// Verify the proof.
const response = await verify("<YOUR-PATH>/circuit_verification_key.json", proof)
// true or false.
console.log(response)
+
++
Incremental Merkle tree implementations in TypeScript.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +An Incremental Merkle Tree is a dynamic data structure optimized for verifying data integrity in growing datasets. The updates are efficient since they modify only relevant nodes, avoiding the need to rebuild the entire tree with each change. This makes it ideal for real-time data verification contexts. You can learn more about the differences between MT and IMT here.
+++[!WARNING]
+
If you are looking for the first version of this package, please visit this link.
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>
+
+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.
+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))
+
+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.
+import { LeanIMT } from "@zk-kit/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))
+
++
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)
+
++
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 } 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) => poseidon2(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.
+ + ++ + + + + + + + + + + + + + + + + + + + + +
+ +++[!WARNING]
+
This library has not been audited.
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.
+Semantic version.
+1.0.0
+
+"latest"
+
+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
Represents a cryptographic entity capable of signing messages and verifying signatures +using the EdDSA scheme with Poseidon hash and the Baby Jubjub elliptic curve.
+