Skip to content

Add Borsh serialization and Solana support#207

Open
AHartNtkn wants to merge 13 commits into
anthony/arm-dep-minimumfrom
anthony/arm-solana-support
Open

Add Borsh serialization and Solana support#207
AHartNtkn wants to merge 13 commits into
anthony/arm-dep-minimumfrom
anthony/arm-solana-support

Conversation

@AHartNtkn

@AHartNtkn AHartNtkn commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

Problem

arm-risc0 needed Solana/Borsh support in the arm crate while preserving existing behavior for non-Solana targets. During this work, logic verification also needed to remain bound to the action-context instance.

What This PR Changes

  1. Adds Solana/Borsh feature plumbing in arm.
  • arm/Cargo.toml: adds optional deps (borsh, sha2, solana-program, solana-secp256k1, dashu)
  • adds features:
    • borsh = ["dep:borsh"]
    • solana = ["transaction", "borsh", "dep:sha2", "dep:solana-program", "dep:solana-secp256k1", "dep:dashu"]
  1. Adds Borsh support to public transaction/compliance/logic types.
  • derives added across Action, ComplianceUnit, Transaction, Delta, LogicInstance, LogicVerifierInputs, ComplianceInstance, Digest, and related app-data structs
  • Digest now has explicit from_bytes / to_bytes helpers used by Solana paths
  1. Adds Solana-specific proving key / verification key selection and constants wiring.
  • arm/src/constants.rs now gates VK bytes by feature = "solana"
  • includes default (risc0-serde) and Solana (Borsh-serializing) VK constants
  1. Keeps logic verification bound to action context.
  • LogicVerifierInputs now carries instance_journal
  • to_logic_verifier(...) decodes provided journal and checks equality against to_instance(is_consumed, root)
  • returns ArmError::LogicInstanceMismatch on mismatch
  • verifier now uses the provided journal bytes after validation
  1. Adds Solana delta verification path.
  • new arm/src/solana_delta.rs (enabled for solana without zkvm)
  • verifies delta proof with Solana syscalls (hashv, secp256k1_recover) and solana-secp256k1
  • includes explicit on-curve validation and accumulated delta/address matching
  • extends errors with DeltaPointNotOnCurve and DeltaMismatch
  1. Adds serialization support for delta proof/witness in both k256 and placeholder modes.
  • Borsh impls for 65-byte DeltaProof and 32-byte DeltaWitness

Scope

Only files in this PR diff (origin/anthony/arm-dep-minimum...origin/anthony/arm-solana-support):

  • arm/Cargo.toml
  • arm/src/action.rs
  • arm/src/compliance.rs
  • arm/src/compliance_unit.rs
  • arm/src/constants.rs
  • arm/src/delta_proof.rs
  • arm/src/delta_types.rs
  • arm/src/digest.rs
  • arm/src/error.rs
  • arm/src/lib.rs
  • arm/src/logic_instance.rs
  • arm/src/logic_proof.rs
  • arm/src/solana_delta.rs
  • arm/src/transaction.rs
  • arm_tests/arm_test_app/src/lib.rs

Verification

Ran on branch anthony/arm-solana-support.

  • cargo fmt --all -- --check
  • cargo check -p anoma-rm-risc0
  • cargo check -p anoma-rm-risc0 --no-default-features
  • cargo check -p anoma-rm-risc0 --no-default-features --features solana
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test -p anoma-rm-risc0 ✅ (4 passed)
  • cargo test -p anoma-rm-risc0 --no-default-features ✅ (6 passed)
  • cargo test -p anoma-rm-risc0 --no-default-features --features solana ✅ (7 passed)
  • Solana PA nix e2e: ./scripts/anchor-test.sh ✅ (36 passing)
    • run inside nix dev shell with PATH preferring nix toolchain wrapper:
      • export PATH="$(dirname "$(dirname "$SBF_SDK_PATH")"):$PATH"

Tracking

AHartNtkn and others added 12 commits February 25, 2026 17:29
- Add borsh, sha2, solana-program, solana-secp256k1, dashu as optional deps
- Add `borsh` and `solana` feature flags
- Add k256 dev-dependency for tests without default features
- Digest: add Borsh derive, make field public, add from_bytes/to_bytes methods
- Digest: replace bytemuck::from_bytes with from_bytes() in TryFrom/FromHex
- Constants: feature-gate VK bytes by solana (Borsh circuit vs risc0 serde circuit)
- Constants: extract BATCH_AGGREGATION_VK_BYTES, add EMPTY_HASH_WORDS, bytes_to_words_const
- Error: add DeltaPointNotOnCurve and DeltaMismatch variants

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Action, ComplianceInstance, ComplianceInstanceWords, ComplianceUnit
- DeltaProof (placeholder), DeltaWitness (placeholder) + len/is_empty/as_slice
- DeltaProof (k256), DeltaWitness (k256): manual BorshSerialize/BorshDeserialize
- LogicInstance, AppData, ExpirableBlob, LogicVerifierInputs
- Transaction, Delta

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- delta_proof: feature-gate hasher (SHA-256 for solana, Keccak-256 for EVM)
- LogicInstance: split to_journal() into zkvm (risc0 serde) and borsh variants
- LogicVerifierInputs: add instance_journal field for pre-serialized journal bytes
- LogicVerifier: use pre-serialized instance_journal instead of recomputing
- ComplianceInstance: add Solana borsh to_journal() impl
- ComplianceWitness: relax feature gate from zkvm+k256 to just k256
- arm_test_app: add instance_journal to LogicVerifierInputs construction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses Solana syscalls (hashv, secp256k1_recover) and solana-secp256k1 for
EC point arithmetic instead of k256, which exceeds SBF stack frame limits.
Module is gated on cfg(all(feature = "solana", not(feature = "zkvm"))).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- arm_circuits/Cargo.toml: add methods crates to workspace members
- All methods/Cargo.toml: add borsh and bin features
- All methods/build.rs: forward borsh/bin features to guest via GuestOptionsBuilder
- All guest/Cargo.toml: add borsh/bincode deps, forward borsh to anoma-rm-risc0/borsh
- All guest/src/main.rs: feature-conditional output (borsh/bincode/default risc0 serde)
- compliance guest: add k256 and zkvm features to anoma-rm-risc0 dep
- trivial_logic guest: add zkvm and k256 features with default-features = false
- arm_test_app: add instance_journal to LogicVerifierInputs construction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DeltaWitness::Serialize uses serialize_bytes (u64 length prefix + bytes)
but DeltaWitness::Deserialize reads [u8; 32] (fixed-size, no prefix).
These are incompatible in bincode: the deserialized key silently contains
the length prefix bytes instead of the actual key, producing a corrupted
DeltaWitness without erroring.

DeltaProof does not have this issue — its Deserialize correctly uses
Vec::deserialize to match serialize_bytes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DeltaWitness::Serialize uses serialize_bytes which writes a u64 length
prefix in bincode. DeltaWitness::Deserialize was reading [u8; 32] which
expects no prefix, causing silent data corruption on roundtrip.

Change Deserialize to use Vec::deserialize (matching what DeltaProof
already does), with an explicit length check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix the same serialize_bytes/Deserialize mismatch in the placeholder
DeltaWitness (delta_types.rs) that was fixed in the k256 version.
Uses Vec::deserialize to match serialize_bytes, same pattern as
placeholder DeltaProof.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
`unsigned_is_multiple_of` is unstable until Rust 1.87.0. The nix flake
in solana-protocol-adapter pins Rust 1.84.1 (the last version compatible
with Anchor 0.31.x), so this breaks downstream compilation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…base

The rebase auto-merged 6af403a's removal of these features, undoing the
fix from ece8158. trivial-logic-guest uses resource_logic which requires
both zkvm and k256.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@AHartNtkn AHartNtkn force-pushed the anthony/arm-solana-support branch from 14e21d7 to 3d87f52 Compare February 25, 2026 23:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

1 participant