chipi-stack 2.2.0__tar.gz → 2.3.0__tar.gz
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.
- {chipi_stack-2.2.0/chipi_stack.egg-info → chipi_stack-2.3.0}/PKG-INFO +1 -1
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/__init__.py +1 -1
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/models/wallet.py +34 -21
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/__init__.py +93 -77
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/signers/__init__.py +28 -4
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/signers/ed25519.py +81 -17
- chipi_stack-2.3.0/chipi_sdk/shhh/signers/webauthn.py +241 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/wallets.py +138 -77
- {chipi_stack-2.2.0 → chipi_stack-2.3.0/chipi_stack.egg-info}/PKG-INFO +1 -1
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_stack.egg-info/SOURCES.txt +1 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/pyproject.toml +1 -1
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/LICENSE +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/MANIFEST.in +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/README.md +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/client.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/constants.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/encryption.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/errors.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/execute_paymaster.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/formatters.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/models/__init__.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/models/core.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/models/session.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/models/sku.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/models/sku_purchase.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/models/sku_transaction.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/models/transaction.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/models/user.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/models/x402.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/py.typed +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/sdk.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/sessions.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/compute_wallet_address.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/execute_paymaster_raw.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/migrate.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/oe.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/recovery.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/signers/eip191.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/signers/jwt_apple_sub.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/signers/stark.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/snip12_hash.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/shhh/threshold.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/sku_purchases.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/sku_transactions.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/skus.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/transactions.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/users.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/validators.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/x402_client.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/x402_facilitator.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_sdk/x402_middleware.py +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_stack.egg-info/dependency_links.txt +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_stack.egg-info/requires.txt +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/chipi_stack.egg-info/top_level.txt +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/setup.cfg +0 -0
- {chipi_stack-2.2.0 → chipi_stack-2.3.0}/setup.py +0 -0
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
from enum import Enum
|
|
5
5
|
from typing import Optional
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
7
8
|
|
|
8
9
|
from .core import Chain, ChainToken
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def to_camel(string: str) -> str:
|
|
12
13
|
"""Convert snake_case to camelCase."""
|
|
13
|
-
components = string.split(
|
|
14
|
-
return components[0] +
|
|
14
|
+
components = string.split("_")
|
|
15
|
+
return components[0] + "".join(x.title() for x in components[1:])
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class WalletType(str, Enum):
|
|
@@ -26,6 +27,7 @@ class WalletType(str, Enum):
|
|
|
26
27
|
JWT_ES256_APPLE_SUB, BLS12_381). Requires CHIPI_SHHH_ENABLED on
|
|
27
28
|
the backend.
|
|
28
29
|
"""
|
|
30
|
+
|
|
29
31
|
CHIPI = "CHIPI"
|
|
30
32
|
READY = "READY"
|
|
31
33
|
SHHH = "SHHH"
|
|
@@ -42,6 +44,7 @@ class ShhhSignerKind(str, Enum):
|
|
|
42
44
|
browser/RN context. Wallet creation with wallet_type=SHHH and no
|
|
43
45
|
signer_kind raises in Python (per plan D10).
|
|
44
46
|
"""
|
|
47
|
+
|
|
45
48
|
STARK = "STARK"
|
|
46
49
|
ED25519 = "ED25519"
|
|
47
50
|
SECP256K1 = "SECP256K1"
|
|
@@ -56,9 +59,9 @@ class ShhhSignerKind(str, Enum):
|
|
|
56
59
|
|
|
57
60
|
class WalletData(BaseModel):
|
|
58
61
|
"""Core wallet data structure."""
|
|
59
|
-
|
|
62
|
+
|
|
60
63
|
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
|
61
|
-
|
|
64
|
+
|
|
62
65
|
public_key: str = Field(..., description="Wallet public address")
|
|
63
66
|
encrypted_private_key: str = Field(..., description="AES encrypted private key")
|
|
64
67
|
wallet_type: Optional[WalletType] = Field(None, description="Type of wallet")
|
|
@@ -67,7 +70,7 @@ class WalletData(BaseModel):
|
|
|
67
70
|
|
|
68
71
|
class DeploymentData(BaseModel):
|
|
69
72
|
"""Contract deployment data."""
|
|
70
|
-
|
|
73
|
+
|
|
71
74
|
class_hash: str
|
|
72
75
|
salt: str
|
|
73
76
|
unique: str
|
|
@@ -96,14 +99,22 @@ class CreateWalletParams(BaseModel):
|
|
|
96
99
|
"Required when wallet_type=SHHH is set EXPLICITLY. When SHHH "
|
|
97
100
|
"is reached via the default-flip (caller omitted wallet_type), "
|
|
98
101
|
"the SDK falls back to STARK to match the TS SDK and the live "
|
|
99
|
-
"on-chain smokes.
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
"on-chain smokes. Supported deploy kinds: STARK + ED25519 "
|
|
103
|
+
"(Chipi-held key), WEBAUTHN_P256 + EIP191_SECP256K1 "
|
|
104
|
+
"(external-rooted — supply owner_pubkey_felts). "
|
|
105
|
+
"JWT_ES256_APPLE_SUB and the remaining kinds raise "
|
|
106
|
+
"NotImplementedError at create time."
|
|
107
|
+
),
|
|
108
|
+
)
|
|
109
|
+
owner_pubkey_felts: Optional[list[str]] = Field(
|
|
110
|
+
None,
|
|
111
|
+
description=(
|
|
112
|
+
"External-rooted SHHH only. The owner's public key as Cairo "
|
|
113
|
+
"felts (hex strings) when Chipi does NOT hold the signing key: "
|
|
114
|
+
"WEBAUTHN_P256 / EIP191_SECP256K1 → [x_low, x_high, y_low, "
|
|
115
|
+
"y_high] (4 felts); external ED25519 (Phantom) → [low, high] "
|
|
116
|
+
"(2 felts). Omit for STARK and Chipi-held ED25519 (the SDK "
|
|
117
|
+
"generates the key)."
|
|
107
118
|
),
|
|
108
119
|
)
|
|
109
120
|
|
|
@@ -140,7 +151,7 @@ CreateWalletResponse = GetWalletResponse
|
|
|
140
151
|
|
|
141
152
|
class GetWalletParams(BaseModel):
|
|
142
153
|
"""Parameters for retrieving a wallet."""
|
|
143
|
-
|
|
154
|
+
|
|
144
155
|
external_user_id: str = Field(..., description="External user identifier")
|
|
145
156
|
|
|
146
157
|
|
|
@@ -157,9 +168,9 @@ class GetTokenBalanceParams(BaseModel):
|
|
|
157
168
|
|
|
158
169
|
class GetTokenBalanceResponse(BaseModel):
|
|
159
170
|
"""Response from token balance query."""
|
|
160
|
-
|
|
171
|
+
|
|
161
172
|
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
|
162
|
-
|
|
173
|
+
|
|
163
174
|
chain: Chain
|
|
164
175
|
chain_token: ChainToken
|
|
165
176
|
chain_token_address: str
|
|
@@ -169,16 +180,16 @@ class GetTokenBalanceResponse(BaseModel):
|
|
|
169
180
|
|
|
170
181
|
class PrepareWalletCreationResponse(BaseModel):
|
|
171
182
|
"""Response from wallet creation preparation."""
|
|
172
|
-
|
|
183
|
+
|
|
173
184
|
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
|
174
|
-
|
|
185
|
+
|
|
175
186
|
typed_data: dict
|
|
176
187
|
account_class_hash: str
|
|
177
188
|
|
|
178
189
|
|
|
179
190
|
class CreateCustodialWalletParams(BaseModel):
|
|
180
191
|
"""Parameters for creating a custodial wallet."""
|
|
181
|
-
|
|
192
|
+
|
|
182
193
|
chain: Chain
|
|
183
194
|
org_id: str
|
|
184
195
|
|
|
@@ -198,7 +209,9 @@ class PrepareWalletUpgradeParams(BaseModel):
|
|
|
198
209
|
"""Parameters for preparing a wallet upgrade."""
|
|
199
210
|
|
|
200
211
|
wallet_address: str = Field(..., description="Wallet address to upgrade")
|
|
201
|
-
target_class_hash: Optional[str] = Field(
|
|
212
|
+
target_class_hash: Optional[str] = Field(
|
|
213
|
+
None, description="Target class hash (defaults to latest CHIPI)"
|
|
214
|
+
)
|
|
202
215
|
|
|
203
216
|
|
|
204
217
|
class PrepareWalletUpgradeResponse(BaseModel):
|
|
@@ -1,50 +1,37 @@
|
|
|
1
1
|
"""SHHH V8.4 ShhhAccount integration surface for `chipi-stack` (Python).
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
WebAuthn
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
`
|
|
3
|
+
Server-side kinds: STARK, ED25519, EIP191_SECP256K1, WEBAUTHN_P256.
|
|
4
|
+
WebAuthn support is **from-assertion only**: Python can't run
|
|
5
|
+
`navigator.credentials` to *create* a passkey assertion (use
|
|
6
|
+
`@chipi-stack/chipi-react` / `chipi-expo` for that), but it CAN build the
|
|
7
|
+
V2_SNIP12 envelope from an assertion (`authenticatorData` +
|
|
8
|
+
`clientDataJSON` + DER signature) that a browser produced and POSTed to
|
|
9
|
+
your server — the same pattern as `build_eip191_envelope_from_signature`
|
|
10
|
+
for MetaMask. The from-private-key WebAuthn helper is browser/test-only
|
|
11
|
+
and is not ported.
|
|
9
12
|
|
|
10
13
|
This module mirrors `@chipi-stack/backend/src/shhh` byte-for-byte where
|
|
11
14
|
possible. Parity is validated against `tests/fixtures/cycle1.json` (the
|
|
12
15
|
same JSON we PR'd to shhh-wallet-cairo as drift-detection fixtures).
|
|
13
16
|
"""
|
|
14
17
|
|
|
15
|
-
from .snip12_hash import (
|
|
16
|
-
CALL_TYPE_HASH_REV1,
|
|
17
|
-
ISIGNER_CANONICAL_LABEL,
|
|
18
|
-
ISIGNER_ID,
|
|
19
|
-
ISRC9_V2_ID,
|
|
20
|
-
OE_DOMAIN_NAME,
|
|
21
|
-
OE_DOMAIN_REVISION,
|
|
22
|
-
OE_DOMAIN_VERSION,
|
|
23
|
-
OUTSIDE_EXECUTION_TYPE_HASH_REV1,
|
|
24
|
-
SIG_VERSION_V1_HEX_ASCII,
|
|
25
|
-
SIG_VERSION_V2_SNIP12,
|
|
26
|
-
SIG_VERSION_V2_THRESHOLD,
|
|
27
|
-
STARKNET_DOMAIN_TYPE_HASH_REV1,
|
|
28
|
-
STARKNET_MESSAGE_PREFIX,
|
|
29
|
-
Call,
|
|
30
|
-
OutsideExecution,
|
|
31
|
-
compute_isigner_id,
|
|
32
|
-
compute_snip12_hash,
|
|
33
|
-
hash_call,
|
|
34
|
-
hash_calls,
|
|
35
|
-
hash_outside_execution_struct,
|
|
36
|
-
hash_starknet_domain,
|
|
37
|
-
snip12_hash_to_hex_ascii_bytes,
|
|
38
|
-
starknet_keccak,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
18
|
from .compute_wallet_address import (
|
|
42
19
|
ComputeAddressInput,
|
|
43
20
|
compute_address_salt,
|
|
44
21
|
compute_shhh_address,
|
|
45
22
|
owner_commitment,
|
|
46
23
|
)
|
|
47
|
-
|
|
24
|
+
from .migrate import (
|
|
25
|
+
BOOTSTRAP_DOMAIN_SEPARATOR,
|
|
26
|
+
BootstrapMessageParams,
|
|
27
|
+
BuildBootstrapSignedCallParams,
|
|
28
|
+
BuildMigrationCallsParams,
|
|
29
|
+
build_bootstrap_signed_call,
|
|
30
|
+
build_migration_calls,
|
|
31
|
+
compute_bootstrap_message,
|
|
32
|
+
label_to_felt,
|
|
33
|
+
sign_bootstrap_message,
|
|
34
|
+
)
|
|
48
35
|
from .oe import (
|
|
49
36
|
ANY_CALLER_FELT,
|
|
50
37
|
MAX_OE_VALIDITY_WINDOW_SECONDS,
|
|
@@ -54,23 +41,55 @@ from .oe import (
|
|
|
54
41
|
wrap_v2_snip12_envelope,
|
|
55
42
|
wrap_v2_threshold_envelope,
|
|
56
43
|
)
|
|
57
|
-
|
|
44
|
+
from .recovery import (
|
|
45
|
+
DEFAULT_OP_EXPIRY_SECONDS,
|
|
46
|
+
OP_ADD_OWNER,
|
|
47
|
+
OP_REMOVE_OWNER,
|
|
48
|
+
OP_ROTATE_OWNER,
|
|
49
|
+
OP_SET_THRESHOLD,
|
|
50
|
+
ROLE_GUARDIAN,
|
|
51
|
+
ROLE_OWNER,
|
|
52
|
+
TIMELOCK_SECONDS,
|
|
53
|
+
VIEW_SELECTORS,
|
|
54
|
+
NewOwnerInput,
|
|
55
|
+
OwnerRole,
|
|
56
|
+
build_cancel_pending_op_call,
|
|
57
|
+
build_cancel_recovery_call,
|
|
58
|
+
build_execute_add_owner_call,
|
|
59
|
+
build_execute_remove_owner_call,
|
|
60
|
+
build_execute_rotate_owner_call,
|
|
61
|
+
build_execute_set_threshold_call,
|
|
62
|
+
build_finalize_recovery_call,
|
|
63
|
+
build_initiate_recovery_call,
|
|
64
|
+
build_propose_add_owner_call,
|
|
65
|
+
build_propose_remove_owner_call,
|
|
66
|
+
build_propose_rotate_owner_call,
|
|
67
|
+
build_propose_set_threshold_call,
|
|
68
|
+
is_ready_to_execute,
|
|
69
|
+
seconds_until_executable,
|
|
70
|
+
)
|
|
58
71
|
from .signers import (
|
|
59
72
|
APPLE_ISSUER,
|
|
60
|
-
AppleTokenResponse,
|
|
61
73
|
ED25519_KIND_TAG,
|
|
62
74
|
EIP191_KIND_TAG,
|
|
63
75
|
JWT_APPLE_SUB_KIND_TAG,
|
|
64
76
|
JWT_APPLE_SUB_KIND_TAG_FELT,
|
|
65
|
-
JwtAppleSubPubkey,
|
|
66
77
|
STARK_KIND_TAG,
|
|
78
|
+
WEBAUTHN_KIND_TAG,
|
|
79
|
+
AppleTokenResponse,
|
|
67
80
|
Eip191Pubkey,
|
|
81
|
+
JwtAppleSubPubkey,
|
|
82
|
+
WebAuthnPubkey,
|
|
83
|
+
base64url_encode,
|
|
68
84
|
build_ed25519_envelope,
|
|
85
|
+
build_ed25519_envelope_from_signature,
|
|
69
86
|
build_eip191_envelope_from_private_key,
|
|
70
87
|
build_eip191_envelope_from_signature,
|
|
71
88
|
build_jwt_apple_sub_envelope_from_test_key,
|
|
72
89
|
build_jwt_apple_sub_envelope_from_token_response,
|
|
73
90
|
build_stark_envelope,
|
|
91
|
+
build_webauthn_envelope_from_assertion,
|
|
92
|
+
byte_array_to_felts,
|
|
74
93
|
ed25519_owner_id,
|
|
75
94
|
ed25519_pubkey_felts,
|
|
76
95
|
ed25519_signed_bytes,
|
|
@@ -82,11 +101,38 @@ from .signers import (
|
|
|
82
101
|
locate_sub_claim,
|
|
83
102
|
message_hash_to_nonce_b64url,
|
|
84
103
|
parse_apple_id_token,
|
|
104
|
+
parse_der_ecdsa_signature,
|
|
85
105
|
parse_eip191_signature,
|
|
86
106
|
stark_owner_id,
|
|
87
107
|
stark_pubkey_felts,
|
|
108
|
+
webauthn_owner_id,
|
|
109
|
+
webauthn_pubkey_felts,
|
|
110
|
+
)
|
|
111
|
+
from .snip12_hash import (
|
|
112
|
+
CALL_TYPE_HASH_REV1,
|
|
113
|
+
ISIGNER_CANONICAL_LABEL,
|
|
114
|
+
ISIGNER_ID,
|
|
115
|
+
ISRC9_V2_ID,
|
|
116
|
+
OE_DOMAIN_NAME,
|
|
117
|
+
OE_DOMAIN_REVISION,
|
|
118
|
+
OE_DOMAIN_VERSION,
|
|
119
|
+
OUTSIDE_EXECUTION_TYPE_HASH_REV1,
|
|
120
|
+
SIG_VERSION_V1_HEX_ASCII,
|
|
121
|
+
SIG_VERSION_V2_SNIP12,
|
|
122
|
+
SIG_VERSION_V2_THRESHOLD,
|
|
123
|
+
STARKNET_DOMAIN_TYPE_HASH_REV1,
|
|
124
|
+
STARKNET_MESSAGE_PREFIX,
|
|
125
|
+
Call,
|
|
126
|
+
OutsideExecution,
|
|
127
|
+
compute_isigner_id,
|
|
128
|
+
compute_snip12_hash,
|
|
129
|
+
hash_call,
|
|
130
|
+
hash_calls,
|
|
131
|
+
hash_outside_execution_struct,
|
|
132
|
+
hash_starknet_domain,
|
|
133
|
+
snip12_hash_to_hex_ascii_bytes,
|
|
134
|
+
starknet_keccak,
|
|
88
135
|
)
|
|
89
|
-
|
|
90
136
|
from .threshold import (
|
|
91
137
|
MIN_THRESHOLD_OWNERS,
|
|
92
138
|
assert_valid_v2_snip12_envelope,
|
|
@@ -95,46 +141,6 @@ from .threshold import (
|
|
|
95
141
|
parse_threshold_envelope,
|
|
96
142
|
)
|
|
97
143
|
|
|
98
|
-
from .recovery import (
|
|
99
|
-
DEFAULT_OP_EXPIRY_SECONDS,
|
|
100
|
-
NewOwnerInput,
|
|
101
|
-
OP_ADD_OWNER,
|
|
102
|
-
OP_REMOVE_OWNER,
|
|
103
|
-
OP_ROTATE_OWNER,
|
|
104
|
-
OP_SET_THRESHOLD,
|
|
105
|
-
OwnerRole,
|
|
106
|
-
ROLE_GUARDIAN,
|
|
107
|
-
ROLE_OWNER,
|
|
108
|
-
TIMELOCK_SECONDS,
|
|
109
|
-
VIEW_SELECTORS,
|
|
110
|
-
build_cancel_pending_op_call,
|
|
111
|
-
build_cancel_recovery_call,
|
|
112
|
-
build_execute_add_owner_call,
|
|
113
|
-
build_execute_remove_owner_call,
|
|
114
|
-
build_execute_rotate_owner_call,
|
|
115
|
-
build_execute_set_threshold_call,
|
|
116
|
-
build_finalize_recovery_call,
|
|
117
|
-
build_initiate_recovery_call,
|
|
118
|
-
build_propose_add_owner_call,
|
|
119
|
-
build_propose_remove_owner_call,
|
|
120
|
-
build_propose_rotate_owner_call,
|
|
121
|
-
build_propose_set_threshold_call,
|
|
122
|
-
is_ready_to_execute,
|
|
123
|
-
seconds_until_executable,
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
from .migrate import (
|
|
127
|
-
BOOTSTRAP_DOMAIN_SEPARATOR,
|
|
128
|
-
BootstrapMessageParams,
|
|
129
|
-
BuildBootstrapSignedCallParams,
|
|
130
|
-
BuildMigrationCallsParams,
|
|
131
|
-
build_bootstrap_signed_call,
|
|
132
|
-
build_migration_calls,
|
|
133
|
-
compute_bootstrap_message,
|
|
134
|
-
label_to_felt,
|
|
135
|
-
sign_bootstrap_message,
|
|
136
|
-
)
|
|
137
|
-
|
|
138
144
|
__all__ = [
|
|
139
145
|
# snip12_hash
|
|
140
146
|
"CALL_TYPE_HASH_REV1",
|
|
@@ -187,9 +193,19 @@ __all__ = [
|
|
|
187
193
|
"parse_eip191_signature",
|
|
188
194
|
"ED25519_KIND_TAG",
|
|
189
195
|
"build_ed25519_envelope",
|
|
196
|
+
"build_ed25519_envelope_from_signature",
|
|
190
197
|
"ed25519_owner_id",
|
|
191
198
|
"ed25519_pubkey_felts",
|
|
192
199
|
"ed25519_signed_bytes",
|
|
200
|
+
# webauthn signer (from-assertion)
|
|
201
|
+
"WEBAUTHN_KIND_TAG",
|
|
202
|
+
"WebAuthnPubkey",
|
|
203
|
+
"base64url_encode",
|
|
204
|
+
"build_webauthn_envelope_from_assertion",
|
|
205
|
+
"byte_array_to_felts",
|
|
206
|
+
"parse_der_ecdsa_signature",
|
|
207
|
+
"webauthn_owner_id",
|
|
208
|
+
"webauthn_pubkey_felts",
|
|
193
209
|
# jwt_apple_sub signer
|
|
194
210
|
"APPLE_ISSUER",
|
|
195
211
|
"AppleTokenResponse",
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
"""SHHH V8.4 signers (Python).
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Server-side kinds: STARK, Ed25519, EIP-191 secp256k1, WebAuthn P-256
|
|
4
|
+
(from-assertion only), JWT_ES256_APPLE_SUB (Apple Sign In).
|
|
5
5
|
|
|
6
|
-
WebAuthn
|
|
6
|
+
WebAuthn note: Python can't run ``navigator.credentials`` to *create*
|
|
7
|
+
assertions, but it CAN build an envelope from one a browser produced and
|
|
8
|
+
POSTed — the same server-side pattern as
|
|
9
|
+
``build_eip191_envelope_from_signature``. Only the from-assertion builder
|
|
10
|
+
is ported (no from-private-key helper).
|
|
7
11
|
"""
|
|
8
12
|
|
|
9
13
|
from .ed25519 import (
|
|
10
14
|
ED25519_KIND_TAG,
|
|
11
15
|
build_ed25519_envelope,
|
|
16
|
+
build_ed25519_envelope_from_signature,
|
|
12
17
|
ed25519_owner_id,
|
|
13
18
|
ed25519_pubkey_felts,
|
|
14
19
|
ed25519_signed_bytes,
|
|
@@ -24,9 +29,9 @@ from .eip191 import (
|
|
|
24
29
|
)
|
|
25
30
|
from .jwt_apple_sub import (
|
|
26
31
|
APPLE_ISSUER,
|
|
27
|
-
AppleTokenResponse,
|
|
28
32
|
JWT_APPLE_SUB_KIND_TAG,
|
|
29
33
|
JWT_APPLE_SUB_KIND_TAG_FELT,
|
|
34
|
+
AppleTokenResponse,
|
|
30
35
|
JwtAppleSubPubkey,
|
|
31
36
|
build_jwt_apple_sub_envelope_from_test_key,
|
|
32
37
|
build_jwt_apple_sub_envelope_from_token_response,
|
|
@@ -43,6 +48,16 @@ from .stark import (
|
|
|
43
48
|
stark_owner_id,
|
|
44
49
|
stark_pubkey_felts,
|
|
45
50
|
)
|
|
51
|
+
from .webauthn import (
|
|
52
|
+
WEBAUTHN_KIND_TAG,
|
|
53
|
+
WebAuthnPubkey,
|
|
54
|
+
base64url_encode,
|
|
55
|
+
build_webauthn_envelope_from_assertion,
|
|
56
|
+
byte_array_to_felts,
|
|
57
|
+
parse_der_ecdsa_signature,
|
|
58
|
+
webauthn_owner_id,
|
|
59
|
+
webauthn_pubkey_felts,
|
|
60
|
+
)
|
|
46
61
|
|
|
47
62
|
__all__ = [
|
|
48
63
|
"STARK_KIND_TAG",
|
|
@@ -58,9 +73,18 @@ __all__ = [
|
|
|
58
73
|
"parse_eip191_signature",
|
|
59
74
|
"ED25519_KIND_TAG",
|
|
60
75
|
"build_ed25519_envelope",
|
|
76
|
+
"build_ed25519_envelope_from_signature",
|
|
61
77
|
"ed25519_owner_id",
|
|
62
78
|
"ed25519_pubkey_felts",
|
|
63
79
|
"ed25519_signed_bytes",
|
|
80
|
+
"WEBAUTHN_KIND_TAG",
|
|
81
|
+
"WebAuthnPubkey",
|
|
82
|
+
"base64url_encode",
|
|
83
|
+
"build_webauthn_envelope_from_assertion",
|
|
84
|
+
"byte_array_to_felts",
|
|
85
|
+
"parse_der_ecdsa_signature",
|
|
86
|
+
"webauthn_owner_id",
|
|
87
|
+
"webauthn_pubkey_felts",
|
|
64
88
|
"APPLE_ISSUER",
|
|
65
89
|
"AppleTokenResponse",
|
|
66
90
|
"JWT_APPLE_SUB_KIND_TAG",
|
|
@@ -25,10 +25,8 @@ Implementation choices vs the TS side:
|
|
|
25
25
|
and amortized across the process lifetime.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
from typing import Union
|
|
29
|
-
|
|
30
|
-
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
31
28
|
from cryptography.hazmat.primitives import serialization
|
|
29
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
32
30
|
from garaga.starknet.tests_and_calldata_generators.signatures import (
|
|
33
31
|
EdDSA25519Signature,
|
|
34
32
|
)
|
|
@@ -114,9 +112,7 @@ def build_ed25519_envelope(
|
|
|
114
112
|
"owner_commitment or pubkey here."
|
|
115
113
|
)
|
|
116
114
|
if len(private_key) != 32:
|
|
117
|
-
raise ValueError(
|
|
118
|
-
f"Ed25519 private key must be exactly 32 bytes; got {len(private_key)}."
|
|
119
|
-
)
|
|
115
|
+
raise ValueError(f"Ed25519 private key must be exactly 32 bytes; got {len(private_key)}.")
|
|
120
116
|
|
|
121
117
|
pk = Ed25519PrivateKey.from_private_bytes(private_key)
|
|
122
118
|
public_key = pk.public_key().public_bytes(
|
|
@@ -128,21 +124,89 @@ def build_ed25519_envelope(
|
|
|
128
124
|
signature = pk.sign(signed_bytes)
|
|
129
125
|
|
|
130
126
|
# RFC 8032: signature = R (32B) || s (32B), both little-endian.
|
|
131
|
-
|
|
132
|
-
|
|
127
|
+
return _assemble_ed25519_envelope(
|
|
128
|
+
ry_twisted=int.from_bytes(signature[:32], "little"),
|
|
129
|
+
s_int=int.from_bytes(signature[32:64], "little"),
|
|
130
|
+
py_twisted=int.from_bytes(public_key, "little"),
|
|
131
|
+
signed_bytes=signed_bytes,
|
|
132
|
+
owner_index=owner_index,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def build_ed25519_envelope_from_signature(
|
|
137
|
+
*,
|
|
138
|
+
signature: bytes,
|
|
139
|
+
public_key: bytes,
|
|
140
|
+
message_hash: int,
|
|
141
|
+
owner_index: int = 0,
|
|
142
|
+
) -> list[int]:
|
|
143
|
+
"""Build a V2_SNIP12 Ed25519 envelope from an externally-produced
|
|
144
|
+
signature — the Phantom / Solana flow.
|
|
145
|
+
|
|
146
|
+
Phantom (and every external Ed25519 wallet) never exposes the private
|
|
147
|
+
key: the user signs via ``window.solana.signMessage(...)``, which
|
|
148
|
+
returns a 64-byte signature (R‖s). This is the from-signature
|
|
149
|
+
counterpart of :func:`build_ed25519_envelope`, mirroring
|
|
150
|
+
:func:`build_eip191_envelope_from_signature` for MetaMask and the TS
|
|
151
|
+
``buildEd25519EnvelopeFromSignature``.
|
|
152
|
+
|
|
153
|
+
The wallet MUST sign the exact bytes returned by
|
|
154
|
+
:func:`ed25519_signed_bytes` (the 64-byte hex-ASCII encoding of the
|
|
155
|
+
SNIP-12 OE hash) — NOT the raw 32-byte ``message_hash``. The Cairo
|
|
156
|
+
verifier reconstructs those same bytes, so a mismatch fails on chain.
|
|
157
|
+
|
|
158
|
+
Inputs:
|
|
159
|
+
signature — 64-byte Ed25519 signature R(32)‖s(32) from the
|
|
160
|
+
wallet's ``signMessage``.
|
|
161
|
+
public_key — 32-byte Ed25519 public key (as Phantom returns it).
|
|
162
|
+
message_hash — SNIP-12 hash of the OE (see oe.compute_oe_hash).
|
|
163
|
+
owner_index — u32 INDEX into the wallet's owner_set. Default 0.
|
|
164
|
+
"""
|
|
165
|
+
if not (0 <= owner_index < (1 << 32)):
|
|
166
|
+
raise ValueError(
|
|
167
|
+
f"build_ed25519_envelope_from_signature: owner_index {owner_index} "
|
|
168
|
+
"is out of u32 range [0, 2^32). owner_id is the u32 INDEX into the "
|
|
169
|
+
"wallet's owner_set (0 for primary); do NOT pass an owner_commitment "
|
|
170
|
+
"or pubkey here."
|
|
171
|
+
)
|
|
172
|
+
if len(signature) != 64:
|
|
173
|
+
raise ValueError(f"Ed25519 signature must be exactly 64 bytes (R‖s); got {len(signature)}.")
|
|
174
|
+
if len(public_key) != 32:
|
|
175
|
+
raise ValueError(f"Ed25519 public key must be exactly 32 bytes; got {len(public_key)}.")
|
|
176
|
+
|
|
177
|
+
signed_bytes = ed25519_signed_bytes(message_hash)
|
|
178
|
+
# RFC 8032: signature = R (32B) || s (32B), both little-endian.
|
|
179
|
+
return _assemble_ed25519_envelope(
|
|
180
|
+
ry_twisted=int.from_bytes(signature[:32], "little"),
|
|
181
|
+
s_int=int.from_bytes(signature[32:64], "little"),
|
|
182
|
+
py_twisted=int.from_bytes(public_key, "little"),
|
|
183
|
+
signed_bytes=signed_bytes,
|
|
184
|
+
owner_index=owner_index,
|
|
185
|
+
)
|
|
133
186
|
|
|
134
|
-
Ry_twisted = int.from_bytes(R, "little")
|
|
135
|
-
s_int = int.from_bytes(s_bytes, "little")
|
|
136
|
-
Py_twisted = int.from_bytes(public_key, "little")
|
|
137
187
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
188
|
+
def _assemble_ed25519_envelope(
|
|
189
|
+
*,
|
|
190
|
+
ry_twisted: int,
|
|
191
|
+
s_int: int,
|
|
192
|
+
py_twisted: int,
|
|
193
|
+
signed_bytes: bytes,
|
|
194
|
+
owner_index: int,
|
|
195
|
+
) -> list[int]:
|
|
196
|
+
"""Shared core for both Ed25519 builders: run Garaga's hint builder
|
|
197
|
+
over the signature halves + pubkey + signed message, then wrap in the
|
|
198
|
+
V2_SNIP12 envelope. The locally-signed and from-signature paths differ
|
|
199
|
+
ONLY in where (R, s, pubkey) come from.
|
|
200
|
+
|
|
201
|
+
Garaga's eddsa_calldata_builder produces:
|
|
202
|
+
[ Ry_low, Ry_high, s_low, s_high,
|
|
203
|
+
msg_len, msg_byte_0, ..., msg_byte_{msg_len-1},
|
|
204
|
+
*msm_hint, *sqrt_Rx_hint, *sqrt_Px_hint ]
|
|
205
|
+
"""
|
|
142
206
|
eddsa_sig = EdDSA25519Signature(
|
|
143
|
-
Ry_twisted=
|
|
207
|
+
Ry_twisted=ry_twisted,
|
|
144
208
|
s=s_int,
|
|
145
|
-
Py_twisted=
|
|
209
|
+
Py_twisted=py_twisted,
|
|
146
210
|
msg=signed_bytes,
|
|
147
211
|
)
|
|
148
212
|
payload = eddsa_sig.serialize_with_hints(
|