@hazbase/simplicity 0.4.5 → 0.4.7

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.
@@ -0,0 +1,240 @@
1
+ /*
2
+ * Strict v2 verifier covenant.
3
+ *
4
+ * One CMR exposes three explicit paths:
5
+ * - ordinary transfer: every strict output is a canonical whitelisted CU(X)
6
+ * - redemption: every strict output is returned to the configured vault
7
+ * - governance: the authority rotates the verifier to a reviewed successor
8
+ *
9
+ * Pilot limits are consensus-visible: at most 16 inputs, at most 8 outputs,
10
+ * and an 8-level owner whitelist proof. Transactions outside these bounds
11
+ * fail closed and require a later reviewed profile.
12
+ */
13
+ fn not(bit: bool) -> bool {
14
+ <u1>::into(jet::complement_1(<bool>::into(bit)))
15
+ }
16
+
17
+ fn explicit_input_asset_amount(index: u32) -> (u256, u64) {
18
+ let pair: (Asset1, Amount1) = unwrap(jet::input_amount(index));
19
+ let (asset, amount): (Asset1, Amount1) = pair;
20
+ let asset_bits: u256 = unwrap_right::<(u1, u256)>(asset);
21
+ let amount_bits: u64 = unwrap_right::<(u1, u256)>(amount);
22
+ (asset_bits, amount_bits)
23
+ }
24
+
25
+ fn explicit_output_asset_amount(index: u32) -> (u256, u64) {
26
+ let pair: (Asset1, Amount1) = unwrap(jet::output_amount(index));
27
+ let (asset, amount): (Asset1, Amount1) = pair;
28
+ let asset_bits: u256 = unwrap_right::<(u1, u256)>(asset);
29
+ let amount_bits: u64 = unwrap_right::<(u1, u256)>(amount);
30
+ (asset_bits, amount_bits)
31
+ }
32
+
33
+ fn whitelist_owner_leaf(owner: Pubkey) -> u256 {
34
+ let tag_hash: u256 = 0x{{WHITELIST_OWNER_TAG_HASH}};
35
+ let ctx: Ctx8 = jet::sha_256_ctx_8_init();
36
+ let ctx: Ctx8 = jet::sha_256_ctx_8_add_32(ctx, tag_hash);
37
+ let ctx: Ctx8 = jet::sha_256_ctx_8_add_32(ctx, tag_hash);
38
+ let ctx: Ctx8 = jet::sha_256_ctx_8_add_32(ctx, owner);
39
+ jet::sha_256_ctx_8_finalize(ctx)
40
+ }
41
+
42
+ fn whitelist_step(step: (bool, u256), node: u256) -> u256 {
43
+ let (sibling_on_left, sibling): (bool, u256) = step;
44
+ let tag_hash: u256 = 0x{{WHITELIST_NODE_TAG_HASH}};
45
+ let ctx: Ctx8 = jet::sha_256_ctx_8_init();
46
+ let ctx: Ctx8 = jet::sha_256_ctx_8_add_32(ctx, tag_hash);
47
+ let ctx: Ctx8 = jet::sha_256_ctx_8_add_32(ctx, tag_hash);
48
+ let ctx: Ctx8 = match sibling_on_left {
49
+ true => jet::sha_256_ctx_8_add_32(ctx, sibling),
50
+ false => jet::sha_256_ctx_8_add_32(ctx, node),
51
+ };
52
+ let ctx: Ctx8 = match sibling_on_left {
53
+ true => jet::sha_256_ctx_8_add_32(ctx, node),
54
+ false => jet::sha_256_ctx_8_add_32(ctx, sibling),
55
+ };
56
+ jet::sha_256_ctx_8_finalize(ctx)
57
+ }
58
+
59
+ fn require_whitelisted(owner: Pubkey, proof: [(bool, u256); {{WHITELIST_DEPTH}}]) {
60
+ let leaf: u256 = whitelist_owner_leaf(owner);
61
+ let root: u256 = array_fold::<whitelist_step, {{WHITELIST_DEPTH}}>(proof, leaf);
62
+ let expected_root: u256 = 0x{{WHITELIST_ROOT}};
63
+ assert!(jet::eq_256(root, expected_root));
64
+ }
65
+
66
+ fn canonical_holder_script_hash(owner: Pubkey) -> u256 {
67
+ let holder_cmr: u256 = 0x{{HOLDER_PROGRAM_CMR}};
68
+ let holder_leaf: u256 = jet::build_tapleaf_simplicity(holder_cmr);
69
+ let tapdata_ctx: Ctx8 = jet::tapdata_init();
70
+ let tapdata_ctx: Ctx8 = jet::sha_256_ctx_8_add_32(tapdata_ctx, owner);
71
+ let owner_tapdata: u256 = jet::sha_256_ctx_8_finalize(tapdata_ctx);
72
+ let holder_root: u256 = jet::build_tapbranch(holder_leaf, owner_tapdata);
73
+ let holder_internal_key: Pubkey = 0x{{HOLDER_NUMS_INTERNAL_KEY}};
74
+ let output_key: u256 = jet::build_taptweak(holder_internal_key, holder_root);
75
+
76
+ let script_ctx: Ctx8 = jet::sha_256_ctx_8_init();
77
+ let script_ctx: Ctx8 = jet::sha_256_ctx_8_add_1(script_ctx, 0x51);
78
+ let script_ctx: Ctx8 = jet::sha_256_ctx_8_add_1(script_ctx, 0x20);
79
+ let script_ctx: Ctx8 = jet::sha_256_ctx_8_add_32(script_ctx, output_key);
80
+ jet::sha_256_ctx_8_finalize(script_ctx)
81
+ }
82
+
83
+ fn next_index(index: u32) -> u32 {
84
+ let (carry, next): (bool, u32) = jet::add_32(index, 1);
85
+ assert!(not(carry));
86
+ next
87
+ }
88
+
89
+ fn scan_input(unused: (), state: (u32, bool)) -> (u32, bool) {
90
+ let (index, found_strict): (u32, bool) = state;
91
+ let past_end: bool = jet::le_32(jet::num_inputs(), index);
92
+ let found_strict: bool = match past_end {
93
+ true => found_strict,
94
+ false => {
95
+ let (asset, amount): (u256, u64) = explicit_input_asset_amount(index);
96
+ let strict_asset: u256 = 0x{{STRICT_ASSET_ID_JET_HEX}};
97
+ let is_positive: bool = not(jet::eq_64(amount, 0));
98
+ let is_strict: bool = jet::eq_256(asset, strict_asset);
99
+ match is_strict {
100
+ true => is_positive,
101
+ false => found_strict,
102
+ }
103
+ },
104
+ };
105
+ (next_index(index), found_strict)
106
+ }
107
+
108
+ fn scan_output_ordinary(
109
+ owner_proof: (Pubkey, [(bool, u256); {{WHITELIST_DEPTH}}]),
110
+ state: (u32, bool)
111
+ ) -> (u32, bool) {
112
+ let (index, found_strict): (u32, bool) = state;
113
+ let past_end: bool = jet::le_32(jet::num_outputs(), index);
114
+ let found_strict: bool = match past_end {
115
+ true => found_strict,
116
+ false => {
117
+ let pair: (Asset1, Amount1) = unwrap(jet::output_amount(index));
118
+ let (asset, amount): (Asset1, Amount1) = pair;
119
+ let asset: u256 = unwrap_right::<(u1, u256)>(asset);
120
+ let unused_amount: u64 = unwrap_right::<(u1, u256)>(amount);
121
+ let strict_asset: u256 = 0x{{STRICT_ASSET_ID_JET_HEX}};
122
+ match jet::eq_256(asset, strict_asset) {
123
+ true => {
124
+ let (owner, proof): (Pubkey, [(bool, u256); {{WHITELIST_DEPTH}}]) = owner_proof;
125
+ require_whitelisted(owner, proof);
126
+ let actual_script_hash: u256 = unwrap(jet::output_script_hash(index));
127
+ let expected_script_hash: u256 = canonical_holder_script_hash(owner);
128
+ assert!(jet::eq_256(actual_script_hash, expected_script_hash));
129
+ true
130
+ },
131
+ false => found_strict,
132
+ }
133
+ },
134
+ };
135
+ (next_index(index), found_strict)
136
+ }
137
+
138
+ fn require_verifier_successor(expected_script_hash: u256) {
139
+ let (verifier_asset, verifier_amount): (u256, u64) = explicit_input_asset_amount(0);
140
+ let expected_verifier_asset: u256 = 0x{{VERIFIER_ASSET_ID_JET_HEX}};
141
+ assert!(jet::eq_256(verifier_asset, expected_verifier_asset));
142
+ assert!(jet::eq_64(verifier_amount, {{VERIFIER_AMOUNT_ATOMIC}}));
143
+
144
+ let (successor_asset, successor_amount): (u256, u64) = explicit_output_asset_amount(0);
145
+ assert!(jet::eq_256(successor_asset, expected_verifier_asset));
146
+ assert!(jet::eq_64(successor_amount, {{VERIFIER_AMOUNT_ATOMIC}}));
147
+ let successor_script_hash: u256 = unwrap(jet::output_script_hash(0));
148
+ assert!(jet::eq_256(successor_script_hash, expected_script_hash))
149
+ }
150
+
151
+ fn scan_output_redemption(unused: (), state: (u32, bool)) -> (u32, bool) {
152
+ let (index, found_strict): (u32, bool) = state;
153
+ let past_end: bool = jet::le_32(jet::num_outputs(), index);
154
+ let found_strict: bool = match past_end {
155
+ true => found_strict,
156
+ false => {
157
+ let (asset, unused_amount): (u256, u64) = explicit_output_asset_amount(index);
158
+ let strict_asset: u256 = 0x{{STRICT_ASSET_ID_JET_HEX}};
159
+ match jet::eq_256(asset, strict_asset) {
160
+ true => {
161
+ let actual_script_hash: u256 = unwrap(jet::output_script_hash(index));
162
+ let redemption_script_hash: u256 = 0x{{REDEMPTION_SCRIPT_HASH}};
163
+ assert!(jet::eq_256(actual_script_hash, redemption_script_hash));
164
+ true
165
+ },
166
+ false => found_strict,
167
+ }
168
+ },
169
+ };
170
+ (next_index(index), found_strict)
171
+ }
172
+
173
+ fn strict_input_present() -> bool {
174
+ let input_slots: [(); {{MAX_INPUTS}}] = [{{INPUT_UNIT_SLOTS}}];
175
+ let input_state: (u32, bool) =
176
+ array_fold::<scan_input, {{MAX_INPUTS}}>(input_slots, (0, false));
177
+ let (unused_input_index, found_strict_input): (u32, bool) = input_state;
178
+ found_strict_input
179
+ }
180
+
181
+ fn ordinary_transfer(
182
+ output_owner_proofs: [(Pubkey, [(bool, u256); {{WHITELIST_DEPTH}}]); {{MAX_OUTPUTS}}]
183
+ ) {
184
+ require_verifier_successor(jet::current_script_hash());
185
+ assert!(strict_input_present());
186
+
187
+ let output_state: (u32, bool) =
188
+ array_fold::<scan_output_ordinary, {{MAX_OUTPUTS}}>(output_owner_proofs, (0, false));
189
+ let (unused_output_index, found_strict_output): (u32, bool) = output_state;
190
+ assert!(found_strict_output)
191
+ }
192
+
193
+ fn redemption(authority_signature: Signature) {
194
+ require_verifier_successor(jet::current_script_hash());
195
+ assert!(strict_input_present());
196
+
197
+ let output_slots: [(); {{MAX_OUTPUTS}}] = [{{OUTPUT_UNIT_SLOTS}}];
198
+ let output_state: (u32, bool) =
199
+ array_fold::<scan_output_redemption, {{MAX_OUTPUTS}}>(output_slots, (0, false));
200
+ let (unused_output_index, found_strict_output): (u32, bool) = output_state;
201
+ assert!(found_strict_output);
202
+
203
+ let authority: Pubkey = 0x{{AUTHORITY_XONLY}};
204
+ jet::bip_0340_verify((authority, jet::sig_all_hash()), authority_signature)
205
+ }
206
+
207
+ fn governance(next: (u256, Signature)) {
208
+ let (next_verifier_script_hash, authority_signature): (u256, Signature) = next;
209
+ require_verifier_successor(next_verifier_script_hash);
210
+ assert!(not(strict_input_present()));
211
+
212
+ let output_slots: [(); {{MAX_OUTPUTS}}] = [{{OUTPUT_UNIT_SLOTS}}];
213
+ let output_state: (u32, bool) =
214
+ array_fold::<scan_output_redemption, {{MAX_OUTPUTS}}>(output_slots, (0, false));
215
+ let (unused_output_index, found_strict_output): (u32, bool) = output_state;
216
+ assert!(not(found_strict_output));
217
+
218
+ let authority: Pubkey = 0x{{AUTHORITY_XONLY}};
219
+ jet::bip_0340_verify((authority, jet::sig_all_hash()), authority_signature)
220
+ }
221
+
222
+ fn main() {
223
+ assert!(jet::eq_32(jet::current_index(), 0));
224
+ assert!(jet::le_32(jet::num_inputs(), {{MAX_INPUTS}}));
225
+ assert!(jet::le_32(jet::num_outputs(), {{MAX_OUTPUTS}}));
226
+
227
+ let action:
228
+ Either<
229
+ [(Pubkey, [(bool, u256); {{WHITELIST_DEPTH}}]); {{MAX_OUTPUTS}}],
230
+ Either<Signature, (u256, Signature)>
231
+ > = witness::ACTION;
232
+ match action {
233
+ Left(output_owner_proofs : [(Pubkey, [(bool, u256); {{WHITELIST_DEPTH}}]); {{MAX_OUTPUTS}}]) =>
234
+ ordinary_transfer(output_owner_proofs),
235
+ Right(protected_action : Either<Signature, (u256, Signature)>) => match protected_action {
236
+ Left(authority_signature : Signature) => redemption(authority_signature),
237
+ Right(next : (u256, Signature)) => governance(next),
238
+ },
239
+ }
240
+ }
@@ -0,0 +1,94 @@
1
+ import type { SimplicityArtifact, SimplicityClientConfig } from "../core/types";
2
+ export declare const STRICT_POLICY_SNAPSHOT_SCHEMA: "hazbase_strict_policy_snapshot_v1";
3
+ export declare const STRICT_POLICY_SNAPSHOT_APPROVAL_SCHEMA: "hazbase_strict_policy_snapshot_approval_v1";
4
+ export declare const STRICT_POLICY_SNAPSHOT_APPROVAL_DOMAIN: "HAZBASE-RWA-POLICY-SNAPSHOT-V1";
5
+ export declare const STRICT_POLICY_AUTHORITY_SET_DOMAIN: "HAZBASE-RWA-POLICY-AUTHORITY-SET-V1";
6
+ export declare const STRICT_POLICY_VERIFIER_MAX_INPUTS: 16;
7
+ export declare const STRICT_POLICY_VERIFIER_MAX_OUTPUTS: 8;
8
+ export type StrictPolicyNetwork = "liquid-regtest" | "liquid-testnet" | "liquid-mainnet";
9
+ export interface StrictPolicyVerifierReference {
10
+ outpoint: {
11
+ txid: string;
12
+ vout: number;
13
+ };
14
+ assetId: string;
15
+ amountAtomic: string;
16
+ cmr: string;
17
+ scriptHash: string;
18
+ }
19
+ export interface StrictPolicySnapshotPayload {
20
+ schema: typeof STRICT_POLICY_SNAPSHOT_SCHEMA;
21
+ network: StrictPolicyNetwork;
22
+ liquidGenesisHash: string;
23
+ assetBindingId: string;
24
+ liquidAssetId: string;
25
+ epoch: string;
26
+ previousSnapshotHash: string | null;
27
+ policyRoot: string;
28
+ whitelistRoot: string;
29
+ verifier: StrictPolicyVerifierReference;
30
+ effectiveAt: string;
31
+ validUntil: string | null;
32
+ }
33
+ export interface StrictPolicySnapshotAuthority {
34
+ authorityType: "issuer_single";
35
+ authorityId: string;
36
+ authorityVersion: string;
37
+ authoritySetHash: string;
38
+ approvalScheme: "bip340-sha256";
39
+ approvalThreshold: 1;
40
+ signerXonly: string;
41
+ approvedAt: string;
42
+ }
43
+ export interface StrictPolicySnapshotApprovalProof {
44
+ type: "issuer_single_v1";
45
+ signerXonly: string;
46
+ signatureHex: string;
47
+ }
48
+ export interface PreparedStrictPolicySnapshot {
49
+ payload: StrictPolicySnapshotPayload;
50
+ authority: StrictPolicySnapshotAuthority;
51
+ canonicalPayload: string;
52
+ snapshotHash: string;
53
+ canonicalApprovalMessage: string;
54
+ approvalMessageHash: string;
55
+ }
56
+ export interface StrictPolicySnapshotEnvelope extends PreparedStrictPolicySnapshot {
57
+ approvalProof: StrictPolicySnapshotApprovalProof;
58
+ approvalProofHash: string;
59
+ }
60
+ export interface StrictPolicyHolderCovenantParams {
61
+ strictAssetIdJetHex: string;
62
+ verifierAssetIdJetHex: string;
63
+ verifierAmountAtomic: string;
64
+ numsInternalKey: string;
65
+ }
66
+ export interface StrictPolicyVerifierCovenantParams {
67
+ strictAssetIdJetHex: string;
68
+ verifierAssetIdJetHex: string;
69
+ verifierAmountAtomic: string;
70
+ holderProgramCmr: string;
71
+ holderNumsInternalKey: string;
72
+ whitelistRoot: string;
73
+ redemptionScriptHash: string;
74
+ authorityXonly: string;
75
+ }
76
+ export declare function normalizeStrictPolicySnapshotPayload(value: unknown): StrictPolicySnapshotPayload;
77
+ export declare function normalizeStrictPolicySnapshotAuthority(value: unknown): StrictPolicySnapshotAuthority;
78
+ export declare function normalizeStrictPolicySnapshotApprovalProof(value: unknown): StrictPolicySnapshotApprovalProof;
79
+ export declare function normalizeStrictPolicyHolderCovenantParams(value: StrictPolicyHolderCovenantParams | unknown): StrictPolicyHolderCovenantParams;
80
+ export declare function normalizeStrictPolicyVerifierCovenantParams(value: StrictPolicyVerifierCovenantParams | unknown): StrictPolicyVerifierCovenantParams;
81
+ export declare function strictPolicyHolderCovenantTemplatePath(): string;
82
+ export declare function renderStrictPolicyHolderCovenantSource(value: StrictPolicyHolderCovenantParams | unknown): Promise<string>;
83
+ export declare function compileStrictPolicyHolderCovenant(config: SimplicityClientConfig, value: StrictPolicyHolderCovenantParams | unknown): Promise<SimplicityArtifact>;
84
+ export declare function strictPolicyVerifierCovenantTemplatePath(): string;
85
+ export declare function renderStrictPolicyVerifierCovenantSource(value: StrictPolicyVerifierCovenantParams | unknown): Promise<string>;
86
+ export declare function compileStrictPolicyVerifierCovenant(config: SimplicityClientConfig, value: StrictPolicyVerifierCovenantParams | unknown): Promise<SimplicityArtifact>;
87
+ export declare function taggedHashHexUtf8(tag: string, canonicalPayload: string): string;
88
+ export declare function computeStrictPolicyAuthoritySetHash(signerXonlyValue: string): string;
89
+ export declare function prepareStrictPolicySnapshot(input: {
90
+ payload: StrictPolicySnapshotPayload | unknown;
91
+ authority: StrictPolicySnapshotAuthority | unknown;
92
+ }): PreparedStrictPolicySnapshot;
93
+ export declare function finalizeStrictPolicySnapshot(prepared: PreparedStrictPolicySnapshot, proofValue: StrictPolicySnapshotApprovalProof | unknown): StrictPolicySnapshotEnvelope;
94
+ export declare function verifyStrictPolicySnapshot(envelopeValue: StrictPolicySnapshotEnvelope): Promise<PreparedStrictPolicySnapshot>;