0xMiden / 0xMiden/miden-signature
bug: `flatten_ef`/`unflatten_ef` use unsafe transmute with unverified memory layout assumption
- 主要語言
- Rust
- 星號
- 2
- 分支
- 1
- PR 合併指標
- 30 天內沒有已合併 PR
描述
## Summary
`flatten_ef` and `unflatten_ef` in `src/internal/proof.rs` cast between `&[EF]` and `&[Goldilocks]` via raw pointer transmute, relying on the assumption that `BinomialExtensionField` has the same memory layout as `[Goldilocks; D]`. This assumption is not verified at compile time and is not guaranteed by Rust's type system.
## Code
```rust
fn flatten_ef>(ef_slice: &[EF]) -> &[Goldilocks] {
let len = ef_slice.len() * EF::DIMENSION;
// Safety: relies on BinomialExtensionField being layout-compatible with [Goldilocks; D]
unsafe { core::slice::from_raw_parts(ef_slice.as_ptr() as *const Goldilocks, len) }
}
fn unflatten_ef>(base_slice: &[Goldilocks]) -> &[EF] {
let len = base_slice.len() / EF::DIMENSION;
unsafe { core::slice::from_raw_parts(base_slice.as_ptr() as *const EF, len) }
}
```
## Why this is unsound
In Rust, `repr(transparent)` only applies to single-field newtype structs. A struct wrapping `[F; D]` can have additional padding or alignment requirements (e.g. from `PhantomData` fields) that differ from `[Goldilocks; D]`. Without a compile-time layout assertion, this is unsound undefined behavior if the layouts differ by even one byte.
These functions are called on every `sign` and `verify` invocation.
## Suggested fix
Use `bytemuck` with a compile-time `Pod` + `Zeroable` bound and a `cast_slice` call, which enforces layout compatibility at compile time:
```rust
fn flatten_ef>(ef_slice: &[EF]) -> &[Goldilocks] {
bytemuck::cast_slice(ef_slice)
}
```
Or add an explicit compile-time size assertion:
```rust
const _: () = assert!(
core::mem::size_of::>()
== core::mem::size_of::<[Goldilocks; 2]>()
);
```
貢獻指南
評估
這個 Issue 還沒有評估資料。