@adapt-toolkit/mufl 0.10.8 → 0.10.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,6 +6,7 @@ config script {
6
6
  $current_transaction_info->#"current_transaction_info.mm",
7
7
  $identity_proof_document->#"identity_proof_document.mm",
8
8
  $lists->#"lists.mm",
9
+ $limits->#"limits.mm",
9
10
  $vector->#"vector.mm",
10
11
  $platform_type_id->#"platform_type_id.mm",
11
12
  $transaction_message_decoder->#"transaction_message_decoder.mm",
@@ -51,6 +52,7 @@ config script {
51
52
  $current_transaction_info->#"current_transaction_info.mm",
52
53
  $identity_proof_document->#"identity_proof_document.mm",
53
54
  $lists->#"lists.mm",
55
+ $limits->#"limits.mm",
54
56
  $vector->#"vector.mm",
55
57
  $platform_type_id->#"platform_type_id.mm",
56
58
  $transaction_message_decoder->#"transaction_message_decoder.mm",
@@ -201,6 +201,40 @@ library address_document loads libraries address_document_types, key_storage, ke
201
201
  RETURN ($version->1, $identity->my_identity, $authorizations->signatures).
202
202
  }
203
203
 
204
+ // The address document for the TRANSPORT identity-proof (node_description) —
205
+ // the self-attestation attached to EVERY outgoing external transaction. The
206
+ // identity is the full v2 record (the $e2e_bundle stays: receivers read the
207
+ // sender's e2e identity key off it for the inbound E2E decode hook), but
208
+ // $authorizations carries TWO self-signatures per SIGN key: one over
209
+ // _value_id(v2 identity) and one over _value_id(v1 bundle-less identity).
210
+ // A pre-e2e_bundle validator (SDK <= 0.9.x schema, e.g. the deployed
211
+ // ours-mcp 0.10.1) re-hashes the identity WITHOUT $e2e_bundle and finds the
212
+ // v1-hash signature in its any-match loop; a current validator finds the
213
+ // v2-hash signature. NOT memoised and used ONLY by node_description::create,
214
+ // so the main address document (invites, delegation certs, readvertise
215
+ // payloads — and every cert ad-hash binding) stays strict v2-sig-only.
216
+ produce_transport_address_document = fn (_) -> t_address_document
217
+ {
218
+ base_identity = key_storage::get_my_identity().
219
+ my_identity = ( $key_list -> (base_identity $key_list),
220
+ $default_keys -> (base_identity $default_keys),
221
+ $container_id -> (base_identity $container_id),
222
+ $e2e_bundle -> e2e::my_public_bundle() ).
223
+ v1_identity = ( $key_list -> (base_identity $key_list),
224
+ $default_keys -> (base_identity $default_keys),
225
+ $container_id -> (base_identity $container_id) ).
226
+ signatures IS crypto_signature(,) = (,).
227
+ hash_v2 = _value_id my_identity.
228
+ hash_v1 = _value_id v1_identity.
229
+
230
+ sc my_identity $key_list -- (key -> ) ?? key_get_function key == $SIGN {
231
+ signatures (key_storage::sign hash_v2 (_crypto_get_key_id key)) -> TRUE.
232
+ signatures (key_storage::sign hash_v1 (_crypto_get_key_id key)) -> TRUE.
233
+ }
234
+
235
+ RETURN ($version->m_current_version, $identity->my_identity, $authorizations->signatures).
236
+ }
237
+
204
238
  // The address document to hand a peer, down-levelled when the peer is a v1
205
239
  // (pre-E2E) node. peer_is_v1 NIL/FALSE => the current (v2) document (memoised as
206
240
  // usual); TRUE => a freshly built v1 document (not memoised). This is the single
@@ -2,7 +2,9 @@ library node_description loads libraries address_document, container_associated_
2
2
  metadef t_node_description: identity_proof_document_types::t_node_description.
3
3
 
4
4
  create = fn (_) -> t_node_description {
5
- ad = address_document::get_my_address_document().
5
+ // Transport self-attestation: dual-signed (v2-hash + v1-hash) so both
6
+ // current and pre-e2e_bundle-schema peers can verify the self-signature.
7
+ ad = address_document::produce_transport_address_document().
6
8
  associated_data = container_associated_data::create().
7
9
  return ($address_document -> ad, $container_associated_data -> associated_data).
8
10
  }
@@ -0,0 +1,67 @@
1
+ // Governance wrapper for the per-packet limits primitive.
2
+ //
3
+ // The engine exposes a single dangerous primitive, _set_limits, which mutates the packet's
4
+ // committed limits. It is DANGEROUS, so a packet's code must grab() it to use it. Authorization for
5
+ // a limit change -- who may change limits, and under what conditions -- is entirely the packet
6
+ // developer's policy: this library provides only the MECHANISM (the raw application path), and the
7
+ // engine enforces the hard FLOOR (a change can never exceed the global ceilings). The wrapper does
8
+ // NOT impose or imply any particular authorization model (no built-in signature requirement); the
9
+ // developer composes whatever check their policy needs -- signed request, owner identity, multi-sig,
10
+ // ... -- around set_limits before applying a change. It follows the same inject-a-grabbed-primitive
11
+ // pattern as key_storage (the app grabs _set_limits and calls limits::init to bind it here).
12
+ //
13
+ // The engine primitive validates the {name -> count} dictionary shape, the canonical dimension
14
+ // names, and the [1, ceiling] ranges.
15
+ //
16
+ // Named tiers (for reference; resolved by the ENGINE, not this library): a transaction's source-level
17
+ // limits(...) clause also accepts three vetted bundles by name -- $limits::small, $limits::standard,
18
+ // $limits::heavy -- expanded at compile time by the clause. The engine's resolver is authoritative;
19
+ // the bundles are:
20
+ // $limits::small = { fuel_ops -> 10000, call_depth -> 64, constructed_elems -> 4000 }
21
+ // $limits::standard = { fuel_ops -> 100000, call_depth -> 256, constructed_elems -> 40000 }
22
+ // $limits::heavy = { fuel_ops -> 500000, call_depth -> 1024, constructed_elems -> 200000 }
23
+ // They bound the compute dimensions only; structural dimensions stay at the enclosing effective, and
24
+ // explicit entries after a tier override it pairwise. A conformance unit test pins the engine's
25
+ // value table red-on-drift; if a ratified change lands there, update this doc block to match.
26
+ library limits {
27
+
28
+ hidden {
29
+ // Placeholder for the injected primitive. If a packet calls a limits function without first
30
+ // grabbing _set_limits and injecting it via init, this aborts loudly rather than silently
31
+ // doing nothing.
32
+ _set_limits is (any -> nil) = fn (_: any) -> nil {
33
+ abort "limits: _set_limits primitive was not grabbed and injected (call limits::init)." when TRUE.
34
+ return NIL.
35
+ }
36
+ }
37
+
38
+ // Bind the grabbed _set_limits primitive. Called once from the packet's code:
39
+ // set = grab(_set_limits). limits::init ($_set_limits -> set).
40
+ init = fn (_:($_set_limits -> set: (any -> nil))) {
41
+ _set_limits -> set.
42
+ }
43
+
44
+ // Apply a {name -> count} limit change. This library provides the MECHANISM only -- authorization
45
+ // is the packet developer's responsibility: perform whatever check your policy requires (signed
46
+ // request, owner identity, multi-sig, ...) BEFORE calling this. The engine primitive still
47
+ // validates the dictionary shape, the canonical dimension names, and the [1, ceiling] ranges, so
48
+ // a change can never exceed the global ceilings regardless of the caller's policy.
49
+ set_limits = fn (new_limits: any) -> nil {
50
+ _set_limits new_limits.
51
+ }
52
+
53
+ // Packet-creation defaults. The SDK passes packet-creation options inside the init argument; by
54
+ // convention a packet that wants creation-time default limits reads a `limits` block ({name ->
55
+ // count}, the same shape as set_limits) from its init argument and applies it here, e.g. in the
56
+ // packet's init transaction:
57
+ //
58
+ // set = grab(_set_limits).
59
+ // limits::init ($_set_limits -> set).
60
+ // if (init_arg $limits) != NIL {
61
+ // limits::set_limits (init_arg $limits).
62
+ // }
63
+ //
64
+ // This is a REQUEST TO THE PACKET'S CODE, not an engine feature: a packet whose code ignores the
65
+ // block simply keeps the global defaults. The engine still enforces the [1, ceiling] floor on
66
+ // whatever is applied.
67
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adapt-toolkit/mufl",
3
- "version": "0.10.8",
3
+ "version": "0.10.10",
4
4
  "type": "module",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "description": "The MUFL toolchain: prebuilt `mufl` (REPL) and `mufl-compile` (compiler) engine binaries plus the MUFL stdlib, meta, and transactions trees they need at run time. Linux x64 only; the binaries are proprietary (AEFL) — see LICENSE and NOTICE.",
Binary file
Binary file
@@ -5,7 +5,10 @@
5
5
 
6
6
  library __t_wrapper loads libraries transaction, key_storage, transaction_queue, identity_proof_document_types, e2e {
7
7
 
8
- metadef t_trn: ($name->str, $targ->any).
8
+ // $__limits (optional): the per-call resource budget carried inside the signed message (see
9
+ // transaction::unsigned_message). Kept as `any+` here too so a budgeted message decodes; the
10
+ // engine validates and folds it. Absent = no budget.
11
+ metadef t_trn: ($name->str, $targ->any, $__limits->any+).
9
12
  metadef t_trn_extended: ($trn->t_trn, $is_signed->bool, $is_encrypted->bool, $is_e2e->bool+).
10
13
  metadef t_trn_message_info: (
11
14
  $decoded_envelope -> transaction::envelope::external::decoded_type || t_trn,
@@ -13,7 +13,12 @@ library transaction loads libraries key_utils, key_storage, identity_proof_docum
13
13
  // }
14
14
  // }
15
15
 
16
- metadef unsigned_message: ($name -> str, $targ -> any).
16
+ // $__limits (optional) is the per-call resource budget: a {name -> count} dictionary the engine
17
+ // folds into this transaction's effective limits (tighten-only). It rides INSIDE the signed
18
+ // message, so it is authenticated input -- a post-sign edit changes the message value-id and
19
+ // fails signature verification. Absent means no per-call budget (unchanged behaviour). The engine
20
+ // validates the dictionary (canonical dimension names, [1, ceiling]); the field type is `any+`.
21
+ metadef unsigned_message: ($name -> str, $targ -> any, $__limits -> any+).
17
22
  metadef signed_message: ($trn -> unsigned_message, $ptsignature -> crypto_signature).
18
23
  metadef encrypted_pt_signed_message: ($encrypted_message -> crypto_message, $ptsignature -> crypto_signature).
19
24
  metadef encrypted_em_signed_message: ($encrypted_message -> crypto_message, $emsignature -> crypto_signature).
@@ -81,7 +86,7 @@ library transaction loads libraries key_utils, key_storage, identity_proof_docum
81
86
  }
82
87
 
83
88
  hidden {
84
- sign = fn (_:($trn -> tn: ($name -> str, $targ -> any))) -> signed_message {
89
+ sign = fn (_:($trn -> tn: ($name -> str, $targ -> any, $__limits -> any+))) -> signed_message {
85
90
  signature = key_storage::default_sign (_value_id tn |).
86
91
  return ($trn -> tn, $ptsignature -> signature) as signed_message.
87
92
  }
@@ -179,7 +184,7 @@ library transaction loads libraries key_utils, key_storage, identity_proof_docum
179
184
  return ($result_kind -> results::kind::success, $result -> actions).
180
185
  }
181
186
 
182
- encrypt = fn (_:($cid -> cid: t_container_id, $trn -> tn: ($name -> str, $targ -> any), $isemsignature -> isem: bool)
187
+ encrypt = fn (_:($cid -> cid: t_container_id, $trn -> tn: ($name -> str, $targ -> any, $__limits -> any+), $isemsignature -> isem: bool)
183
188
  ) -> encrypted_signed_message
184
189
  {
185
190
  encrypted_data = key_storage::default_encrypt tn cid.