Files
pulsar/proofs/easycrypt/Pulsar_N1_Sign_Wrapper.ec
zeekay c79fe61d62 consolidate: merge pulsar-mptc submission framework into canonical luxfi/pulsar
Single repo, one canonical impl + spec + proofs + KAT + cut tool.

Per "ONE and ONLY ONE way to do things" the prior dual-repo split
(luxfi/pulsar = production library, luxfi/pulsar-mptc = NIST MPTC
submission framework) is collapsed into a single canonical home at
github.com/luxfi/pulsar. SINGLE-IMPL-PLAN.md (now marked COMPLETED)
describes the steps; this commit lands the final step.

Files moved (89 new):
  16 submission docs (SUBMISSION, NIST-SUBMISSION, SPEC, SUITE,
     PATENTS, AXIOM-INVENTORY, PROOF-CLAIMS, FIPS-TRACEABILITY,
     TRUSTED-COMPUTING-BASE, HANZO-CRYPTO-SUITE, INFORMATION-
     ARCHITECTURE, ROADMAP, CHANGELOG, SYNC-STATUS, STATUS-
     SUBMISSION-READINESS, SINGLE-IMPL-PLAN)
  10 docs/ supplements (ietf-draft-skeleton, magnetar, evaluation,
     patent-claims, x-wing-sig, design-decisions, family-architecture,
     threat-model, nist-mptc-category, patent-notes-draft)
  19 proofs/ (13 EC theories + 2 EC lemmas + 4 metadata/READMEs +
     lean-easycrypt-bridge.md)
  14 jasmin/ (lib/* + ml-dsa-65 fetch + threshold/{combine,round1,
     round2}.jazz + READMEs)
  10 ct/dudect/ (Makefile, combine_ct.go, dudect_combine.c,
     dudect_compat.h, dudect_verify.c, fetch.sh, README, run-
     submission.sh, verify_ct.go) + ct/jasmin-ct-libjade.md
  1 .github/workflows/ci.yml
  1 test/interoperability/n1_class_test.go (19/19 N1 subtests)
  1 bench/results/REPORT.md
  11 scripts/ (cut-submission, check-high-assurance, check-lean-
     bridge, nightly, extract-jasmin-ec, checks/{ec-admits, ec-
     compile, ec-refinement-scaffold, ec-regressions, extraction,
     jasmin}, checks/test/{go-unit, interop, kat, no-secret-logs})

Files merged (16 overlapping, mptc-canonical chosen because newer +
post-rewire-correct; pulsar versions still bore stale "Pulsar-M" /
"pulsarm" branding):
  README.md, BLOCKERS.md, CONTRIBUTING.md, LICENSE, LICENSING.md,
  SECURITY.md, .gitignore, bench/run_all.sh, vectors/dkg.json (v1.0.7
  regen), scripts/{bench,build,gen_vectors,sbom,test}.sh,
  spec/{pulsar,parameters,system-model}.tex,
  CRYPTOGRAPHER-SIGN-OFF.md (path refs).

Pulsar-only spec supplements preserved:
  spec/{blockers,design-decisions,family-architecture,nist-mptc-
  category,patent-notes,threat-model}.tex.

Path rewrites applied: 158 occurrences across 26 files
  github.com/luxfi/pulsar-mptc -> github.com/luxfi/pulsar
  ~/work/lux/pulsar-mptc/      -> ~/work/lux/pulsar/
  luxfi/pulsar-mptc            -> luxfi/pulsar
  pulsar-mptc/                  -> ./

Narrative collapses (no more two-repo framing):
  SUBMISSION.md "At a glance" — single Repository row
  SYNC-STATUS.md — rewritten to single-repo state
  SINGLE-IMPL-PLAN.md — marked COMPLETED 2026-05-18
  HANZO-CRYPTO-SUITE.md — tier 1 row = single canonical home
  scripts/cut-submission.sh — replace/vendor dance removed; cuts
  directly from in-tree canonical sources

go.mod: dropped mptc's replace directive (no longer needed since this
IS the canonical pulsar repo). Module path is github.com/luxfi/pulsar.
Deps: cloudflare/circl v1.6.3, golang.org/x/crypto v0.32.0.

Verification:
  GOWORK=off go build ./...              PASS
  GOWORK=off go test -count=1 ./...      PASS (1.4s)
  GOWORK=off go test -race ./ref/...     PASS (14.7s)
  go test ./test/interoperability/       PASS (19/19 N1 subtests)
  scripts/check-high-assurance.sh        PASS
  scripts/check-lean-bridge.sh           PASS (5/5 bridges)
  scripts/gen_vectors.sh                 byte-identical replay
  scripts/cut-submission.sh --help       PASS
2026-05-18 19:53:08 -07:00

227 lines
9.2 KiB
Plaintext

(* -------------------------------------------------------------------- *)
(* Pulsar — Class N1 sign wrapper *)
(* -------------------------------------------------------------------- *)
(* Decomplected from Pulsar_N1_Wrapper_Bridge.ec. *)
(* *)
(* This file owns ONE thing: the sign-side wrapper machinery that lifts *)
(* the extracted libjade M.sign byte-walk into a procedure-level equiv *)
(* against Pulsar_N1.FIPS204Sign.sign. Specifically: *)
(* *)
(* - n1_share_to_layout_sign, n1_msg_to_layout_sign — adapters *)
(* - n1_inputs_to_sign_full — builds sign_full_args_t *)
(* - encode_sign_args — composes adapter + Layout encoder *)
(* - sign_wrapper_bridge — the byte-level wrapper-bridge lemma *)
(* - SignExtractedWrapper — module satisfying MLDSA65_Sign *)
(* - sign_wrapper_equiv_FIPS204Sign — procedure-level equiv *)
(* *)
(* The combine-side mirror is Pulsar_N1_Combine_Wrapper.ec. The *)
(* composition into pulsar_n1_byte_equality_extracted lives in *)
(* Pulsar_N1_Extracted.ec. *)
(* -------------------------------------------------------------------- *)
require import AllCore List Int IntDiv Distr DBool DInterval SmtMap.
(* Sign-side refinement: sign_full_args_t, wire_sign_args_of_full,
refine_sig_to_n1_sign, sign_body_fn, proven sign_body_spec
lemma + sign_abs_op definition. *)
require import Pulsar_N1_Sign_Refinement.
(* Concrete sign layout: encode_sign_args + encode_sign_args_layout
aggregate lemma + read_sig_sign. *)
require import Pulsar_N1_Sign_Layout.
(* Memory: shared mem_t used by both layouts. *)
require import Pulsar_N1_Memory.
(* Pulsar_N1: protocol types + MLDSA65_Sign module type +
FIPS204Sign abstract module + mldsa_sign_op. *)
require import Pulsar_N1.
(* ===================================================================
Wire derivation ops.
Project the protocol-level Pulsar_N1 types onto the Sign_Layout
file's LOCAL abstract wire types. These mirror the combine-side
`derive_*_wire` ops.
`n1_share_to_layout_sign` projects the abstract Pulsar_N1
`share_t` onto the byte-encoded FIPS 204 §3.5.4 sk packing
(rho || K || tr || s1 || s2 || t0). This is the secret-key
adapter the threshold wrapper uses when calling libjade.
`n1_msg_to_layout_sign` projects the abstract Pulsar_N1
`message_t` onto the libjade-side message byte layout.
`ctx` and `rho_rnd` do NOT have wire-layer counterparts —
libjade's M.sign has no ctx/rnd parameters (the threshold
wrapper handles them BEFORE calling libjade by folding ctx
into mu and rho_rnd into K-derived randomness). They appear
only as GHOST fields in `sign_full_args_t` (see the GHOST
CONTRACT block in Pulsar_N1_Sign_Refinement.ec).
=================================================================== *)
op n1_share_to_layout_sign :
Pulsar_N1.share_t -> Pulsar_N1_Sign_Layout.share_t.
op n1_msg_to_layout_sign :
Pulsar_N1.message_t -> Pulsar_N1_Sign_Layout.message_t.
(* ===================================================================
Bundle adapter + concrete encoder.
=================================================================== *)
op n1_inputs_to_sign_full
(sk : Pulsar_N1.share_t) (m : Pulsar_N1.message_t)
(ctx : Pulsar_N1.ctx_t) (rho_rnd : Pulsar_N1.randomness_t)
: sign_full_args_t =
{| sgn_wire =
{| sk_abs = n1_share_to_layout_sign sk;
m_abs = n1_msg_to_layout_sign m; |};
sgn_sk_n1 = sk;
sgn_m_n1 = m;
sgn_ctx_n1 = ctx;
sgn_rnd_n1 = rho_rnd; |}.
op encode_sign_args
(sk : Pulsar_N1.share_t) (m : Pulsar_N1.message_t)
(ctx : Pulsar_N1.ctx_t) (rho_rnd : Pulsar_N1.randomness_t)
: Pulsar_N1_Memory.mem_t *
Pulsar_N1_Sign_Layout.sign_ptrs_t *
sign_full_args_t =
let full = n1_inputs_to_sign_full sk m ctx rho_rnd in
let (mem, ptrs) =
Pulsar_N1_Sign_Layout.encode_sign_args
full.`sgn_wire.`sk_abs
full.`sgn_wire.`m_abs
(Pulsar_N1_Sign_Layout.msg_len full.`sgn_wire.`m_abs) in
(mem, ptrs, full).
(* ===================================================================
Sign wrapper bridge — PROVED.
Mirrors the combine-side proof:
- encode_sign_args_layout (PROVED in Sign_Layout)
- sign_body_spec (lemma in Sign_Refinement, derived from
sign_body_compute_sig_spec axiom)
- sign_abs_op definition (folds the four ghost fields into
mldsa_sign_op directly)
=================================================================== *)
lemma sign_wrapper_bridge :
forall (sk : Pulsar_N1.share_t)
(m : Pulsar_N1.message_t)
(ctx : Pulsar_N1.ctx_t)
(rho_rnd : Pulsar_N1.randomness_t),
Pulsar_N1.accept_signing_attempt sk m ctx rho_rnd =>
let (mem, ptrs, full) = encode_sign_args sk m ctx rho_rnd in
Pulsar_N1_Sign_Refinement.refine_sig_to_n1_sign
(Pulsar_N1_Sign_Layout.read_sig_sign
(Pulsar_N1_Sign_Refinement.sign_body_fn mem ptrs)
ptrs.`Pulsar_N1_Sign_Layout.ptr_signature)
= Pulsar_N1.mldsa_sign_op sk m ctx rho_rnd.
proof.
move=> sk m ctx rho_rnd Haccept /=.
rewrite /encode_sign_args /=.
have Hlay :
Pulsar_N1_Sign_Layout.layout_sign_args
(Pulsar_N1_Sign_Layout.encode_sign_args
(n1_share_to_layout_sign sk)
(n1_msg_to_layout_sign m)
(Pulsar_N1_Sign_Layout.msg_len (n1_msg_to_layout_sign m))).`1
(Pulsar_N1_Sign_Layout.encode_sign_args
(n1_share_to_layout_sign sk)
(n1_msg_to_layout_sign m)
(Pulsar_N1_Sign_Layout.msg_len (n1_msg_to_layout_sign m))).`2
(wire_sign_args_of_full
(n1_inputs_to_sign_full sk m ctx rho_rnd)).
- rewrite /wire_sign_args_of_full /n1_inputs_to_sign_full /=.
by apply Pulsar_N1_Sign_Layout.encode_sign_args_layout.
have Hacc :
Pulsar_N1.accept_signing_attempt
(n1_inputs_to_sign_full sk m ctx rho_rnd).`sgn_sk_n1
(n1_inputs_to_sign_full sk m ctx rho_rnd).`sgn_m_n1
(n1_inputs_to_sign_full sk m ctx rho_rnd).`sgn_ctx_n1
(n1_inputs_to_sign_full sk m ctx rho_rnd).`sgn_rnd_n1.
- by rewrite /n1_inputs_to_sign_full /=.
have Hspec :=
Pulsar_N1_Sign_Refinement.sign_body_spec
(Pulsar_N1_Sign_Layout.encode_sign_args
(n1_share_to_layout_sign sk)
(n1_msg_to_layout_sign m)
(Pulsar_N1_Sign_Layout.msg_len (n1_msg_to_layout_sign m))).`1
(Pulsar_N1_Sign_Layout.encode_sign_args
(n1_share_to_layout_sign sk)
(n1_msg_to_layout_sign m)
(Pulsar_N1_Sign_Layout.msg_len (n1_msg_to_layout_sign m))).`2
(n1_inputs_to_sign_full sk m ctx rho_rnd)
Hlay Hacc.
move: Hspec.
rewrite /Pulsar_N1_Sign_Refinement.sign_abs_op
/n1_inputs_to_sign_full /=.
by rewrite /Pulsar_N1.mldsa_sign_op /=; move=> ->.
qed.
(* ===================================================================
Concrete extracted-wrapper module.
=================================================================== *)
module SignExtractedWrapper : Pulsar_N1.MLDSA65_Sign = {
proc sign(sk : Pulsar_N1.share_t,
m : Pulsar_N1.message_t,
ctx : Pulsar_N1.ctx_t,
rho_rnd : Pulsar_N1.randomness_t)
: Pulsar_N1.signature_t = {
var enc : Pulsar_N1_Memory.mem_t *
Pulsar_N1_Sign_Layout.sign_ptrs_t *
sign_full_args_t;
var mem_post : Pulsar_N1_Memory.mem_t;
var sig : Pulsar_N1.signature_t;
enc <- encode_sign_args sk m ctx rho_rnd;
mem_post <- Pulsar_N1_Sign_Refinement.sign_body_fn enc.`1 enc.`2;
sig <- Pulsar_N1_Sign_Refinement.refine_sig_to_n1_sign
(Pulsar_N1_Sign_Layout.read_sig_sign
mem_post
enc.`2.`Pulsar_N1_Sign_Layout.ptr_signature);
return sig;
}
}.
(* ===================================================================
Procedure-level equiv against the abstract FIPS204Sign.
=================================================================== *)
lemma sign_wrapper_equiv_FIPS204Sign :
equiv [ SignExtractedWrapper.sign ~ Pulsar_N1.FIPS204Sign.sign :
={arg}
/\ Pulsar_N1.accept_signing_attempt
sk{1} m{1} ctx{1} rho_rnd{1}
==> ={res} ].
proof.
proc.
inline Pulsar_N1.FIPS204Sign.sign.
wp; skip => />.
move=> &1 Haccept.
exact: (sign_wrapper_bridge sk{1} m{1} ctx{1} rho_rnd{1} Haccept).
qed.
(* ===================================================================
ACCOUNTING
axioms (0 — sign_wrapper_bridge is a lemma):
(none)
ops:
n1_share_to_layout_sign, n1_msg_to_layout_sign
(abstract wire-type projectors)
n1_inputs_to_sign_full (record builder)
encode_sign_args (3-tuple — composes adapter +
Layout encoder)
modules:
SignExtractedWrapper : Pulsar_N1.MLDSA65_Sign
PROVED lemmas:
sign_wrapper_bridge
sign_wrapper_equiv_FIPS204Sign
=================================================================== *)