Skip to content

zk-sdk: Do not require passing owned vectors to RangeProof#194

Open
vadorovsky wants to merge 1 commit into
solana-program:mainfrom
vadorovsky:zk-sdk-avoid-heap-alloc
Open

zk-sdk: Do not require passing owned vectors to RangeProof#194
vadorovsky wants to merge 1 commit into
solana-program:mainfrom
vadorovsky:zk-sdk-avoid-heap-alloc

Conversation

@vadorovsky

Copy link
Copy Markdown

The current implementation of RangeProof::new and RangeProof::verify requires the caller to pass inputs as owned vectors. That requires heap allocations even if the number of inputs is small (even as small as 1).

Remove that requirement by accepting AsRef<[T]> trait as inputs, which still makes it possible to pass Vec<T>, so we don't break the old users relying on the old API. But for callers who want performance, it accepts also the following types that can be allocated on the stack:

  • [T]
  • [T; N]
  • &[T]

Furthermore, single elements can be passed using slice::from_ref[0], e.g.

let proof = RangeProof::new(
    slice::from_ref(&55),
    slice::from_ref(&64),
    slice::from_ref(&open),
    &mut transcript_create,
)

which does not perform any allocation at all. Instead, it performs raw pointer casting to coerce a reference to a single-element slice[1][2].

Additionally, AsRef<T> makes it possible to pass the following iterable types:

  • std::slice::Iter<'_, T>
  • IterMut<'_, T>
  • IntoIter<T, A>

[0] https://doc.rust-lang.org/std/slice/fn.from_ref.html
[1] https://github.com/rust-lang/rust/blob/1.92.0/library/core/src/slice/raw.rs#L203-L205
[2] https://github.com/rust-lang/rust/blob/1.92.0/library/core/src/array/mod.rs#L164-L167

The current implementation of `RangeProof::new` and `RangeProof::verify`
requires the caller to pass inputs as owned vectors. That requires heap
allocations even if the number of inputs is small (even as small as 1).

Remove that requirement by accepting `AsRef<[T]>` trait as inputs, which
still makes it possible to pass `Vec<T>`, so we don't break the old
users relying on the old API. But for callers who want performance, it
accepts also the following types that can be allocated on the stack:

- `[T]`
- `[T; N]`
- `&[T]`

Furthermore, single elements can be passed using `slice::from_ref`[0],
e.g.

```rust
let proof = RangeProof::new(
    slice::from_ref(&55),
    slice::from_ref(&64),
    slice::from_ref(&open),
    &mut transcript_create,
)
```

which does not perform any allocation at all. Instead, it performs raw
pointer casting to coerce a reference to a single-element slice[1][2].

Additionally, `AsRef<T>` makes it possible to pass the following
iterable types:

- `std::slice::Iter<'_, T>`
- `IterMut<'_, T>`
- `IntoIter<T, A>`

[0] https://doc.rust-lang.org/std/slice/fn.from_ref.html
[1] https://github.com/rust-lang/rust/blob/1.92.0/library/core/src/slice/raw.rs#L203-L205
[2] https://github.com/rust-lang/rust/blob/1.92.0/library/core/src/array/mod.rs#L164-L167
@vadorovsky vadorovsky marked this pull request as ready for review January 14, 2026 12:53
@samkim-crypto samkim-crypto self-requested a review January 14, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant