@@ -220,10 +220,9 @@ fn launch_pointwise_mul_batched(
220220/// Layout: `m` columns, each `lde_size` u64s, column `c` at byte offset
221221/// `c * lde_size * 8` within `buf`. Freed when `buf` Arc drops.
222222///
223- /// `tree` optionally carries the main-trace Merkle tree kept resident on device
224- /// (populated by the keep path), so R4 query openings can gather authentication
225- /// paths on device instead of D2H'ing the whole tree to host. `None` on the CPU
226- /// path or when the tree wasn't retained.
223+ /// `tree` optionally carries the main trace Merkle tree kept resident on device
224+ /// (the keep path), so R4 query openings gather paths on device instead of
225+ /// copying the whole tree to host. None on the CPU path.
227226#[ derive( Clone ) ]
228227pub struct GpuLdeBase {
229228 pub buf : Arc < CudaSlice < u64 > > ,
@@ -240,24 +239,22 @@ pub struct GpuLdeExt3 {
240239 pub buf : Arc < CudaSlice < u64 > > ,
241240 pub m : usize ,
242241 pub lde_size : usize ,
243- /// Optionally the aux/composition Merkle tree kept resident on device (the
244- /// keep path), so R4 openings gather paths on device instead of D2H'ing the
245- /// whole tree. `None` on the CPU path or when not retained.
242+ /// Optionally the aux or composition Merkle tree kept resident on device
243+ /// (the keep path), so R4 openings gather paths on device. None otherwise.
246244 pub tree : Option < GpuMerkleTree > ,
247245}
248246
249- /// Handle to a Merkle tree kept live on device after a commit, so query
250- /// openings can gather authentication paths on device instead of D2H'ing the
251- /// whole tree to host. Node layout matches the CPU tree
252- /// (`crypto/crypto/src/merkle_tree`): `nodes[0..leaves_len-1]` are inner nodes
253- /// (root at index 0), `nodes[leaves_len-1..]` are the leaves; each node is 32
247+ /// Merkle tree kept resident on device after a commit, so query openings gather
248+ /// paths on device instead of copying the whole tree to host. Node layout
249+ /// matches the CPU tree (`crypto/crypto/src/merkle_tree`): `nodes[0..leaves_len-1]`
250+ /// are inner nodes (root at 0), `nodes[leaves_len-1..]` are the leaves, each 32
254251/// bytes. Freed when the `nodes` Arc drops.
255252#[ derive( Clone ) ]
256253pub struct GpuMerkleTree {
257254 pub nodes : Arc < CudaSlice < u8 > > ,
258255 pub leaves_len : usize ,
259- /// The Merkle root (node 0), copied to host at build time (32 bytes) so the
260- /// commitment is available without D2H'ing the whole tree.
256+ /// The Merkle root (node 0), copied to host at build time so the commitment
257+ /// is available without copying the whole tree.
261258 pub root : [ u8 ; 32 ] ,
262259}
263260
@@ -643,41 +640,11 @@ pub fn coset_lde_batch_base_into_with_leaf_hash(
643640 . map ( |_| ( ) )
644641}
645642
646- /// Like `coset_lde_batch_base_into_with_leaf_hash`, but also builds the full
647- /// Merkle tree on device and returns the `2*lde_size - 1` node buffer back
648- /// to the caller in `merkle_nodes_out` (byte length `(2*lde_size - 1) * 32`).
649- ///
650- /// The leaf hashes are never exposed to the caller — they stay on device and
651- /// feed straight into the pair-hash tree kernel, avoiding the
652- /// pinned→pageable→pinned round-trip that the separate-step GPU tree build
653- /// would pay.
654- pub fn coset_lde_batch_base_into_with_merkle_tree (
655- columns : & [ & [ u64 ] ] ,
656- blowup_factor : usize ,
657- weights : & [ u64 ] ,
658- outputs : & mut [ & mut [ u64 ] ] ,
659- merkle_nodes_out : & mut [ u8 ] ,
660- ) -> Result < ( ) > {
661- coset_lde_batch_base_into_with_merkle_tree_inner (
662- columns,
663- blowup_factor,
664- weights,
665- outputs,
666- Some ( merkle_nodes_out) ,
667- KeccakCommit :: FullTree ,
668- false ,
669- false ,
670- )
671- . map ( |_| ( ) )
672- }
673-
674- /// Fused LDE + leaf-hash + Merkle tree build, keeping **both** the LDE buffer
675- /// and the Merkle tree resident on device (returned in `GpuLdeBase` + its
676- /// `tree`, including the root). The host tree is **not** materialised — there is
677- /// no `merkle_nodes_out` — so the whole-tree Device→Host copy is eliminated.
678- /// Callers gather query authentication paths from the device tree instead
679- /// (`crate::merkle::gather_merkle_paths_dev`) and use a root-only host tree for
680- /// the commitment.
643+ /// Fused LDE, leaf hash, and Merkle tree build that keeps both the LDE buffer
644+ /// and the Merkle tree (with root) resident on device, returned in `GpuLdeBase`.
645+ /// The host tree is not built (no `merkle_nodes_out`), so the whole tree copy to
646+ /// host is eliminated. Callers gather query paths from the device tree
647+ /// (`crate::merkle::gather_merkle_paths_dev`) and use a root only host tree.
681648pub fn coset_lde_batch_base_into_with_merkle_tree_keep (
682649 columns : & [ & [ u64 ] ] ,
683650 blowup_factor : usize ,
@@ -840,32 +807,32 @@ fn coset_lde_batch_base_into_with_merkle_tree_inner(
840807 crate :: merkle:: build_inner_tree_levels ( stream. as_ref ( ) , be, & mut nodes_dev, lde_size) ?;
841808 }
842809
843- // D2H the LDE columns via pinned staging (still read on host by constraint
844- // eval / openings ). The full tree nodes are D2H'd only when the caller asks
845- // for a host tree (`nodes_out`); the device- resident path passes ` None` and
846- // keeps the tree on device, eliminating the whole-tree D2H .
810+ // Copy the LDE columns to host via pinned staging (constraint eval and
811+ // openings still read them ). The full tree is copied only when the caller
812+ // wants a host tree (`nodes_out`); the resident path passes None and keeps
813+ // the tree on device.
847814 stream. memcpy_dtoh ( & buf, & mut pinned[ ..m * lde_size] ) ?;
848815 if let Some ( no) = nodes_out {
849816 d2h_bytes_via_pinned_hashes ( & stream, be, & nodes_dev, no) ?;
850817 }
851- // Ensure the ( async) LDE D2H above has landed before reading `pinned`.
852- // Previously the tree D2H's `synchronize` covered this; the device- resident
853- // path skips that D2H, so synchronize explicitly .
818+ // Make sure the async LDE copy above landed before reading `pinned`. The
819+ // tree copy used to provide this sync ; the resident path skips it, so sync
820+ // here .
854821 stream. synchronize ( ) ?;
855822
856- // Copy pinned into caller outputs. Runs under the pinned- staging lock,
823+ // Copy pinned into caller outputs. Runs under the pinned staging lock,
857824 // where rayon can deadlock. See `Backend::pinned_staging`.
858825 for ( c, dst) in outputs. iter_mut ( ) . enumerate ( ) {
859826 dst. copy_from_slice ( & pinned[ c * lde_size..c * lde_size + lde_size] ) ;
860827 }
861828 drop ( staging) ;
862829
863830 if keep_device_buf {
864- // Retain the device tree nodes for on- device opening (FullTree only; in
865- // LeavesOnly mode there are no inner nodes to gather paths from).
831+ // Retain the device tree for on device opening (FullTree only; LeavesOnly
832+ // has no inner nodes to gather paths from).
866833 let tree = if keep_tree && commit == KeccakCommit :: FullTree {
867- // Copy just the 32- byte root (node 0) so the commitment is available
868- // without D2H'ing the whole tree.
834+ // Copy just the 32 byte root (node 0) so the commitment is available
835+ // without copying the whole tree.
869836 let mut root = [ 0u8 ; 32 ] ;
870837 stream. memcpy_dtoh ( & nodes_dev. slice ( 0 ..32 ) , & mut root) ?;
871838 stream. synchronize ( ) ?;
@@ -891,60 +858,10 @@ fn coset_lde_batch_base_into_with_merkle_tree_inner(
891858 }
892859}
893860
894- /// Ext3 variant of `coset_lde_batch_base_into_with_leaf_hash`: fused
895- /// LDE + Keccak-256 leaf hashing over ext3 columns. Thin wrapper over
896- /// `coset_lde_batch_ext3_into_with_merkle_tree_inner` with `LeavesOnly`.
897- pub fn coset_lde_batch_ext3_into_with_leaf_hash (
898- columns : & [ & [ u64 ] ] ,
899- n : usize ,
900- blowup_factor : usize ,
901- weights : & [ u64 ] ,
902- outputs : & mut [ & mut [ u64 ] ] ,
903- hashed_leaves_out : & mut [ u8 ] ,
904- ) -> Result < ( ) > {
905- coset_lde_batch_ext3_into_with_merkle_tree_inner (
906- columns,
907- n,
908- blowup_factor,
909- weights,
910- outputs,
911- Some ( hashed_leaves_out) ,
912- KeccakCommit :: LeavesOnly ,
913- false ,
914- false ,
915- )
916- . map ( |_| ( ) )
917- }
918-
919- /// Ext3 variant of the fused `coset_lde_batch_base_into_with_merkle_tree`.
920- /// LDE + leaf hashing + inner-tree build, all on device; D2Hs only the LDE
921- /// evaluations and the full `2*lde_size - 1` node buffer.
922- pub fn coset_lde_batch_ext3_into_with_merkle_tree (
923- columns : & [ & [ u64 ] ] ,
924- n : usize ,
925- blowup_factor : usize ,
926- weights : & [ u64 ] ,
927- outputs : & mut [ & mut [ u64 ] ] ,
928- merkle_nodes_out : & mut [ u8 ] ,
929- ) -> Result < ( ) > {
930- coset_lde_batch_ext3_into_with_merkle_tree_inner (
931- columns,
932- n,
933- blowup_factor,
934- weights,
935- outputs,
936- Some ( merkle_nodes_out) ,
937- KeccakCommit :: FullTree ,
938- false ,
939- false ,
940- )
941- . map ( |_| ( ) )
942- }
943-
944861/// Ext3 variant of [`coset_lde_batch_base_into_with_merkle_tree_keep`]: keeps
945- /// both the de-interleaved LDE buffer and the Merkle tree (with root) resident
946- /// on device. The host tree is **not** materialised (no `merkle_nodes_out`), so
947- /// the whole-tree D2H is eliminated; openings gather paths from the device tree.
862+ /// both the deinterleaved LDE buffer and the Merkle tree (with root) resident on
863+ /// device. No host tree is built, so the whole tree copy to host is eliminated;
864+ /// openings gather paths from the device tree.
948865pub fn coset_lde_batch_ext3_into_with_merkle_tree_keep (
949866 columns : & [ & [ u64 ] ] ,
950867 n : usize ,
@@ -1103,15 +1020,15 @@ fn coset_lde_batch_ext3_into_with_merkle_tree_inner(
11031020 crate :: merkle:: build_inner_tree_levels ( stream. as_ref ( ) , be, & mut nodes_dev, lde_size) ?;
11041021 }
11051022
1106- // D2H the LDE columns. The full tree nodes are D2H'd only when the caller
1107- // asks for a host tree (`nodes_out`); the device- resident path passes ` None`
1108- // and keeps the tree on device, eliminating the whole-tree D2H .
1023+ // Copy the LDE columns to host . The full tree is copied only when the caller
1024+ // wants a host tree (`nodes_out`); the resident path passes None and keeps
1025+ // the tree on device.
11091026 stream. memcpy_dtoh ( & buf, & mut pinned[ ..mb * lde_size] ) ?;
11101027 if let Some ( no) = nodes_out {
11111028 d2h_bytes_via_pinned_hashes ( & stream, be, & nodes_dev, no) ?;
11121029 }
1113- // Ensure the ( async) LDE D2H has landed before reading `pinned` (the tree
1114- // D2H's synchronize used to cover this; the device- resident path skips it).
1030+ // Make sure the async LDE copy landed before reading `pinned` (the tree copy
1031+ // used to provide this sync ; the resident path skips it).
11151032 stream. synchronize ( ) ?;
11161033
11171034 unpack_pinned_slabs_to_ext3 ( pinned, outputs, lde_size) ;
0 commit comments