Download audit report
This document presents the results of the security review conducted by Nethermind Security for Anoma, including Resource Machine and EVM Protocol Adapter.
This audit focused on the end-to-end review of the above-described changes. The audit comprises 789 lines of Solidity and 2085 Rust code. The audit was performed using (a) manual analysis of the codebase, and (b) automated analysis tools.
| Audit assessment | |
| Audit Type | Security Review |
| Initial Report | November 10, 2025 |
| Final Report | November 13, 2025 |
| Initial Protocol Adapter Commit Hash | e6cfdf8fab |
| Initial ARM Commit Hash | a0cca9cdc8 |
| Final Protocol Adapter Commit Hash | fee4f47050 |
| Final ARM Commit Hash | 087e7d05f6 |
| Documentation Assessment | High |
| Test Suite Assessment | High |
Findings by severity
| # | Contract | LoC | Comments | Ratio | Blank | Total |
| 1 | ProtocolAdapter.sol | 268 | 117 | 43.66% | 57 | 442 |
| 2 | libs/MerkleTree.sol | 103 | 68 | 66.02% | 32 | 203 |
| 3 | state/CommitmentTree.sol | 88 | 33 | 37.50% | 23 | 144 |
| 4 | libs/RiscZeroUtils.sol | 78 | 50 | 64.10% | 14 | 142 |
| 5 | libs/proving/Logic.sol | 51 | 35 | 68.63% | 8 | 94 |
| 6 | libs/proving/Delta.sol | 34 | 33 | 97.06% | 14 | 81 |
| 7 | interfaces/IProtocolAdapter.sol | 16 | 43 | 268.75% | 13 | 72 |
| 8 | libs/TagUtils.sol | 30 | 17 | 56.67% | 10 | 57 |
| 9 | interfaces/ICommitmentTree.sol | 17 | 28 | 164.71% | 9 | 54 |
| 10 | libs/proving/Compliance.sol | 23 | 26 | 113.04% | 5 | 54 |
| 11 | state/NullifierSet.sol | 23 | 12 | 52.17% | 9 | 44 |
| 12 | Types.sol | 22 | 18 | 81.82% | 4 | 44 |
| 13 | libs/SHA256.sol | 10 | 14 | 140.00% | 3 | 27 |
| 14 | libs/proving/Aggregation.sol | 11 | 12 | 109.09% | 3 | 26 |
| 15 | interfaces/INullifierSet.sol | 6 | 13 | 216.67% | 3 | 22 |
| 16 | interfaces/IForwarder.sol | 4 | 11 | 275.00% | 1 | 16 |
| 17 | libs/Versioning.sol | 5 | 7 | 140.00% | 2 | 14 |
| Total | 789 | 537 | 68.06% | 210 | 1536 |
The scope includes a function EllipticCurve.ecAdd() from the external library elliptic-curve-solidity, which was not written by the Anoma team. This function was included in the security review since the entire library was never audited.
| # | Contract | LoC | Comments | Ratio | Blank | Total |
| 1 | resource.rs | 213 | 38 | 17.84% | 22 | 273 |
| 2 | compliance.rs | 220 | 15 | 6.82% | 31 | 266 |
| 3 | encryption.rs | 150 | 16 | 10.67% | 35 | 201 |
| 4 | logic_proof.rs | 173 | 0 | 0.00% | 26 | 199 |
| 5 | delta_proof.rs | 164 | 4 | 2.44% | 26 | 194 |
| 6 | transaction.rs | 149 | 15 | 10.07% | 15 | 179 |
| 7 | aggregation/mod.rs | 132 | 8 | 6.06% | 20 | 160 |
| 8 | aggregation/batch.rs | 123 | 7 | 5.69% | 20 | 150 |
| 9 | authorization.rs | 111 | 2 | 1.80% | 22 | 135 |
| 10 | action.rs | 95 | 4 | 4.21% | 15 | 114 |
| 11 | action_tree.rs | 70 | 15 | 21.43% | 8 | 93 |
| 12 | proving_system.rs | 74 | 5 | 6.76% | 11 | 90 |
| 13 | error.rs | 70 | 0 | 0.00% | 1 | 71 |
| 14 | nullifier_key.rs | 52 | 3 | 5.77% | 11 | 66 |
| 15 | resource_logic.rs | 51 | 5 | 9.80% | 8 | 64 |
| 16 | utils.rs | 48 | 0 | 0.00% | 7 | 55 |
| 17 | logic_instance.rs | 47 | 0 | 0.00% | 8 | 55 |
| 18 | merkle_path.rs | 43 | 3 | 6.98% | 7 | 53 |
| 19 | compliance_unit.rs | 39 | 3 | 7.69% | 5 | 47 |
| 20 | lib.rs | 37 | 0 | 0.00% | 1 | 38 |
| 21 | constants.rs | 13 | 4 | 30.77% | 3 | 20 |
| 22 | aggregation/constants.rs | 11 | 4 | 36.36% | 3 | 18 |
| Total | 2085 | 151 | 7.24% | 305 | 2541 |
| # | Finding | Severity | Update |
| 1 | Check a point is on the curve | Low | Fixed |
| 2 | ECDSA signature creation and verification | Low | Fixed |
| 3 | Update rand_seed to stronger randomness guarantees | Low | Fixed |
| 4 | Privacy Leakage through imageID usage | Info | Acknowledged |
| 5 | Differences between the specification and implementation | Info | Acknowledged |
| 6 | The function verifyMerkleProof() does not distinguish between the leaves and nodes | Info | Fixed |
| 7 | Should constrain logic instances' length to match the number of keys in the batch circuit | Best Practices | Fixed |
| 8 | Remove debug trait for secret key | Best Practices | Fixed |
Anoma’s Resource Machine (ARM) defines what resources and transactions are, how they compose, and how validity is proven — supporting an intent-centric, privacy-preserving model where users express goals and settlement proves correctness without revealing sensitive data. The ARM specification frames intents, transactions, and proofs, and places the Resource Machine as a core protocol component for programmable, shielded state updates.
The arm-risc0 codebase is a concrete implementation of this Resource Machine that runs ARM logic inside a zkVM. It provides full transaction processing, plus circuits and helpers for resources, transactions, Merkle paths, nullifier keys, compliance checks, and batching/aggregation.
On the settlement side, the EVM Protocol Adapter is a Solidity suite that lets EVM chains verify ARM executions and update on-chain state via commitments. The adapter’s purpose is to enable ARM transaction settlement on EVM-compatible chains.
Proof verification is designed to rely on the RISC Zero Ethereum verifier contracts, so an ARM execution proven in the RISC0 zkVM can be checked on EVM.
Taking all into account, users produce intents that compile to ARM transactions; the ARM circuits compute state transitions and generate (optionally aggregated) ZK proofs; the EVM Protocol Adapter receives the transaction and verifies proofs on-chain. Fig. 2 shows the flow of execution.

Resources can be thought of as "units of state", they represent objects that can be created and consumed during state transitions — e.g., tokens, NFTs, rights, or any other application-specific object. A Resource carries both data and its own rules for how it may be consumed. Each Resource specifies the logic that governs its life-cycle via a reference to a resource-logic program. A Resource has the following components:
logic_ref — hash of the logic program that defines how this resource may be consumed or createdlabel_ref — identifies the kind/class of resourcequantity — amount of this resourcevalue_ref — application-specific payloadis_ephemeral — marks resources that do not need nullifier balancing checksnonce — uniqueness salt for otherwise identical resourcesnk_commitment — commitment derived from the nullifier key used to prevent double-consumptionrand_seed — randomness used for commitment and nullifier generationEach Resource, therefore, contains both what it is (quantity) and how it behaves (logic). Through its logic_ref, the Resource enforces constraints on whether it may be consumed, and under which conditions new Resources may be created.
A compliance unit is the part of the transaction logic that proves that a consumed resource was valid and that it is correctly linked to a newly created resource. It serves as the bridge between the previous state and the new state, and it is enforced through a zero-knowledge proof.
A compliance unit contains
proof the ZK proof attesting correctnessinstance the public inputs bound to that proofThe witness inputs to this ZK proof are:
comsumed_resourcemerkle_pathephemeral_rootnf_keycreated_resourcercvThe proof checks that the consumed resource was present in the commitment tree (via its Merkle path or ephemeral root), that the correct nullifier key is used to consume it, and that the newly created resource is consistent with the referenced logic program. It also calculates the “delta” curve point: consumed kind times its quantity, minus created kind times its quantity, plus a generator multiple of the random scalar. That delta captures the net change in fungible balance.
The Action groups of compliance units. This allows for gathering consumed and created resources that participate in the same application, but can contain different logics. The action is represented as a Merkle Tree, where leaves are nullifiers and commitments. The action root is recreated during the execution in the Protocol Adapter to ensure the correct content of the action.
struct Action {
Logic.VerifierInput[] logicVerifierInputs;
Compliance.VerifierInput[] complianceVerifierInputs;
}Transaction consists of Actions, delta proof and aggregation proof (if used). The delta proof guarantees that all the resources in the transaction are balanced. The transaction is submitted to the protocol adapter, as illustrated in Fig. 3.
struct Transaction {
Action[] actions;
bytes deltaProof;
bytes aggregationProof;
}
Built using the Risc-Zero zkVM, Anoma uses two different ZK proofs to prove state transitions to establish the correct consumption and creation of resources, called the compliance proofs and logic proofs. Additionally, for efficiency reasons, it also provides an in-built aggregation method to verify all the proofs in one.
Compliance proofs are a fixed proof defined by Anoma that proves that the nullifier of the resource consumed is equal to the nonce of the created resource. Additionally, it computes the delta value of the created and computed resources, following the style of a Pedersen commitment, whereby Δ = consumed kind * consumed quantity - created kind * created quantity + G * rcv where G is the generator on the curve and rcv is a random scalar generated. A resource kind is the hash to curve(logic reference||label reference) where the hash used is SHA256 and the curve is Secp256k1. The public values of the circuit are:
These proofs convince the verifier that a user has correctly consumed and created a new resource.
Logic Proofs are user-defined proofs that outline how specific resources can or cannot be consumed or created. More specific details about writing these circuits will be discussed in Section .
The final proof circuit is the Batch Aggregation Proof, which, as the name suggests, proves that all these provided proofs verify under these provided keys. Split between compliance and logic proofs, it takes as input the journal instances and the keys/imageIDs (for compliance, it is a fixed key as the circuit does not change) to verify. Calling the in-built verify function, the proofs can be verified in sequence: first, all the compliance proofs are verified, then all the logic proofs are verified. Finally, all the instances and keys input are committed as public values.
The delta proof is the signature (and recovery ID) of all the deltas in a transaction. Formally, it can be expressed as Sign(H(Vec(Δ))rcv [] σ = (r,s), recID where the signature attests to the integrity and authenticity of the aggregated deltas.
To enforce the transaction being balanced, meaning the total amount created of a resource must equal the total amount consumed, the sum of all delta values must correspond to the aggregate randomness rcv. When a transaction is submitted on-chain, this condition is verified by recovering the public key from the signature rcv and comparing it to the expected public key derived from the summed delta values. Should the value not recover to the aggregate sum of the rcv's in the transaction, it means there is an imbalance.
The Protocol Adapter (PA) allows the Anoma applications to be run on existing chains. It processes the transactions created in the Anoma Resource Machine (ARM) and updates the state according to the provided resources. In this iteration of the protocol, the PA is implemented as a Solidity smart contract and can be utilised as a connector to any EVM-compatible chain. The entrypoint is the function execute() with input being the Transaction. The execute() function iterates over provided Action objects, computes the Action root from collected nullifiers and commitments (tags), and for each Compliance Unit performs the following actions:
Forwarder smart contract with provided calldata.Next, the delta proof is verified. The signature is utilised to recover the Keccak-256 hash of tags, which is compared against the hash of the provided public key (instance). If used, the aggregation proof is checked. If all proofs are verified correctly and the external call was executed successfully with the expected output, the new commitment root is added to the set of historic roots.
Commitment accumulator is a Merkle Tree with variable size. The leaves contain the resource commitment. The tree is expanded with empty leaves if the full capacity is reached. Roots of the tree are stored in the _roots mapping, which allows for proving commitment against historic tree state. This accumulator allows for duplicated values of leaves.
Nullifier set contains the resource nullifier. It prevents duplicates.
The Forwarder is a smart contract created by the application developer. It should be callable only from Anoma's protocol adapter and only with the calldata included in the resource linked to particular logic. The forwarder can contain arbitrary logic and is used to interact with an external contract.
Users create applications on Anoma by developing logic circuits and deploying a forwarder contract on the desired blockchain. Logic consists of constraints that must be satisfied during proof creation. Logic constraints allow for defining:
This section outlines the approach the Nethermind Security team performed to evaluate the security of the Anoma Resource Machine protocol, outlining the properties checked.
Additionally, the assumptions about the system are provided, taking into account when assessing the protocol and the limitations of the security review.
4.11.1 Assumptions
The assumptions used for the security audit were as follows:
4.11.2 Limitations
During this security review, we were unable to assess:
4.11.3 Resources
The following properties were assessed with regard to the security and validity of the resource objects:
rand_seed value generation using thread_rng(), which is used in both nullifier and commitment creation.4.11.4 Compliance Unit
The following properties were assessed with regard to the security and validity of the resource objects:
4.11.5 Action
The properties checked for actions were:
4.11.6 Transaction
The properties checked for transactions were:
4.11.7 Delta Proofs
For the delta proof, the following was checked:
Resource::kind() (consisting of the hash of the logic reference and label) is correctly projected onto the curve.rcv value to artificially balance a transaction is not possible.Action::delta(), Transaction::delta(), and in the Protocol Adapter at vars.transactionDelta.add().DeltaProof::prove(), verifying that the public key is computed as the sum of deltas, the secret key as the sum of rcv values, and the signed message as the hash of all nullifiers and commitments.DeltaProof::verify() and in the Protocol Adapter’s Delta.verify() implementation.4.11.8 Protocol Adapter
The following properties were assessed in the Protocol Adapter:
_processCompliance() and _processLogic() call into the Risc Zero router with the exact public instance values reconstructed from calldata.4.11.9 Attack Scenarios Considered
In addition to ensuring the above properties of each component of Anoma, the review considered the following potential attack vectors:
The risk rating methodology used by Nethermind Security follows the principles established by the OWASP Foundation. The severity of each finding is determined by two factors: Likelihood and Impact.
Likelihood measures how likely the finding is to be uncovered and exploited by an attacker. This factor will be one of the following values:
When defining the likelihood of a finding, other factors are also considered. These can include but are not limited to motive, opportunity, exploit accessibility, ease of discovery, and ease of exploit.
Impact is a measure of the damage that may be caused if an attacker exploits the finding. This factor will be one of the following values:
When defining the impact of a finding, other factors are also considered. These can include but are not limited to data and state integrity, loss of availability, financial loss, and reputation damage. After defining the likelihood and impact of an issue, the severity is determined according to the table below.
| Impact / Likelihood | Low | Medium | High |
| High | Medium | High | Critical |
| Medium | Low | Medium | High |
| Low | Info / Best Practices | Low | Medium |
| Undetermined | Undetermined | Undetermined | Undetermined |
To address issues that do not fit a High, Medium or Low severity, Nethermind Security also uses three more finding severities: Informational, Best Practices, and Undetermined.
| File | Fix commit | Type | Status |
contracts/src/libs/proving/Delta.sol | PR #396 | Low | Fixed |
The function ecAdd(...) uses functions jacAdd(...) and jacDouble(...) to add points on the elliptic curve, secp256k1 specifically. However, inputs to these functions are of type uint256, which do not assert the validity that these points are initially on the curve and Jacobian coordinates mapping, as well as the additional formulas that assume that the points are already on the curve.
Moreover, isOnCurve(...) function won't validate the point at infinity " (0, 0)", so this case must be handled separately.
Recommendation
Check that points are on the Curve in add(...).
Resolution
Added in protocol adapter PR #396.
Update from Nethermind Security
We note that this fix assumes the first elliptic-curve point used is already on the curve, as is also mentioned in the function's comment. Since the resulting point would—with high probability—fall outside the curve.
| File | Fix commit | Type | Status |
arm/src/delta_proof.rscontracts/src/libs/proving/Delta.sol | PR #162 PR #161 | Low | Fixed |
The Anoma Resource Machine implements the DeltaProof::verify() function, which differs from the Delta.verify() in the Ethereum Protocol Adapter. Below we list the differences:
DeltaProof::verify() accepts the malleable signatures, where the s > secp256k1n ÷ 2 + 1, while the Protocol Adapter Delta.verify() uses the OpenZeppelin library that prevents malleability by ensuring the s is less than half of the curve order;DeltaProof::verify() handles the cases where recovery ID is equal to 2 or 3, which represent the overflow of r. Such cases are unlikely to happen, but the on-chain ECDSA verification ecrecover() does not handle such signatures, since EVM treats them as invalid (Ethereum Yellow Paper Appendix F);Moreover, the ARM's DeltaProof::prove() function utilises the k256 crate, which may generate a signature with the recid equal to 2 or 3. Those signatures are not supported in on-chain verification and should be handled during generation. Note, however, that there is a low probability of generating such signatures.
Recommendation
Consider checking if the generated signature is compatible with the on-chain verification algorithm. Also consider unifying the verification function in ARM and the Ethereum Protocol Adapter.
Resolution
Added in PRs arm-risc0 #162 and #161.
rand_seed to stronger randomness guarantees| File | Fix commit | Type | Status |
arm/src/resource.rs | PR #159 | Low | Fixed |
When a resource is created, rand::thread_rng().gen() is used as a seed in the psi() function. Although thread_rng() is initially seeded from OS entropy and is generally secure, for stronger guarantees, it’s recommended to use OsRng directly.
Recomendations: Replace rand_seed initialization using thread_rng() with OsRng().
Resolution
Added in PR arm-risc0 #159.
| File | Fix commit | Type | Status |
contracts/src/ProtocolAdapter.sol | — | Info | Acknowledged |
The imageID of a circuit is its identifier, but also its verifying key. In Anoma, users can construct their own Risc-0 circuits, known as the logic, which defines a resource's ability to be consumed, created, and how it should deal with being ephemeral.
Though the circuit itself is not necessarily public, and is up to the app how it is communicated, when the Anoma transaction is sent on-chain to add the commitments to the tree and nullify consumed resources, the imageID is used to verify the logic zk proof for each resource. This is shown in the code below:
// snippet from execute(...) in ProtocolAdapter.sol
// @audit the logic ref is the same as the imageID
vars = _processLogic({
isConsumed: true,
// The `lookup` function reverts if the nullifier is not part of the logic verifier inputs.
input: action.logicVerifierInputs.lookup(complianceVerifierInput.instance.consumed.nullifier),
logicRefFromComplianceUnit: complianceVerifierInput.instance.consumed.logicRef,
actionTreeRoot: actionTreeRoot,
vars: vars
});
// Process the logic proof of the created resource.
vars = _processLogic({
isConsumed: false,
// The `lookup` function reverts if the commitment is not part of the logic verifier inputs.
input: action.logicVerifierInputs.lookup(complianceVerifierInput.instance.created.commitment),
logicRefFromComplianceUnit: complianceVerifierInput.instance.created.logicRef,
actionTreeRoot: actionTreeRoot,
vars: vars
});Ultimately this calls, in the function _processLogic(...) the following:
// snippet from _processLogic(...) in ProtocolAdapter.sol
// Verify the logic proof.
//slither-disable-next-line calls-loop
_TRUSTED_RISC_ZERO_VERIFIER_ROUTER.verify({
seal: input.proof,
imageId: logicRef,
journalDigest: sha256(instance.toJournal())
});The nullifier and its commitment should not be linkable given a large enough privacy pool, however, the usage of this imageID enables them to be linkable under certain conditions. Since it is possible for an observer to monitor the transactions on Ethereum, they can create a mapping of each imageID to its commitment/nullifier. This ultimately shrinks the privacy to pool from one with all commitments, to a subset with only the specific imageID.
This means the privacy pool can be shrunk by the other public information available and the "rules" that Anoma transactions and actions work with. More specifically:
The simplest example is given, an existing commitment tree with a large number of commitments and a long list of nullifiers in the nullifier accumulator. If a user creates a new resource with a unique image ID. This means that an observer watching this will see a unique image ID be submitted on-chain to verify a commitment's logic zk proof. If no other resource of the same imageID is created, then an observer will know for certain which commitment corresponds to which nullifier, as the imageID will need to be used again to nullify the resource and verify its zk proof. Thus, the resources commitment and nullifier are linked.
In summary, the usage of imageID to verify the resource logic zk proof can thus be used to link together commitments and their corresponding nullifiers.
Recommendation
Add explicit explanation for developers that, on first usage of a specific imageID, it can cause the aforementioned problem. The solution currently, without function privacy, is to, on first usage, create many of the resources to initialise the privacy pool.
Resolution
Planning on updating specification.
| File | Fix commit | Type | Status |
* | — | Info | Acknowledged |
The specification that describes the Anoma RM components differs from the implementation. Below we list the identified differences:
Accumulator, AccumulatorWitness, CommitmentIdentifier, and AccumulatedValueadd() is _addCommitment(), verify() is verifyMerkleProof() and value() is latestCommitmentTreeRoot()_addNullifier() not insert() and checking nullifier existence is done with isNullifierContained() not contains()ComplianceUnit in the specification contains VerifyingKey, which is not present in the implementationInstance is different in the specification, since it does not include logic referencescreate() function implementation takes only the witness, while the specification states that parameters are ProvingKey, VerifyingKey, Instance, Witnessverify() does in specification returns a boolean, while the implemented function throws an error on incorrect proofcreated() and consumed() functions are not implementeddelta() function does not return data of type DeltaHashlogicVKOuter fields. Implemented ComplianceInstance contains a single nullifier and commitment, logic references, consumed resource commitment tree root, and deltalogicVKOuter = logicVKOuterHash(r.logicRef, ...)actionTreeSizetag, which is not present in the specificationcreate() function that generates compliance proofs and resource logic proofs. Proofs are generated first, and an action is created with new()to_instance() function which is in specificationdelta_vk, and the types are different except for the actions fieldcreate() takes actions and delta as parameters, which is different from the description. Creation of a delta proof is not done in create() but in separate function generate_delta_proof()compose() function in the specification states that two transactions with generated delta proofs can be aggregated using their delta proofs and verifying keys. However, in the implementation, transactions are composed using delta witnesses before proof generation, using the signing key (rcv) and the set of tagsverify() does not contain checks that do not require access to global structures described in point 2 (actions partition the state change induced by the transaction). This is addressed in v0.8.2DeltaProof and DeltInstanceTransaction With Payment and TransactionFunction - it is not implemented;
actionTreeRoot is computed as the root of a Merkle tree of depth 4, but in the implementation, the action tree does not have a defined depth.Recommendation
Consider unifying the specification and the implementation.
Resolution
Will update documentation.
verifyMerkleProof() does not distinguish between the leaves and nodes| File | Fix commit | Type | Status |
contracts/src/state/CommitmentTree.sol | PR #392 | Info | Fixed |
The function verifyMerkleProof() in CommitmentTree verifies that a Merkle path and a commitment leaf reproduce a given root. However, if this function received the node as a commitment parameter and a shorter path, the proof would still be valid. This is possible, since there is no lower limit on the path size and no distinction between generating the leaf and the node during the proof check.
Recommendation
Consider introducing the domain separation in the commitment tree to protect against providing valid proofs for the nodes.
Resolution
The verifyMerkleProof() is not used in production or in any way affects state change. However, due to the fact that this function can be misinterpreted by external parties to possess usual path-verification semantics, we have decided to delete it from production code in #392.
| File | Fix commit | Type | Status |
arm_circuits/batch_aggregation/methods/guest/src/main.rs | PR #160 | Best Practices | Fixed |
In the batch aggregation circuit, the inputs to the zkVM are read, but there is a lack of checking that the same number of keys and instances exist before beginning to verify the proofs.
Recommendation
It is best practice to add a constraint that logic instances length == logic keys length to ensure this is the case, and so it does not rely on the panic.
Resolution
Added in arm risc0 PR #160.
| File | Fix commit | Type | Status |
encryption.rs | PR #164 | Best Practices | Fixed |
The Debug trait is being derived for the SecretKey, which makes it possible to log and therefore retain in memory the secret key of a user, potentially leaking the value. This issue arises mainly in two scenarios:
Enabling logging of this value increases the risk of exposing sensitive information such as the user's secret key. As this function may be used by the users of Anoma, it is possible that they will not run in release mode when inheriting the struct and could inadvertently leak the secret key.
Recommendation
Remove the Debug trait derivation from the SecretKey implementation.
Resolution
Added in arm risc0 PR #164.
Software documentation refers to the written or visual information that describes the functionality, architecture, design, and implementation of software. It provides a comprehensive overview of the software system and helps users, developers, and stakeholders understand how the software works, how to use it, and how to maintain it. Software documentation can take different forms, such as user manuals, system manuals, technical specifications, requirements documents, design documents, and code comments. Software documentation is critical in software development, enabling effective communication between developers, testers, users, and other stakeholders. It helps to ensure that everyone involved in the development process has a shared understanding of the software system and its functionality. Moreover, software documentation can improve software maintenance by providing a clear and complete understanding of the software system, making it easier for developers to maintain, modify, and update the software over time. Smart contracts can use various types of software documentation. Some of the most common types include:
These types of documentation are essential for smart contract development and maintenance. They help ensure that the contract is properly designed, implemented, and tested, and they provide a reference for developers who need to modify or maintain the contract in the future.
The Anoma Resource Machine protocol provided detailed specification: Resource Machine and Protocol Adapter. In addition, the team provided audit-specific documentation, detailing the core components and outlining the flow step by step. Furthermore, the Anoma team thoroughly addressed all questions and concerns raised by the Nethermind Security team, providing valuable insights and a comprehensive understanding of the project's technical aspects.
Because the tests perform local proving, the Kudo app test fails due to an OOM signal. However, the remaining tests successfully confirm the correct creation of proofs.
| 156Tests passed | 0Failed |
The complete test output is in the full report.
As auditors, we recommend that any changes or updates made to the audited codebase undergo a re-audit or security review to address potential vulnerabilities or risks introduced by the modifications. By conducting a re-audit or security review of the modified codebase, you can significantly enhance the overall security of your system and reduce the likelihood of exploitation. However, we do not possess the authority or right to impose obligations or restrictions on our clients regarding codebase updates, modifications, or subsequent audits. Accordingly, the decision to seek a re-audit or security review lies solely with you.
This report is based on the scope of materials and documentation provided by you to Nethermind in order that Nethermind could conduct the security review outlined in 1. Executive Summary and 2. Audited Files. The results set out in this report may not be complete nor inclusive of all vulnerabilities. Nethermind has provided the review and this report on an as-is, where-is, and as-available basis. You agree that your access and/or use, including but not limited to any associated services, products, protocols, platforms, content, and materials, will be at your sole risk. Blockchain technology remains under development and is subject to unknown risks and flaws. The review does not extend to the compiler layer, or any other areas beyond the programming language, or other programming aspects that could present security risks. This report does not indicate the endorsement of any particular project or team, nor guarantee its security. No third party should rely on this report in any way, including for the purpose of making any decisions to buy or sell a product, service or any other asset. To the fullest extent permitted by law, Nethermind disclaims any liability in connection with this report, its content, and any related services and products and your use thereof, including, without limitation, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement. Nethermind does not warrant, endorse, guarantee, or assume responsibility for any product or service advertised or offered by a third party through the product, any open source or third-party software, code, libraries, materials, or information linked to, called by, referenced by or accessible through the report, its content, and the related services and products, any hyperlinked websites, any websites or mobile applications appearing on any advertising, and Nethermind will not be a party to or in any way be responsible for monitoring any transaction between you and any third-party providers of products or services. As with the purchase or use of a product or service through any medium or in any environment, you should use your best judgment and exercise caution where appropriate. FOR AVOIDANCE OF DOUBT, THE REPORT, ITS CONTENT, ACCESS, AND/OR USAGE THEREOF, INCLUDING ANY ASSOCIATED SERVICES OR MATERIALS, SHALL NOT BE CONSIDERED OR RELIED UPON AS ANY FORM OF FINANCIAL, INVESTMENT, TAX, LEGAL, REGULATORY, OR OTHER ADVICE.
The Leading Engineers of Blockchain Infrastructure