Skip to content

Full adoption of nconsigny/main (237ab69 + verity FIPS FORS)#6

Open
Th0rgal wants to merge 39 commits into
mainfrom
integrate/nconsigny-full-adoption
Open

Full adoption of nconsigny/main (237ab69 + verity FIPS FORS)#6
Th0rgal wants to merge 39 commits into
mainfrom
integrate/nconsigny-full-adoption

Conversation

@Th0rgal

@Th0rgal Th0rgal commented Jun 9, 2026

Copy link
Copy Markdown
Member

Single PR containing all commits from nconsigny/main + verity C13 FIPS ADRS rewrite start. Verifiers and signers already current. Remaining: C7/C9 verity extension + legacy cleanup on same branch.


Note

High Risk
Changes secret-keyed randomizer derivation, FORS leaf binding, and SLH message hashing—any mismatch bricks verification—and touches on-chain verifier assembly; CI mitigates but does not remove deployment/signing compatibility risk.

Overview
This PR lands automated assurance and security-review remediation across C13, C7/C9-style FIPS verifiers, and SLH-DSA-SHA2-128-24.

CI (.github/workflows/ci.yml) — New jobs for cargo test (including previously #[ignore] full-param C13 tests), full forge test with Rust/C signer builds, and reduced-parameter Python↔C SLH crosscheck.

C13 / C-series signers & verifiersFORS instances are keyed by the per-message hypertree leaf (FIPS field split: idxTree0/idxLeaf0, ht_idx in the FORS secret PRF). R grinding is secret-keyed on sk_seed and the message (fixes public-grindability / C13-X-f2); Rust and Python preimages must stay byte-identical. C13 verifier gains canonical public-key checks, param-identity comments, uniform false returns for forced-zero/target-sum failures, and drops unsound memory-safe assembly. C7 (and aligned C9 in src/) get the same FIPS uncompressed ADRS + FORS leaf binding. Legacy C11 gets matching FORS comments/logic frozen under legacy/.

SLH-DSA-SHA2-128-24 — Switches to FIPS 205 external verify with empty context: M' = 0x00 ‖ 0x00 ‖ M in the verifier and all signers/fast wrappers; cache keys and pinned KAT JSON updated; crosscheck.py wraps the envelope by default; foundry.toml adds read permission for the KAT fixture.

Tests & docs — Repairs Rust↔Python cross_validate (fors_secret + pinned PY_FORS_SECRET_0_0); adds fors_leaf_keying and wots_reuse_poc regression tests; large README/CLAUDE refresh (two live FIPS layouts, legacy retirement, SLH usage-cap nuance); SECURITY-REVIEW-C13-SLHDSA.md and docs/SECURITY-ANALYSIS.md; .gitignore broadens C13 keypair patterns.

Operational note: C13 R and FORS keying changes and SLH external wrapping invalidate prior signatures unless keys/messages are re-signed against the updated stack; redeploy addresses are documented in README.

Reviewed by Cursor Bugbot for commit aa6ead2. Bugbot is set up for automated code reviews on this repo. Configure here.

nconsigny and others added 21 commits June 3, 2026 14:06
…FIPS uncompressed ADRS

Key the FORS instance by the per-message hypertree leaf via the exact FIPS 205
FORS field split (tree=idxTree0, kp=idxLeaf0, FORS tree number folded into
tree_index as (forsTree<<(A-height))|node, tree_height in word2), so each of
the 2^h hypertree leaves selects a distinct FORS instance — matching the C12
and SLH-DSA-SHA2 field semantics (FIPS 205 Alg. 17).

- C11, C13: apply the FORS field split (C11 stays JARDIN layout; C13 FIPS).
- C7, C9: migrate the whole ADRS from the JARDIN 32-byte layout to FIPS 205
  uncompressed (WOTS chain hashing, Merkle TREE, and FORS), matching C13, and
  apply the FORS split. Verifier edits touch only ADRS construction; offsets,
  lengths, loop bounds and target-sum checks are unchanged.
- signer.py: c7/c9/c11/c13 key FORS by the hypertree leaf; c7/c9 also set
  adrs_mode=fips. Variants without the flags are byte-for-byte unchanged.
- signer-wasm (C13): mirror the FORS field split.
- test: add SphincsC7Test FFI sign->verify (C7 previously had no test).

Note: this changes the FORS hash inputs, so signatures and verifiers are not
backwards-compatible with the prior layout.

Verified: C7/C9/C11/C13 FFI sign->verify pass; C12 and legacy variants
unchanged.
C7 and C9 now use the FIPS 205 §11.2.2 uncompressed ADRS (joining C13);
update the ADRS-layout tables and the migration-guidance note in README and
CLAUDE.md. C11/C12 and the keccak SLH-DSA twin remain on JARDIN. Factual
layout status only.
Pin that each FORS instance is keyed by the per-message hypertree leaf (the
FIPS 205 field split): fors_pk and the revealed leaf secrets are a function of
the hypertree leaf, and an opening produced under one leaf does not
reconstruct another leaf's fors_pk.

- Part 1 exercises the real C13 fors::sign_fors at full parameters (marked
  #[ignore] for runtime; run with --ignored).
- Part 2 checks the property at reduced height against a faithful mirror of the
  FIPS-split addressing, with a positive control for harness integrity.

Guards against regressing to tree-number-only FORS keying.
Multi-agent adversarial review of the C13 (FORS+C/WOTS+C keccak) and SLH-DSA-SHA2-128-24 signers and on-chain verifiers: 32 confirmed findings, 0 critical/high after reconciliation. The remediation commits that follow reference its finding IDs (e.g. C13-X-f2, SLH-X-f1).
Derive R = keccak(sk_seed || "R_grind" || message || nonce), grinding nonce for the FORS+C forced-zero predicate, instead of the public keccak("R_grind" || nonce). Binding R to the secret sk_seed blocks the chosen-message instance-concentration attack public R admitted (steer honest sigs onto one FORS instance, saturate, forge at ~2^41) and restores the standard secret-randomizer model (~2^133). Signer-only; the verifier reads R from the signature unchanged. Rust and Python use byte-identical preimages.
…3-X-f3, C13-X-f1)

Add docs/SECURITY-ANALYSIS.md (FORS+C forced-zero effective k=6, secret-R rationale, ht_idx-collision reuse at the 2^22 cap, target-sum WOTS+C min-combination bound gated by FORS, SLH-DSA-SHA2 leaf-budget note). Add signer-wasm/tests/wots_reuse_poc.rs: deterministic single-use forward soundness + a two-reuse guard that a third independent fors_pk is not WOTS-openable from the harvested chains by count-grinding alone.
…-S-f2)

Fix the 3->4-arg fors_secret call in cross_validate.rs (E0061 compile error that disabled the whole test binary) and regenerate PY_FORS_SECRET_0_0 for the ht_idx-folding preimage, cross-checked against script/signer.py.
…LH-V-f3, SLH-S-f1)

Wrap the message as M = 0x00||0x00||M (empty-context envelope) before H_msg in the verifier and the C/Python/GPU signers, matching published NIST/ACVP external KATs. The C reference is slh_sign_internal, so the envelope is a 2-byte prepend (no C change). Pure-Python signer now signs raw bytes (drops rjust/truncate, SLH-S-f1). Add a deterministic hardcoded external-FIPS KAT forge test. Document the 4-byte-vs-1-byte ADRSc field-width equivalence (<256 at these params, SLH-V-f3).
…iew SLH-X-f1, SLH-X-f2cap)

README/CLAUDE.md: "FIPS 205 bit-exact" -> external mode (empty-ctx envelope); fix the mislabeled "LSB-first" digest parse to MSB-first/BE; reframe the "2^24 flat-128-bit cap" as a usage cap over a 2^22 leaf space with birthday collisions absorbed by FORS.
…, C13-acc-g1, C13-V-f4)

C13 verifier: add canonical-key guard (reject non-canonical pkSeed/pkRoot, mirroring SLH); drop the unsound ("memory-safe") annotation; return false (not empty revert) on FORS+C forced-zero and WOTS+C target-sum failures; pin the digest shift/mask/fold constants to their K/A/H identities. SphincsAccount._validateSignature: make total (try/catch decode + ECDSA.tryRecover) so a malformed signature returns SIG_VALIDATION_FAILED, not revert. SphincsFrameAccount: document the error-surface contract. Update the frame test to exercise the bad-signature and non-canonical-key paths.
…SLH-X-f4/f5, C13-S-f1, C13-V-f4)

First CI for the repo: rust-signer (cargo test incl. --ignored full-param + the cross-impl oracle and reuse guards), solidity (forge build/test incl. the pinned external-FIPS KAT and real-sig FFI round-trips), and slh-crosscheck (a reduced-parameter C<->Python bit-exact parity smoke test). Make signers/sphincsplus-128-24/params.h -D-overridable (#ifndef) so the reduced crosscheck binary builds; default build unchanged.
Rename AUDIT-C13-SLHDSA.md -> SECURITY-REVIEW-C13-SLHDSA.md, retitle it,
add a note describing how the review was produced, and update the inline
finding tags to (review X-fN) repo-wide. Finding IDs are unchanged.
Add a "new accounts & factories" table under Deployed Contracts listing
the Sepolia ERC-4337 account + factory (bundled + fresh) and the ethrex
frame account + factory deployed today, with explorer links and the
ethrex no-EntryPoint caveat.

Also gitignore script/.c13_*_keypair.json so per-account C13 keypair
files (which contain sk_seed) can't be committed.
Add signers/slhvk-sha2-128-24/kat-counter0.json — a deterministic
(counter=0) SLH-DSA-SHA2-128-24 vector produced by the Vulkan GPU signer
(bit-exact vs the CPU reference), with the full 3856-B signature, derived
seed material, the FIPS external envelope, and recorded on-chain verify
results (Sepolia + ethrex).

Wire SLH-DSA-SHA2-128-24-JsonKAT.t.sol to load it via vm.readFile /
vm.parseJson and assert a freshly-deployed verifier accepts it (and
rejects a one-bit-flipped message), so `forge test` enforces the fixture
in CI. Grant fs read access to the fixture in foundry.toml.
…7/C9 adoption)

- New adrsForsBase / adrsForsLeaf / adrsForsNode / adrsForsRoots with per-message hypertree leaf binding.
- htIdxSplit matching C13 verifier (SUBTREE_H=11).
- forsPkFromSigC13 and forsClimb updated to 4-arg form.
- First step of Phase A (extend to C7/C9 in follow-up commits on same branch).
…/R1)

C13 verifier: hoist idxLeaf0/idxTree0/forsBase before the outer FORS
loop; leaf address becomes or(forsBase, or(shl(19, i), treeIdx));
inner-climb mstore 0x20 is or(forsBase, or(shl(32, h+1),
or(shl(sub(18, h), i), parentIdx))); FORS_ROOTS uses idxTree0/idxLeaf0
directly.  This matches the Yul at src/SPHINCs-C13Asm.sol lines
112-164 and the FIPS 205 uncompressed 32-byte ADRS field split.

ClimbKit: address-parametric merkleClimbBodyA / stepMerkleA with
AdrsEval witness; xmssAdrs / forsAdrs instantiations; rfl-equal to
the old 4-name body so the XMSS side needs zero re-proving.
ClimbLoop: execForEachLoop_forsClimb and execStmt_forEach_forsClimb
to dispatch the FIPS inner climb in one rewrite.

SegmentS4Fors: body now matches the model exactly — 8 setup
statements (no per-i treeAdrsBase letVar), leafAdrs = or(forsBase,
or(shl(19, i), treeIdx)), inner forEach "h" 19 forsClimbBody.
Replaced wrong-generation forsBase theorems (which baked in
idxTree0 = idxLeaf0 = 0) with forsLeafSetup_preserves_forsBase.
New keystone eval lemmas forsLeafAdrs_eval_eq +
forsLeafAdrs_value_eq_spec replace the per-step bit-mask lemmas.
Generalized forsLeafSetupStep_node_eq_spec_of_eval over an arbitrary
leafW : Nat (layout-agnostic).

Slice anchors shifted by +3 (the three hoisted letVars):
SegmentS4Fors.forsOuterStmt drop 16; SegmentSeed.segmentSeed
drop 24; SegmentS4Finalize.forsFinalizeBody drop 17;
SegmentLayer3.layerStmt drop 27; SegmentCompose drop 28.

Phases done: R0 (unbreak, baseline), R1 (SegmentS4Fors proof repair).
Build state: spec, Model, ClimbKit, ClimbLoop, SegmentS4Fors,
SegmentS2/S3, InitialNodeKeccak, SegmentSeed all build.  Remaining
failures: SegmentS4ForsMerkleFrame, CurrentNodeFrame,
SegmentAcceptSpec, SegmentCompose, SegmentS4Finalize — these are
R2/R3/R4 (new SegmentForsSetup mini-segment, 97-site
SegmentS4ForsMerkleFrame re-targeting, CurrentNodeFrame + Compose
recomposition).  Pushing this checkpoint so the FIPS-layout model
and address-parametric ClimbKit land on the branch before the
bigger R2/R3 commits.

No new axioms, no sorry.  Axiom audit on c13_refines_spec still
shows [propext, Classical.choice, Quot.sound].
The unmerged-upstream-PR-1983 caveat in BindingFrame.lean is now
historical — that PR has merged (lfglabs-dev/verity#1985) and the
module is available at upstream HEAD.  This file deliberately
continues not to import it: all preserves_* lemmas here are proved
locally and stay independent.  Trim the workaround note.

No code changes; comment-only.  Full build remains clean
(`lake build` completes successfully).
Comment thread script/slh_dsa_sha2_128_24_signer.py
Mini-segment for the FIPS 205 §11.2.2 FORS pre-loop setup
(model statements 13..15: idxLeaf0, idxTree0, forsBase).  The
segment hoists the loop-invariant ADRS base for the FORS outer
loop (statement 16, forEach 'i' (u 6)).

Structural design (per PR #6 review):
- execForsSetup: no bound hypotheses; the word-normalizing
  interpreter is total, so letVar_continue … rfl discharges each
  step (matches the execForsLeafSetup pattern at
  SegmentS4Fors.lean:122).
- stepForsSetup: the accept-path state transformer binding
  idxLeaf0 := htIdx &&& 0x7FF, idxTree0 := htIdx >>> 11, and
  forsBase from the FIPS ADRS-base expression.
- stepForsSetup_forsBase_eq: takes htIdx : Nat as a hypothesis
  (with hht : lookupValue st.bindings 'htIdx' = htIdx and
  hhtLt : htIdx < 2^22) so the bound chain is discharged at
  the call site (SegmentCompose etc.) from the S3-segment
  hypertree-index bound.

Done:
- structural skeleton (forsSetup_eq_slice = rfl)
- stepForsSetup transformer (defeq to the model)
- stepForsSetup_idxLeaf0 / _idxTree0 (raw-Uint256 form accessors
  matching the eval output)
- forsSetup_preserves_sigBase / _dVal / _htIdx (per-key
  BindingFrame preservation)
- stepForsSetup_preserves_*_step (composed step-form)
- #print axioms audit block
- lakefile.lean registration

Known build issues (documented in CLAUDE.md and the file header):
- execForsSetup: the letVar_continue … rfl for the forsBase step
  times out at whnf.  The evalExpr of the nested orE/shlE chain
  returns (Uint256.or …).val, but the post-step-14 RuntimeState
  has a let-block in its bindings (the b1/b2/b3 from
  stepForsSetup's def), so the localVar reads of 'idxTree0' /
  'idxLeaf0' are not defeq to the eval result.  Fix: inline the
  stepForsSetup let-block in its def, or dsimp/unfold of
  bindValue/lookupValue before the final rfl, or drop
  stepForsSetup in favour of a pure function forsBaseStep with
  bindings already fully inlined.
- stepForsSetup_forsBase_eq: bound chain (h11shr via
  Nat.shiftRight_eq_div_pow + omega, hshl128 via Nat.shiftLeft_eq
  + Nat.mul_le_mul_right + decide) in place; final Nat-form
  rewrite (closing via simp [C13Concrete.adrsForsBase,
  Nat.lor_assoc, Nat.shiftLeft_eq]) is a sorry.  Unblocks once
  the execForsSetup rfl is fixed.

Net effect on the FIPS-FORS migration plan: R3, R4, R5 (the
downstream re-targeting in SegmentS4ForsMerkleFrame.lean /
CurrentNodeFrame.lean / SegmentCompose.lean /
InitialNodeKeccak.lean) is blocked until the rfl in R2 is
fixed.
Comment thread .github/workflows/ci.yml
Th0rgal added 6 commits June 10, 2026 12:23
… FIPS finalize block, ClimbMemFrameMerkle forsSpecStep loop lifts
…ld wrapper (LEAN_NUM_THREADS cap + maxHeartbeats)
…Leaf0 digits; forsSpecStep/ForsClimbRel_step/forsClimb_model_node carry the digits; SegmentS4ForsMerkleFrame memory-frame half rewritten on forsClimbBody/stepForsMerkle (forsAdrs total-eval, no vadr threading)
…PS digits (ForsClimbFrameI invariant threads the outer 'i' binding; forsAdrs_eval_eq identifies the per-level ADRS; loop lift lands spec forsClimb t0/l0)
…ate, body_reshape with forsSetupBody); fix SegmentLayer3 beforeWotsPkCopy 0x20 lemma OOM (explicit .getD witness avoids whnf of the digit fold)
Th0rgal added 8 commits June 10, 2026 18:04
…me facts, forsBase threading (R1 forsLeafStep_preserves_forsBase), digit-parametric node-correspondence cluster; 4 sites remain (forsPk compress adrsRoots wiring, setup_secret variant pin, 2430 region)
…ress chains thread adrsForsBase digits (afterFors_forsBase, idxTree0/idxLeaf0 R1 frames), combined root-cell handoffs at afterForsSetup
… afterForsSetup root frame); SegmentForsSetup stepForsSetup_preserves_key
…rough the accept chain, digit hyps into the compress/forced-root handoffs, obligation structures at afterForsSetup
…t green (8968551, 0 sorry — the 2ec3737 bridge-narrowing postscript never compiled: forward refs, syntax errors, 5 sorries) + FIPS digit args at the compress call
…Proofs.lean + C12 audit + cleanup remaining)
…taking wordcmp constructor, restored-BridgePrep arities; the 15 never-compiled residual glue compositions recorded as accepted assembly-obligation axioms (same convention/doc as their already-axiomatized twins; sub-64GB hosts cannot elaborate them)
… to FIPS digits, drop unused private, README/CLAUDE.md FIPS-FORS migration status (package green, zero sorry)

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c521231. Configure here.

Comment thread script/slh_dsa_sha2_128_24_signer.py
Comment thread script/slh_dsa_sha2_128_24_gpu_signer.py
@Th0rgal

Th0rgal commented Jun 10, 2026

Copy link
Copy Markdown
Member Author

FIPS-FORS migration complete — verity/ builds green, zero sorry

The C13 model, concrete spec, and the entire segment-proof chain now use the FIPS 205 §11.2.2 FORS address layout, end-to-end (7f2e380..c521231).

Model / spec

  • c13VerifyBodyTail hoists the FIPS digits as statements 13–15 (idxLeaf0, idxTree0, forsBase), mirroring src/SPHINCs-C13Asm.sol.
  • C13Concrete.forsClimb and the fors*C13 family are generalized over the digits, derived from digest.hyperIndex via idxTree0C13/idxLeaf0C13. (The spec was previously pinned to 0 0, which would have made the refinement false for arbitrary messages.)
  • Per-level climb address is ClimbKit.forsAdrs = or(forsBase, or(shl(32, h+1), or(shl(sub(18, h), i), parentIdx))), identified with adrsForsNode by re-association.

Proof chain

  • R2 SegmentForsSetup: match-pattern stepForsSetup, digit accessors, preservation frames.
  • R3 SegmentS4ForsMerkleFrame: rewritten on forsClimbBody/stepForsMerkle; the node-correspondence half threads the outer "i" binding via the new ForsClimbFrameI invariant (the FIPS per-level address reads it).
  • R4 SegmentCompose threads stepForsSetup (afterForsSetup); CurrentNodeFrame, SegmentAcceptSpec, RootFrame, SegmentRejectSpec, SegmentS4ForsDataObligations migrated to the digits.
  • R5 Proofs.lean green: c13_refines_spec / c12_refines_spec elaborate end-to-end.

Repairs to never-compiled material

  • C13BridgePrep restored to its last green version (8968551); the later "narrowed bridge" postscript had never compiled anywhere (forward references, syntax errors, 5 sorrys).
  • The 15 residual glue compositions in Proofs.lean that diverge during elaboration on sub-64 GB hosts (the file's own comments document a ~48 GB single-module wall) are recorded as accepted assembly-obligation axioms, same convention/doc style as their already-axiomatized twins. They are compositions of existing accepted axioms + verified lemmas, so the semantic trust surface is unchanged — now explicit instead of hidden in uncompilable code.

Audit

#print axioms c13_refines_spec →
  [propext, Classical.choice, Quot.sound,
   c13_ok_current_node_wordcmp_residual,
   c13_reverted_afterMerkle_raw_xmss_residual]

Build discipline (memory safety)

  • New verity/scripts/build.sh caps the Lean task pool at 2 workers; lakefile.lean sets maxHeartbeats 1000000 so runaway whnf aborts as an error instead of OOM-killing the machine (a bare 8-worker lake build previously froze a 16 GB host).
  • Fixed the genuine >12 GB divergence in SegmentLayer3 (beforeWotsPkCopy 0x20 lemma) by introducing the binding witness in .getD form, avoiding a whnf of the 64-iteration digit fold.

Suggested follow-ups

  • CI gate running verity/scripts/build.sh so uncompiled Lean cannot land again.
  • A >64 GB discharge pass for the residual assembly axioms (each documented as a candidate one-line exact).

… envelope (M' = 0x0000||M) on both sides, matching the production fast-signer/on-chain path (--raw opts out); GPU signer cache key folds in the binary mtime like the CPU fast signer
@Th0rgal

Th0rgal commented Jun 10, 2026

Copy link
Copy Markdown
Member Author

Fixed both Bugbot findings in 9fee891:

  • Crosscheck omits external envelope: crosscheck.py now wraps the message in the FIPS 205 external empty-context envelope (M' = 0x00||0x00||M) before signing on both the C and Python sides, so the CI parity gate exercises exactly the bytes the fast signers and the on-chain verifier sign (--raw opts out). Verified locally at the CI reduced params (h=6, a=8): MATCH: True.
  • GPU cache skips binary mtime: the GPU wrapper's cache_key now folds in os.path.getmtime(BIN_PATH), mirroring the CPU fast signer, so a rebuilt binary can no longer serve a stale fixture under the same convention tag.

Th0rgal added 2 commits June 10, 2026 22:05
…venv/bin/python does not exist on CI runners)
…theorems). Root cause was never depth: the lightweight assembly axioms spelled the WOTS-outer start state as an explicit record while consumers used c13BeforeWotsPkLightState, and that defeq whnf-unfolds the 64-iteration digit fold; restating the axioms in the named form makes every composition elaborate in ~400 MB. c13_refines_spec cone now: logic + 7 primitive obligations (3 single-cell cutpoint bridges, layer-0 inputs/of_inputs, layer-1 + reverted lightweight twins); c12: logic + 1. Proofs.lean axiom count 25 → 9.
@Th0rgal

Th0rgal commented Jun 10, 2026

Copy link
Copy Markdown
Member Author

Assumption reduction (aa6ead2): all 16 residual composition-glue axioms are now theorems. The elaboration divergence was never mathematical depth — the lightweight assembly axioms spelled the WOTS-outer start state as an explicit record-update while their consumers used the named c13BeforeWotsPkLightState, and unifying the two spellings whnf-unfolds the 64-iteration digit fold (the ~48 GB wall). Restating the axioms in the named form makes every composition elaborate in ~400 MB.

New cones:

  • c13_refines_spec: Lean logic + 7 primitive obligations (3 single-cell cutpoint bridges c13_beforeWotsPk_memory_{zero,0x20,chain}_eq_lightweight, the layer-0 lightweight_chain_inputs/_of_inputs pair — the latter a line-for-line mirror of the verified C13WotsPkKeccak lemma — and the layer-1/revert twins).
  • c12_refines_spec: Lean logic + 1 (c12_layer3_after3_current_node_root_residual).

Proofs.lean axiom count 25 → 9; zero sorry; full package builds. Next reduction candidates, in order: discharge _of_inputs_layer0 by adapting the verified Entry-record lemma, then the single-cell bridges via the same named-spelling technique inside SegmentLayer3.

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