@calimero-network/mero-js 19.5.0 → 19.7.0
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.
- package/dist/account/account.d.ts +76 -0
- package/dist/account/account.js +0 -0
- package/dist/account/index.d.ts +2 -0
- package/dist/account/index.js +2 -0
- package/dist/account/wordlist.d.ts +16 -0
- package/dist/account/wordlist.js +273 -0
- package/dist/admin-api/admin-client.d.ts +69 -0
- package/dist/admin-api/admin-client.js +80 -0
- package/dist/cloud/cloud-client.d.ts +182 -0
- package/dist/cloud/cloud-client.js +142 -0
- package/dist/cloud/connect.js +8 -1
- package/dist/cloud/index.d.ts +1 -1
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +2585 -212
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.mjs +2585 -212
- package/dist/index.mjs.map +3 -3
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -697,6 +697,41 @@ function createAuthApiClientFromHttpClient(httpClient, _config) {
|
|
|
697
697
|
return new AuthApiClient(httpClient);
|
|
698
698
|
}
|
|
699
699
|
|
|
700
|
+
// src/capabilities.ts
|
|
701
|
+
var CAPABILITIES = {
|
|
702
|
+
CAN_CREATE_CONTEXT: 1 << 0,
|
|
703
|
+
CAN_INVITE_MEMBERS: 1 << 1,
|
|
704
|
+
CAN_JOIN_OPEN_SUBGROUPS: 1 << 2,
|
|
705
|
+
MANAGE_MEMBERS: 1 << 3,
|
|
706
|
+
MANAGE_APPLICATION: 1 << 4,
|
|
707
|
+
CAN_CREATE_SUBGROUP: 1 << 5,
|
|
708
|
+
CAN_DELETE_SUBGROUP: 1 << 6,
|
|
709
|
+
CAN_MANAGE_VISIBILITY: 1 << 7,
|
|
710
|
+
CAN_MANAGE_METADATA: 1 << 8,
|
|
711
|
+
/**
|
|
712
|
+
* Publish writes attributed to ANOTHER member, under a warrant that member
|
|
713
|
+
* signed — the grant delegated execution runs on.
|
|
714
|
+
*
|
|
715
|
+
* Implied by nothing: not by membership, not by admin, and not propagated by
|
|
716
|
+
* the subgroup-admit cascade. So every group is authorship-closed until an
|
|
717
|
+
* admin sets this bit, and a relay without it is refused at
|
|
718
|
+
* `performIntent` before anything executes. That is why it is worth naming
|
|
719
|
+
* here rather than leaving callers to write `1 << 9`: a client granting it
|
|
720
|
+
* has to be able to say what it is granting.
|
|
721
|
+
*/
|
|
722
|
+
CAN_AUTHOR_ON_BEHALF: 1 << 9
|
|
723
|
+
};
|
|
724
|
+
function hasCap(mask, cap) {
|
|
725
|
+
const capU32 = cap >>> 0;
|
|
726
|
+
return (mask & capU32) >>> 0 === capU32;
|
|
727
|
+
}
|
|
728
|
+
function withCap(mask, cap) {
|
|
729
|
+
return (mask | cap) >>> 0;
|
|
730
|
+
}
|
|
731
|
+
function withoutCap(mask, cap) {
|
|
732
|
+
return (mask & ~cap) >>> 0;
|
|
733
|
+
}
|
|
734
|
+
|
|
700
735
|
// src/admin-api/admin-client.ts
|
|
701
736
|
function unwrap(response) {
|
|
702
737
|
return response?.data;
|
|
@@ -1455,6 +1490,85 @@ var AdminApiClient = class {
|
|
|
1455
1490
|
async setDefaultCapabilities(groupId, request) {
|
|
1456
1491
|
await this.httpClient.put(`/admin-api/groups/${groupId}/settings/default-capabilities`, request);
|
|
1457
1492
|
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Make every member admitted to `groupId` from now on able to relay a
|
|
1495
|
+
* delegated write, without a per-node governance op each time.
|
|
1496
|
+
*
|
|
1497
|
+
* `CAN_AUTHOR_ON_BEHALF` is implied by nothing — not membership, not admin —
|
|
1498
|
+
* so every group is authorship-closed and each fleet relay otherwise needs an
|
|
1499
|
+
* admin to grant it individually, at the moment the relay is assigned and the
|
|
1500
|
+
* admin is not watching. Setting it in the group's DEFAULT mask is core's own
|
|
1501
|
+
* answer to that: `add_member` seeds a non-admin's capability row from the
|
|
1502
|
+
* default, so an attested node admitted afterwards lands open.
|
|
1503
|
+
*
|
|
1504
|
+
* Call it on the NAMESPACE (the root group). A grant resolves through the
|
|
1505
|
+
* membership anchor, so one at the root reaches every Open subgroup beneath
|
|
1506
|
+
* it, which is where contexts actually live; a `Restricted` subgroup is a
|
|
1507
|
+
* membership boundary and needs its own call.
|
|
1508
|
+
*
|
|
1509
|
+
* ### Two things this does not do
|
|
1510
|
+
*
|
|
1511
|
+
* **It is not retroactive.** The default is copied into a member's row when
|
|
1512
|
+
* that member is admitted, so nodes already admitted keep the row they got.
|
|
1513
|
+
* Use {@link grantAuthorship} for those — or call this at namespace creation,
|
|
1514
|
+
* which is the only point that needs no backfill at all.
|
|
1515
|
+
*
|
|
1516
|
+
* **It does not reach admins.** Core seeds the default only for non-admin
|
|
1517
|
+
* roles, and `CAN_AUTHOR_ON_BEHALF` is deliberately not implied by admin. An
|
|
1518
|
+
* admin's own node therefore stays closed and needs {@link grantAuthorship}.
|
|
1519
|
+
*
|
|
1520
|
+
* ### What it widens
|
|
1521
|
+
*
|
|
1522
|
+
* Every future non-admin member of the group, not only attested TEE nodes, so
|
|
1523
|
+
* any of them may be named as a warrant's `executor`. The bound worth knowing
|
|
1524
|
+
* before deciding: an executor cannot FORGE. A delegated write is authorized
|
|
1525
|
+
* by the author's own warrant — signed by their device key, committed to one
|
|
1526
|
+
* context, method and exact arguments, with its nonce checked unspent — so a
|
|
1527
|
+
* holder can only spend a warrant it was deliberately handed. What it does
|
|
1528
|
+
* gain is the arguments in cleartext and the choice of when, or whether, to
|
|
1529
|
+
* publish.
|
|
1530
|
+
*
|
|
1531
|
+
* Read-modify-write rather than a blind set: core seeds a new group's default
|
|
1532
|
+
* with `CAN_JOIN_OPEN_SUBGROUPS`, and overwriting that would quietly stop
|
|
1533
|
+
* every later member inheriting into Open subgroups.
|
|
1534
|
+
*
|
|
1535
|
+
* Returns the resulting mask and whether an op was published — it is a no-op
|
|
1536
|
+
* when the bit is already set, so it is safe to call on every startup.
|
|
1537
|
+
*/
|
|
1538
|
+
async openToDelegatedExecution(groupId) {
|
|
1539
|
+
const current = await this.getDefaultCapabilities(groupId);
|
|
1540
|
+
if (hasCap(current, CAPABILITIES.CAN_AUTHOR_ON_BEHALF)) {
|
|
1541
|
+
return { changed: false, defaultCapabilities: current };
|
|
1542
|
+
}
|
|
1543
|
+
const next = withCap(current, CAPABILITIES.CAN_AUTHOR_ON_BEHALF);
|
|
1544
|
+
await this.setDefaultCapabilities(groupId, { defaultCapabilities: next });
|
|
1545
|
+
return { changed: true, defaultCapabilities: next };
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* Grant `account` the authorship bit on `groupId`, leaving its other
|
|
1549
|
+
* capabilities alone.
|
|
1550
|
+
*
|
|
1551
|
+
* The per-member counterpart to {@link openToDelegatedExecution}, and what
|
|
1552
|
+
* closes the gap that method cannot: a relay admitted BEFORE the default was
|
|
1553
|
+
* set, and an admin's own node, which never receives the default at all.
|
|
1554
|
+
*
|
|
1555
|
+
* `account` is the member's ACCOUNT id (64 hex) as `listGroupMembers` returns
|
|
1556
|
+
* it — for a fleet relay, the `account` the cloud reports for that node. Not
|
|
1557
|
+
* the signing key that added them; both are 64 hex, so nothing but the source
|
|
1558
|
+
* tells them apart.
|
|
1559
|
+
*
|
|
1560
|
+
* Read-modify-write, so it adds the bit rather than replacing the member's
|
|
1561
|
+
* mask. A no-op when the member already holds it.
|
|
1562
|
+
*/
|
|
1563
|
+
async grantAuthorship(groupId, account) {
|
|
1564
|
+
const { capabilities } = await this.getMemberCapabilities(groupId, account);
|
|
1565
|
+
if (hasCap(capabilities, CAPABILITIES.CAN_AUTHOR_ON_BEHALF)) {
|
|
1566
|
+
return { changed: false, capabilities };
|
|
1567
|
+
}
|
|
1568
|
+
const next = withCap(capabilities, CAPABILITIES.CAN_AUTHOR_ON_BEHALF);
|
|
1569
|
+
await this.setMemberCapabilities(groupId, account, { capabilities: next });
|
|
1570
|
+
return { changed: true, capabilities: next };
|
|
1571
|
+
}
|
|
1458
1572
|
async setSubgroupVisibility(groupId, request) {
|
|
1459
1573
|
await this.httpClient.put(`/admin-api/groups/${groupId}/settings/subgroup-visibility`, request);
|
|
1460
1574
|
}
|
|
@@ -2315,6 +2429,2326 @@ var EphemeralClient = class {
|
|
|
2315
2429
|
}
|
|
2316
2430
|
};
|
|
2317
2431
|
|
|
2432
|
+
// src/crypto/internal.ts
|
|
2433
|
+
var PKCS8_ED25519_PREFIX = new Uint8Array([
|
|
2434
|
+
48,
|
|
2435
|
+
46,
|
|
2436
|
+
2,
|
|
2437
|
+
1,
|
|
2438
|
+
0,
|
|
2439
|
+
48,
|
|
2440
|
+
5,
|
|
2441
|
+
6,
|
|
2442
|
+
3,
|
|
2443
|
+
43,
|
|
2444
|
+
101,
|
|
2445
|
+
112,
|
|
2446
|
+
4,
|
|
2447
|
+
34,
|
|
2448
|
+
4,
|
|
2449
|
+
32
|
|
2450
|
+
]);
|
|
2451
|
+
function u32le(value) {
|
|
2452
|
+
const out = new Uint8Array(4);
|
|
2453
|
+
new DataView(out.buffer).setUint32(0, value, true);
|
|
2454
|
+
return out;
|
|
2455
|
+
}
|
|
2456
|
+
function hex(bytes) {
|
|
2457
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
2458
|
+
}
|
|
2459
|
+
function fromHex(value, label, expectedBytes) {
|
|
2460
|
+
const clean = value.trim();
|
|
2461
|
+
if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {
|
|
2462
|
+
throw new Error(
|
|
2463
|
+
`${label} must be ${expectedBytes * 2} hex characters, got ${clean.length}`
|
|
2464
|
+
);
|
|
2465
|
+
}
|
|
2466
|
+
const bytes = new Uint8Array(expectedBytes);
|
|
2467
|
+
for (let i = 0; i < expectedBytes; i += 1) {
|
|
2468
|
+
bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
2469
|
+
}
|
|
2470
|
+
return bytes;
|
|
2471
|
+
}
|
|
2472
|
+
function u64le(value) {
|
|
2473
|
+
const out = new Uint8Array(8);
|
|
2474
|
+
new DataView(out.buffer).setBigUint64(0, BigInt(value), true);
|
|
2475
|
+
return out;
|
|
2476
|
+
}
|
|
2477
|
+
function concat(...parts) {
|
|
2478
|
+
const out = new Uint8Array(parts.reduce((total, p) => total + p.length, 0));
|
|
2479
|
+
let offset = 0;
|
|
2480
|
+
for (const part of parts) {
|
|
2481
|
+
out.set(part, offset);
|
|
2482
|
+
offset += part.length;
|
|
2483
|
+
}
|
|
2484
|
+
return out;
|
|
2485
|
+
}
|
|
2486
|
+
async function domainHash(domain, parts) {
|
|
2487
|
+
const chunks = [u64le(domain.length), domain];
|
|
2488
|
+
for (const part of parts) {
|
|
2489
|
+
chunks.push(u64le(part.length), part);
|
|
2490
|
+
}
|
|
2491
|
+
return new Uint8Array(
|
|
2492
|
+
await crypto.subtle.digest("SHA-256", concat(...chunks))
|
|
2493
|
+
);
|
|
2494
|
+
}
|
|
2495
|
+
async function importSigningKey(secretHex) {
|
|
2496
|
+
const seed = fromHex(secretHex, "deviceSecret", 32);
|
|
2497
|
+
const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
|
|
2498
|
+
try {
|
|
2499
|
+
return await crypto.subtle.importKey(
|
|
2500
|
+
"pkcs8",
|
|
2501
|
+
pkcs8,
|
|
2502
|
+
{ name: "Ed25519" },
|
|
2503
|
+
false,
|
|
2504
|
+
["sign"]
|
|
2505
|
+
);
|
|
2506
|
+
} catch (cause) {
|
|
2507
|
+
const detail = cause instanceof Error ? `: ${cause.message}` : "";
|
|
2508
|
+
throw new Error(
|
|
2509
|
+
"this runtime has no WebCrypto Ed25519, so a warrant cannot be signed here. Node 18.4+, Safari 17+, Firefox 129+ and Chrome 137+ have it; otherwise mint the warrant with `merod account warrant`" + detail
|
|
2510
|
+
);
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
async function derivePublicKey(secretHex) {
|
|
2514
|
+
const seed = fromHex(secretHex, "deviceSecret", 32);
|
|
2515
|
+
const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
|
|
2516
|
+
const key = await crypto.subtle.importKey(
|
|
2517
|
+
"pkcs8",
|
|
2518
|
+
pkcs8,
|
|
2519
|
+
{ name: "Ed25519" },
|
|
2520
|
+
true,
|
|
2521
|
+
["sign"]
|
|
2522
|
+
);
|
|
2523
|
+
const jwk = await crypto.subtle.exportKey("jwk", key);
|
|
2524
|
+
const raw = jwk.x;
|
|
2525
|
+
return Uint8Array.from(
|
|
2526
|
+
atob(raw.replace(/-/g, "+").replace(/_/g, "/")),
|
|
2527
|
+
(c) => c.charCodeAt(0)
|
|
2528
|
+
);
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2531
|
+
// src/device-cert/device-cert.ts
|
|
2532
|
+
var CERT_DOMAIN = new TextEncoder().encode("calimero.device.cert.v1");
|
|
2533
|
+
var ACCOUNT_ID_DOMAIN = new TextEncoder().encode("calimero.account.genesis.v1");
|
|
2534
|
+
var DEVICE_ID_DOMAIN = new TextEncoder().encode("calimero.device.id.v1");
|
|
2535
|
+
var ACCOUNT_GENESIS_VERSION = 2;
|
|
2536
|
+
async function mintDeviceId(account, nonce) {
|
|
2537
|
+
if (nonce.length !== 16) {
|
|
2538
|
+
throw new Error(`nonce must be 16 bytes, got ${nonce.length}`);
|
|
2539
|
+
}
|
|
2540
|
+
const accountBytes = fromHex(account, "account", 32);
|
|
2541
|
+
return hex(await domainHash(DEVICE_ID_DOMAIN, [accountBytes, nonce]));
|
|
2542
|
+
}
|
|
2543
|
+
async function deviceCertPayload(input) {
|
|
2544
|
+
return domainHash(CERT_DOMAIN, [
|
|
2545
|
+
fromHex(input.account, "account", 32),
|
|
2546
|
+
fromHex(input.device, "device", 32),
|
|
2547
|
+
fromHex(input.signPublicKey, "signPublicKey", 32),
|
|
2548
|
+
fromHex(input.kemPublicKey, "kemPublicKey", 32),
|
|
2549
|
+
u32le(input.keyEpoch),
|
|
2550
|
+
u32le(input.deviceEpoch)
|
|
2551
|
+
]);
|
|
2552
|
+
}
|
|
2553
|
+
function accountProofBytes(input) {
|
|
2554
|
+
return concat(
|
|
2555
|
+
new Uint8Array([ACCOUNT_GENESIS_VERSION]),
|
|
2556
|
+
input.rootPublicKey,
|
|
2557
|
+
u32le(0),
|
|
2558
|
+
fromHex(input.account, "account", 32),
|
|
2559
|
+
fromHex(input.device, "device", 32),
|
|
2560
|
+
fromHex(input.signPublicKey, "signPublicKey", 32),
|
|
2561
|
+
fromHex(input.kemPublicKey, "kemPublicKey", 32),
|
|
2562
|
+
u32le(input.keyEpoch),
|
|
2563
|
+
u32le(input.deviceEpoch),
|
|
2564
|
+
input.signature
|
|
2565
|
+
);
|
|
2566
|
+
}
|
|
2567
|
+
async function signDeviceCert(input) {
|
|
2568
|
+
const rootPublicKey = await derivePublicKey(input.rootSecret);
|
|
2569
|
+
const account = hex(
|
|
2570
|
+
await domainHash(ACCOUNT_ID_DOMAIN, [
|
|
2571
|
+
concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey)
|
|
2572
|
+
])
|
|
2573
|
+
);
|
|
2574
|
+
const keyEpoch = 0;
|
|
2575
|
+
const payload = await deviceCertPayload({
|
|
2576
|
+
account,
|
|
2577
|
+
device: input.device,
|
|
2578
|
+
signPublicKey: input.signPublicKey,
|
|
2579
|
+
kemPublicKey: input.kemPublicKey,
|
|
2580
|
+
keyEpoch,
|
|
2581
|
+
deviceEpoch: input.deviceEpoch
|
|
2582
|
+
});
|
|
2583
|
+
const key = await importSigningKey(input.rootSecret);
|
|
2584
|
+
const signature = new Uint8Array(
|
|
2585
|
+
await crypto.subtle.sign("Ed25519", key, payload)
|
|
2586
|
+
);
|
|
2587
|
+
const credential = accountProofBytes({
|
|
2588
|
+
rootPublicKey,
|
|
2589
|
+
account,
|
|
2590
|
+
device: input.device,
|
|
2591
|
+
signPublicKey: input.signPublicKey,
|
|
2592
|
+
kemPublicKey: input.kemPublicKey,
|
|
2593
|
+
keyEpoch,
|
|
2594
|
+
deviceEpoch: input.deviceEpoch,
|
|
2595
|
+
signature
|
|
2596
|
+
});
|
|
2597
|
+
return hex(credential);
|
|
2598
|
+
}
|
|
2599
|
+
async function accountForRoot(rootSecret) {
|
|
2600
|
+
const rootPublicKey = await derivePublicKey(rootSecret);
|
|
2601
|
+
return hex(
|
|
2602
|
+
await domainHash(ACCOUNT_ID_DOMAIN, [
|
|
2603
|
+
concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey)
|
|
2604
|
+
])
|
|
2605
|
+
);
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
// src/account/wordlist.ts
|
|
2609
|
+
var ENGLISH_WORDLIST = [
|
|
2610
|
+
"abandon",
|
|
2611
|
+
"ability",
|
|
2612
|
+
"able",
|
|
2613
|
+
"about",
|
|
2614
|
+
"above",
|
|
2615
|
+
"absent",
|
|
2616
|
+
"absorb",
|
|
2617
|
+
"abstract",
|
|
2618
|
+
"absurd",
|
|
2619
|
+
"abuse",
|
|
2620
|
+
"access",
|
|
2621
|
+
"accident",
|
|
2622
|
+
"account",
|
|
2623
|
+
"accuse",
|
|
2624
|
+
"achieve",
|
|
2625
|
+
"acid",
|
|
2626
|
+
"acoustic",
|
|
2627
|
+
"acquire",
|
|
2628
|
+
"across",
|
|
2629
|
+
"act",
|
|
2630
|
+
"action",
|
|
2631
|
+
"actor",
|
|
2632
|
+
"actress",
|
|
2633
|
+
"actual",
|
|
2634
|
+
"adapt",
|
|
2635
|
+
"add",
|
|
2636
|
+
"addict",
|
|
2637
|
+
"address",
|
|
2638
|
+
"adjust",
|
|
2639
|
+
"admit",
|
|
2640
|
+
"adult",
|
|
2641
|
+
"advance",
|
|
2642
|
+
"advice",
|
|
2643
|
+
"aerobic",
|
|
2644
|
+
"affair",
|
|
2645
|
+
"afford",
|
|
2646
|
+
"afraid",
|
|
2647
|
+
"again",
|
|
2648
|
+
"age",
|
|
2649
|
+
"agent",
|
|
2650
|
+
"agree",
|
|
2651
|
+
"ahead",
|
|
2652
|
+
"aim",
|
|
2653
|
+
"air",
|
|
2654
|
+
"airport",
|
|
2655
|
+
"aisle",
|
|
2656
|
+
"alarm",
|
|
2657
|
+
"album",
|
|
2658
|
+
"alcohol",
|
|
2659
|
+
"alert",
|
|
2660
|
+
"alien",
|
|
2661
|
+
"all",
|
|
2662
|
+
"alley",
|
|
2663
|
+
"allow",
|
|
2664
|
+
"almost",
|
|
2665
|
+
"alone",
|
|
2666
|
+
"alpha",
|
|
2667
|
+
"already",
|
|
2668
|
+
"also",
|
|
2669
|
+
"alter",
|
|
2670
|
+
"always",
|
|
2671
|
+
"amateur",
|
|
2672
|
+
"amazing",
|
|
2673
|
+
"among",
|
|
2674
|
+
"amount",
|
|
2675
|
+
"amused",
|
|
2676
|
+
"analyst",
|
|
2677
|
+
"anchor",
|
|
2678
|
+
"ancient",
|
|
2679
|
+
"anger",
|
|
2680
|
+
"angle",
|
|
2681
|
+
"angry",
|
|
2682
|
+
"animal",
|
|
2683
|
+
"ankle",
|
|
2684
|
+
"announce",
|
|
2685
|
+
"annual",
|
|
2686
|
+
"another",
|
|
2687
|
+
"answer",
|
|
2688
|
+
"antenna",
|
|
2689
|
+
"antique",
|
|
2690
|
+
"anxiety",
|
|
2691
|
+
"any",
|
|
2692
|
+
"apart",
|
|
2693
|
+
"apology",
|
|
2694
|
+
"appear",
|
|
2695
|
+
"apple",
|
|
2696
|
+
"approve",
|
|
2697
|
+
"april",
|
|
2698
|
+
"arch",
|
|
2699
|
+
"arctic",
|
|
2700
|
+
"area",
|
|
2701
|
+
"arena",
|
|
2702
|
+
"argue",
|
|
2703
|
+
"arm",
|
|
2704
|
+
"armed",
|
|
2705
|
+
"armor",
|
|
2706
|
+
"army",
|
|
2707
|
+
"around",
|
|
2708
|
+
"arrange",
|
|
2709
|
+
"arrest",
|
|
2710
|
+
"arrive",
|
|
2711
|
+
"arrow",
|
|
2712
|
+
"art",
|
|
2713
|
+
"artefact",
|
|
2714
|
+
"artist",
|
|
2715
|
+
"artwork",
|
|
2716
|
+
"ask",
|
|
2717
|
+
"aspect",
|
|
2718
|
+
"assault",
|
|
2719
|
+
"asset",
|
|
2720
|
+
"assist",
|
|
2721
|
+
"assume",
|
|
2722
|
+
"asthma",
|
|
2723
|
+
"athlete",
|
|
2724
|
+
"atom",
|
|
2725
|
+
"attack",
|
|
2726
|
+
"attend",
|
|
2727
|
+
"attitude",
|
|
2728
|
+
"attract",
|
|
2729
|
+
"auction",
|
|
2730
|
+
"audit",
|
|
2731
|
+
"august",
|
|
2732
|
+
"aunt",
|
|
2733
|
+
"author",
|
|
2734
|
+
"auto",
|
|
2735
|
+
"autumn",
|
|
2736
|
+
"average",
|
|
2737
|
+
"avocado",
|
|
2738
|
+
"avoid",
|
|
2739
|
+
"awake",
|
|
2740
|
+
"aware",
|
|
2741
|
+
"away",
|
|
2742
|
+
"awesome",
|
|
2743
|
+
"awful",
|
|
2744
|
+
"awkward",
|
|
2745
|
+
"axis",
|
|
2746
|
+
"baby",
|
|
2747
|
+
"bachelor",
|
|
2748
|
+
"bacon",
|
|
2749
|
+
"badge",
|
|
2750
|
+
"bag",
|
|
2751
|
+
"balance",
|
|
2752
|
+
"balcony",
|
|
2753
|
+
"ball",
|
|
2754
|
+
"bamboo",
|
|
2755
|
+
"banana",
|
|
2756
|
+
"banner",
|
|
2757
|
+
"bar",
|
|
2758
|
+
"barely",
|
|
2759
|
+
"bargain",
|
|
2760
|
+
"barrel",
|
|
2761
|
+
"base",
|
|
2762
|
+
"basic",
|
|
2763
|
+
"basket",
|
|
2764
|
+
"battle",
|
|
2765
|
+
"beach",
|
|
2766
|
+
"bean",
|
|
2767
|
+
"beauty",
|
|
2768
|
+
"because",
|
|
2769
|
+
"become",
|
|
2770
|
+
"beef",
|
|
2771
|
+
"before",
|
|
2772
|
+
"begin",
|
|
2773
|
+
"behave",
|
|
2774
|
+
"behind",
|
|
2775
|
+
"believe",
|
|
2776
|
+
"below",
|
|
2777
|
+
"belt",
|
|
2778
|
+
"bench",
|
|
2779
|
+
"benefit",
|
|
2780
|
+
"best",
|
|
2781
|
+
"betray",
|
|
2782
|
+
"better",
|
|
2783
|
+
"between",
|
|
2784
|
+
"beyond",
|
|
2785
|
+
"bicycle",
|
|
2786
|
+
"bid",
|
|
2787
|
+
"bike",
|
|
2788
|
+
"bind",
|
|
2789
|
+
"biology",
|
|
2790
|
+
"bird",
|
|
2791
|
+
"birth",
|
|
2792
|
+
"bitter",
|
|
2793
|
+
"black",
|
|
2794
|
+
"blade",
|
|
2795
|
+
"blame",
|
|
2796
|
+
"blanket",
|
|
2797
|
+
"blast",
|
|
2798
|
+
"bleak",
|
|
2799
|
+
"bless",
|
|
2800
|
+
"blind",
|
|
2801
|
+
"blood",
|
|
2802
|
+
"blossom",
|
|
2803
|
+
"blouse",
|
|
2804
|
+
"blue",
|
|
2805
|
+
"blur",
|
|
2806
|
+
"blush",
|
|
2807
|
+
"board",
|
|
2808
|
+
"boat",
|
|
2809
|
+
"body",
|
|
2810
|
+
"boil",
|
|
2811
|
+
"bomb",
|
|
2812
|
+
"bone",
|
|
2813
|
+
"bonus",
|
|
2814
|
+
"book",
|
|
2815
|
+
"boost",
|
|
2816
|
+
"border",
|
|
2817
|
+
"boring",
|
|
2818
|
+
"borrow",
|
|
2819
|
+
"boss",
|
|
2820
|
+
"bottom",
|
|
2821
|
+
"bounce",
|
|
2822
|
+
"box",
|
|
2823
|
+
"boy",
|
|
2824
|
+
"bracket",
|
|
2825
|
+
"brain",
|
|
2826
|
+
"brand",
|
|
2827
|
+
"brass",
|
|
2828
|
+
"brave",
|
|
2829
|
+
"bread",
|
|
2830
|
+
"breeze",
|
|
2831
|
+
"brick",
|
|
2832
|
+
"bridge",
|
|
2833
|
+
"brief",
|
|
2834
|
+
"bright",
|
|
2835
|
+
"bring",
|
|
2836
|
+
"brisk",
|
|
2837
|
+
"broccoli",
|
|
2838
|
+
"broken",
|
|
2839
|
+
"bronze",
|
|
2840
|
+
"broom",
|
|
2841
|
+
"brother",
|
|
2842
|
+
"brown",
|
|
2843
|
+
"brush",
|
|
2844
|
+
"bubble",
|
|
2845
|
+
"buddy",
|
|
2846
|
+
"budget",
|
|
2847
|
+
"buffalo",
|
|
2848
|
+
"build",
|
|
2849
|
+
"bulb",
|
|
2850
|
+
"bulk",
|
|
2851
|
+
"bullet",
|
|
2852
|
+
"bundle",
|
|
2853
|
+
"bunker",
|
|
2854
|
+
"burden",
|
|
2855
|
+
"burger",
|
|
2856
|
+
"burst",
|
|
2857
|
+
"bus",
|
|
2858
|
+
"business",
|
|
2859
|
+
"busy",
|
|
2860
|
+
"butter",
|
|
2861
|
+
"buyer",
|
|
2862
|
+
"buzz",
|
|
2863
|
+
"cabbage",
|
|
2864
|
+
"cabin",
|
|
2865
|
+
"cable",
|
|
2866
|
+
"cactus",
|
|
2867
|
+
"cage",
|
|
2868
|
+
"cake",
|
|
2869
|
+
"call",
|
|
2870
|
+
"calm",
|
|
2871
|
+
"camera",
|
|
2872
|
+
"camp",
|
|
2873
|
+
"can",
|
|
2874
|
+
"canal",
|
|
2875
|
+
"cancel",
|
|
2876
|
+
"candy",
|
|
2877
|
+
"cannon",
|
|
2878
|
+
"canoe",
|
|
2879
|
+
"canvas",
|
|
2880
|
+
"canyon",
|
|
2881
|
+
"capable",
|
|
2882
|
+
"capital",
|
|
2883
|
+
"captain",
|
|
2884
|
+
"car",
|
|
2885
|
+
"carbon",
|
|
2886
|
+
"card",
|
|
2887
|
+
"cargo",
|
|
2888
|
+
"carpet",
|
|
2889
|
+
"carry",
|
|
2890
|
+
"cart",
|
|
2891
|
+
"case",
|
|
2892
|
+
"cash",
|
|
2893
|
+
"casino",
|
|
2894
|
+
"castle",
|
|
2895
|
+
"casual",
|
|
2896
|
+
"cat",
|
|
2897
|
+
"catalog",
|
|
2898
|
+
"catch",
|
|
2899
|
+
"category",
|
|
2900
|
+
"cattle",
|
|
2901
|
+
"caught",
|
|
2902
|
+
"cause",
|
|
2903
|
+
"caution",
|
|
2904
|
+
"cave",
|
|
2905
|
+
"ceiling",
|
|
2906
|
+
"celery",
|
|
2907
|
+
"cement",
|
|
2908
|
+
"census",
|
|
2909
|
+
"century",
|
|
2910
|
+
"cereal",
|
|
2911
|
+
"certain",
|
|
2912
|
+
"chair",
|
|
2913
|
+
"chalk",
|
|
2914
|
+
"champion",
|
|
2915
|
+
"change",
|
|
2916
|
+
"chaos",
|
|
2917
|
+
"chapter",
|
|
2918
|
+
"charge",
|
|
2919
|
+
"chase",
|
|
2920
|
+
"chat",
|
|
2921
|
+
"cheap",
|
|
2922
|
+
"check",
|
|
2923
|
+
"cheese",
|
|
2924
|
+
"chef",
|
|
2925
|
+
"cherry",
|
|
2926
|
+
"chest",
|
|
2927
|
+
"chicken",
|
|
2928
|
+
"chief",
|
|
2929
|
+
"child",
|
|
2930
|
+
"chimney",
|
|
2931
|
+
"choice",
|
|
2932
|
+
"choose",
|
|
2933
|
+
"chronic",
|
|
2934
|
+
"chuckle",
|
|
2935
|
+
"chunk",
|
|
2936
|
+
"churn",
|
|
2937
|
+
"cigar",
|
|
2938
|
+
"cinnamon",
|
|
2939
|
+
"circle",
|
|
2940
|
+
"citizen",
|
|
2941
|
+
"city",
|
|
2942
|
+
"civil",
|
|
2943
|
+
"claim",
|
|
2944
|
+
"clap",
|
|
2945
|
+
"clarify",
|
|
2946
|
+
"claw",
|
|
2947
|
+
"clay",
|
|
2948
|
+
"clean",
|
|
2949
|
+
"clerk",
|
|
2950
|
+
"clever",
|
|
2951
|
+
"click",
|
|
2952
|
+
"client",
|
|
2953
|
+
"cliff",
|
|
2954
|
+
"climb",
|
|
2955
|
+
"clinic",
|
|
2956
|
+
"clip",
|
|
2957
|
+
"clock",
|
|
2958
|
+
"clog",
|
|
2959
|
+
"close",
|
|
2960
|
+
"cloth",
|
|
2961
|
+
"cloud",
|
|
2962
|
+
"clown",
|
|
2963
|
+
"club",
|
|
2964
|
+
"clump",
|
|
2965
|
+
"cluster",
|
|
2966
|
+
"clutch",
|
|
2967
|
+
"coach",
|
|
2968
|
+
"coast",
|
|
2969
|
+
"coconut",
|
|
2970
|
+
"code",
|
|
2971
|
+
"coffee",
|
|
2972
|
+
"coil",
|
|
2973
|
+
"coin",
|
|
2974
|
+
"collect",
|
|
2975
|
+
"color",
|
|
2976
|
+
"column",
|
|
2977
|
+
"combine",
|
|
2978
|
+
"come",
|
|
2979
|
+
"comfort",
|
|
2980
|
+
"comic",
|
|
2981
|
+
"common",
|
|
2982
|
+
"company",
|
|
2983
|
+
"concert",
|
|
2984
|
+
"conduct",
|
|
2985
|
+
"confirm",
|
|
2986
|
+
"congress",
|
|
2987
|
+
"connect",
|
|
2988
|
+
"consider",
|
|
2989
|
+
"control",
|
|
2990
|
+
"convince",
|
|
2991
|
+
"cook",
|
|
2992
|
+
"cool",
|
|
2993
|
+
"copper",
|
|
2994
|
+
"copy",
|
|
2995
|
+
"coral",
|
|
2996
|
+
"core",
|
|
2997
|
+
"corn",
|
|
2998
|
+
"correct",
|
|
2999
|
+
"cost",
|
|
3000
|
+
"cotton",
|
|
3001
|
+
"couch",
|
|
3002
|
+
"country",
|
|
3003
|
+
"couple",
|
|
3004
|
+
"course",
|
|
3005
|
+
"cousin",
|
|
3006
|
+
"cover",
|
|
3007
|
+
"coyote",
|
|
3008
|
+
"crack",
|
|
3009
|
+
"cradle",
|
|
3010
|
+
"craft",
|
|
3011
|
+
"cram",
|
|
3012
|
+
"crane",
|
|
3013
|
+
"crash",
|
|
3014
|
+
"crater",
|
|
3015
|
+
"crawl",
|
|
3016
|
+
"crazy",
|
|
3017
|
+
"cream",
|
|
3018
|
+
"credit",
|
|
3019
|
+
"creek",
|
|
3020
|
+
"crew",
|
|
3021
|
+
"cricket",
|
|
3022
|
+
"crime",
|
|
3023
|
+
"crisp",
|
|
3024
|
+
"critic",
|
|
3025
|
+
"crop",
|
|
3026
|
+
"cross",
|
|
3027
|
+
"crouch",
|
|
3028
|
+
"crowd",
|
|
3029
|
+
"crucial",
|
|
3030
|
+
"cruel",
|
|
3031
|
+
"cruise",
|
|
3032
|
+
"crumble",
|
|
3033
|
+
"crunch",
|
|
3034
|
+
"crush",
|
|
3035
|
+
"cry",
|
|
3036
|
+
"crystal",
|
|
3037
|
+
"cube",
|
|
3038
|
+
"culture",
|
|
3039
|
+
"cup",
|
|
3040
|
+
"cupboard",
|
|
3041
|
+
"curious",
|
|
3042
|
+
"current",
|
|
3043
|
+
"curtain",
|
|
3044
|
+
"curve",
|
|
3045
|
+
"cushion",
|
|
3046
|
+
"custom",
|
|
3047
|
+
"cute",
|
|
3048
|
+
"cycle",
|
|
3049
|
+
"dad",
|
|
3050
|
+
"damage",
|
|
3051
|
+
"damp",
|
|
3052
|
+
"dance",
|
|
3053
|
+
"danger",
|
|
3054
|
+
"daring",
|
|
3055
|
+
"dash",
|
|
3056
|
+
"daughter",
|
|
3057
|
+
"dawn",
|
|
3058
|
+
"day",
|
|
3059
|
+
"deal",
|
|
3060
|
+
"debate",
|
|
3061
|
+
"debris",
|
|
3062
|
+
"decade",
|
|
3063
|
+
"december",
|
|
3064
|
+
"decide",
|
|
3065
|
+
"decline",
|
|
3066
|
+
"decorate",
|
|
3067
|
+
"decrease",
|
|
3068
|
+
"deer",
|
|
3069
|
+
"defense",
|
|
3070
|
+
"define",
|
|
3071
|
+
"defy",
|
|
3072
|
+
"degree",
|
|
3073
|
+
"delay",
|
|
3074
|
+
"deliver",
|
|
3075
|
+
"demand",
|
|
3076
|
+
"demise",
|
|
3077
|
+
"denial",
|
|
3078
|
+
"dentist",
|
|
3079
|
+
"deny",
|
|
3080
|
+
"depart",
|
|
3081
|
+
"depend",
|
|
3082
|
+
"deposit",
|
|
3083
|
+
"depth",
|
|
3084
|
+
"deputy",
|
|
3085
|
+
"derive",
|
|
3086
|
+
"describe",
|
|
3087
|
+
"desert",
|
|
3088
|
+
"design",
|
|
3089
|
+
"desk",
|
|
3090
|
+
"despair",
|
|
3091
|
+
"destroy",
|
|
3092
|
+
"detail",
|
|
3093
|
+
"detect",
|
|
3094
|
+
"develop",
|
|
3095
|
+
"device",
|
|
3096
|
+
"devote",
|
|
3097
|
+
"diagram",
|
|
3098
|
+
"dial",
|
|
3099
|
+
"diamond",
|
|
3100
|
+
"diary",
|
|
3101
|
+
"dice",
|
|
3102
|
+
"diesel",
|
|
3103
|
+
"diet",
|
|
3104
|
+
"differ",
|
|
3105
|
+
"digital",
|
|
3106
|
+
"dignity",
|
|
3107
|
+
"dilemma",
|
|
3108
|
+
"dinner",
|
|
3109
|
+
"dinosaur",
|
|
3110
|
+
"direct",
|
|
3111
|
+
"dirt",
|
|
3112
|
+
"disagree",
|
|
3113
|
+
"discover",
|
|
3114
|
+
"disease",
|
|
3115
|
+
"dish",
|
|
3116
|
+
"dismiss",
|
|
3117
|
+
"disorder",
|
|
3118
|
+
"display",
|
|
3119
|
+
"distance",
|
|
3120
|
+
"divert",
|
|
3121
|
+
"divide",
|
|
3122
|
+
"divorce",
|
|
3123
|
+
"dizzy",
|
|
3124
|
+
"doctor",
|
|
3125
|
+
"document",
|
|
3126
|
+
"dog",
|
|
3127
|
+
"doll",
|
|
3128
|
+
"dolphin",
|
|
3129
|
+
"domain",
|
|
3130
|
+
"donate",
|
|
3131
|
+
"donkey",
|
|
3132
|
+
"donor",
|
|
3133
|
+
"door",
|
|
3134
|
+
"dose",
|
|
3135
|
+
"double",
|
|
3136
|
+
"dove",
|
|
3137
|
+
"draft",
|
|
3138
|
+
"dragon",
|
|
3139
|
+
"drama",
|
|
3140
|
+
"drastic",
|
|
3141
|
+
"draw",
|
|
3142
|
+
"dream",
|
|
3143
|
+
"dress",
|
|
3144
|
+
"drift",
|
|
3145
|
+
"drill",
|
|
3146
|
+
"drink",
|
|
3147
|
+
"drip",
|
|
3148
|
+
"drive",
|
|
3149
|
+
"drop",
|
|
3150
|
+
"drum",
|
|
3151
|
+
"dry",
|
|
3152
|
+
"duck",
|
|
3153
|
+
"dumb",
|
|
3154
|
+
"dune",
|
|
3155
|
+
"during",
|
|
3156
|
+
"dust",
|
|
3157
|
+
"dutch",
|
|
3158
|
+
"duty",
|
|
3159
|
+
"dwarf",
|
|
3160
|
+
"dynamic",
|
|
3161
|
+
"eager",
|
|
3162
|
+
"eagle",
|
|
3163
|
+
"early",
|
|
3164
|
+
"earn",
|
|
3165
|
+
"earth",
|
|
3166
|
+
"easily",
|
|
3167
|
+
"east",
|
|
3168
|
+
"easy",
|
|
3169
|
+
"echo",
|
|
3170
|
+
"ecology",
|
|
3171
|
+
"economy",
|
|
3172
|
+
"edge",
|
|
3173
|
+
"edit",
|
|
3174
|
+
"educate",
|
|
3175
|
+
"effort",
|
|
3176
|
+
"egg",
|
|
3177
|
+
"eight",
|
|
3178
|
+
"either",
|
|
3179
|
+
"elbow",
|
|
3180
|
+
"elder",
|
|
3181
|
+
"electric",
|
|
3182
|
+
"elegant",
|
|
3183
|
+
"element",
|
|
3184
|
+
"elephant",
|
|
3185
|
+
"elevator",
|
|
3186
|
+
"elite",
|
|
3187
|
+
"else",
|
|
3188
|
+
"embark",
|
|
3189
|
+
"embody",
|
|
3190
|
+
"embrace",
|
|
3191
|
+
"emerge",
|
|
3192
|
+
"emotion",
|
|
3193
|
+
"employ",
|
|
3194
|
+
"empower",
|
|
3195
|
+
"empty",
|
|
3196
|
+
"enable",
|
|
3197
|
+
"enact",
|
|
3198
|
+
"end",
|
|
3199
|
+
"endless",
|
|
3200
|
+
"endorse",
|
|
3201
|
+
"enemy",
|
|
3202
|
+
"energy",
|
|
3203
|
+
"enforce",
|
|
3204
|
+
"engage",
|
|
3205
|
+
"engine",
|
|
3206
|
+
"enhance",
|
|
3207
|
+
"enjoy",
|
|
3208
|
+
"enlist",
|
|
3209
|
+
"enough",
|
|
3210
|
+
"enrich",
|
|
3211
|
+
"enroll",
|
|
3212
|
+
"ensure",
|
|
3213
|
+
"enter",
|
|
3214
|
+
"entire",
|
|
3215
|
+
"entry",
|
|
3216
|
+
"envelope",
|
|
3217
|
+
"episode",
|
|
3218
|
+
"equal",
|
|
3219
|
+
"equip",
|
|
3220
|
+
"era",
|
|
3221
|
+
"erase",
|
|
3222
|
+
"erode",
|
|
3223
|
+
"erosion",
|
|
3224
|
+
"error",
|
|
3225
|
+
"erupt",
|
|
3226
|
+
"escape",
|
|
3227
|
+
"essay",
|
|
3228
|
+
"essence",
|
|
3229
|
+
"estate",
|
|
3230
|
+
"eternal",
|
|
3231
|
+
"ethics",
|
|
3232
|
+
"evidence",
|
|
3233
|
+
"evil",
|
|
3234
|
+
"evoke",
|
|
3235
|
+
"evolve",
|
|
3236
|
+
"exact",
|
|
3237
|
+
"example",
|
|
3238
|
+
"excess",
|
|
3239
|
+
"exchange",
|
|
3240
|
+
"excite",
|
|
3241
|
+
"exclude",
|
|
3242
|
+
"excuse",
|
|
3243
|
+
"execute",
|
|
3244
|
+
"exercise",
|
|
3245
|
+
"exhaust",
|
|
3246
|
+
"exhibit",
|
|
3247
|
+
"exile",
|
|
3248
|
+
"exist",
|
|
3249
|
+
"exit",
|
|
3250
|
+
"exotic",
|
|
3251
|
+
"expand",
|
|
3252
|
+
"expect",
|
|
3253
|
+
"expire",
|
|
3254
|
+
"explain",
|
|
3255
|
+
"expose",
|
|
3256
|
+
"express",
|
|
3257
|
+
"extend",
|
|
3258
|
+
"extra",
|
|
3259
|
+
"eye",
|
|
3260
|
+
"eyebrow",
|
|
3261
|
+
"fabric",
|
|
3262
|
+
"face",
|
|
3263
|
+
"faculty",
|
|
3264
|
+
"fade",
|
|
3265
|
+
"faint",
|
|
3266
|
+
"faith",
|
|
3267
|
+
"fall",
|
|
3268
|
+
"false",
|
|
3269
|
+
"fame",
|
|
3270
|
+
"family",
|
|
3271
|
+
"famous",
|
|
3272
|
+
"fan",
|
|
3273
|
+
"fancy",
|
|
3274
|
+
"fantasy",
|
|
3275
|
+
"farm",
|
|
3276
|
+
"fashion",
|
|
3277
|
+
"fat",
|
|
3278
|
+
"fatal",
|
|
3279
|
+
"father",
|
|
3280
|
+
"fatigue",
|
|
3281
|
+
"fault",
|
|
3282
|
+
"favorite",
|
|
3283
|
+
"feature",
|
|
3284
|
+
"february",
|
|
3285
|
+
"federal",
|
|
3286
|
+
"fee",
|
|
3287
|
+
"feed",
|
|
3288
|
+
"feel",
|
|
3289
|
+
"female",
|
|
3290
|
+
"fence",
|
|
3291
|
+
"festival",
|
|
3292
|
+
"fetch",
|
|
3293
|
+
"fever",
|
|
3294
|
+
"few",
|
|
3295
|
+
"fiber",
|
|
3296
|
+
"fiction",
|
|
3297
|
+
"field",
|
|
3298
|
+
"figure",
|
|
3299
|
+
"file",
|
|
3300
|
+
"film",
|
|
3301
|
+
"filter",
|
|
3302
|
+
"final",
|
|
3303
|
+
"find",
|
|
3304
|
+
"fine",
|
|
3305
|
+
"finger",
|
|
3306
|
+
"finish",
|
|
3307
|
+
"fire",
|
|
3308
|
+
"firm",
|
|
3309
|
+
"first",
|
|
3310
|
+
"fiscal",
|
|
3311
|
+
"fish",
|
|
3312
|
+
"fit",
|
|
3313
|
+
"fitness",
|
|
3314
|
+
"fix",
|
|
3315
|
+
"flag",
|
|
3316
|
+
"flame",
|
|
3317
|
+
"flash",
|
|
3318
|
+
"flat",
|
|
3319
|
+
"flavor",
|
|
3320
|
+
"flee",
|
|
3321
|
+
"flight",
|
|
3322
|
+
"flip",
|
|
3323
|
+
"float",
|
|
3324
|
+
"flock",
|
|
3325
|
+
"floor",
|
|
3326
|
+
"flower",
|
|
3327
|
+
"fluid",
|
|
3328
|
+
"flush",
|
|
3329
|
+
"fly",
|
|
3330
|
+
"foam",
|
|
3331
|
+
"focus",
|
|
3332
|
+
"fog",
|
|
3333
|
+
"foil",
|
|
3334
|
+
"fold",
|
|
3335
|
+
"follow",
|
|
3336
|
+
"food",
|
|
3337
|
+
"foot",
|
|
3338
|
+
"force",
|
|
3339
|
+
"forest",
|
|
3340
|
+
"forget",
|
|
3341
|
+
"fork",
|
|
3342
|
+
"fortune",
|
|
3343
|
+
"forum",
|
|
3344
|
+
"forward",
|
|
3345
|
+
"fossil",
|
|
3346
|
+
"foster",
|
|
3347
|
+
"found",
|
|
3348
|
+
"fox",
|
|
3349
|
+
"fragile",
|
|
3350
|
+
"frame",
|
|
3351
|
+
"frequent",
|
|
3352
|
+
"fresh",
|
|
3353
|
+
"friend",
|
|
3354
|
+
"fringe",
|
|
3355
|
+
"frog",
|
|
3356
|
+
"front",
|
|
3357
|
+
"frost",
|
|
3358
|
+
"frown",
|
|
3359
|
+
"frozen",
|
|
3360
|
+
"fruit",
|
|
3361
|
+
"fuel",
|
|
3362
|
+
"fun",
|
|
3363
|
+
"funny",
|
|
3364
|
+
"furnace",
|
|
3365
|
+
"fury",
|
|
3366
|
+
"future",
|
|
3367
|
+
"gadget",
|
|
3368
|
+
"gain",
|
|
3369
|
+
"galaxy",
|
|
3370
|
+
"gallery",
|
|
3371
|
+
"game",
|
|
3372
|
+
"gap",
|
|
3373
|
+
"garage",
|
|
3374
|
+
"garbage",
|
|
3375
|
+
"garden",
|
|
3376
|
+
"garlic",
|
|
3377
|
+
"garment",
|
|
3378
|
+
"gas",
|
|
3379
|
+
"gasp",
|
|
3380
|
+
"gate",
|
|
3381
|
+
"gather",
|
|
3382
|
+
"gauge",
|
|
3383
|
+
"gaze",
|
|
3384
|
+
"general",
|
|
3385
|
+
"genius",
|
|
3386
|
+
"genre",
|
|
3387
|
+
"gentle",
|
|
3388
|
+
"genuine",
|
|
3389
|
+
"gesture",
|
|
3390
|
+
"ghost",
|
|
3391
|
+
"giant",
|
|
3392
|
+
"gift",
|
|
3393
|
+
"giggle",
|
|
3394
|
+
"ginger",
|
|
3395
|
+
"giraffe",
|
|
3396
|
+
"girl",
|
|
3397
|
+
"give",
|
|
3398
|
+
"glad",
|
|
3399
|
+
"glance",
|
|
3400
|
+
"glare",
|
|
3401
|
+
"glass",
|
|
3402
|
+
"glide",
|
|
3403
|
+
"glimpse",
|
|
3404
|
+
"globe",
|
|
3405
|
+
"gloom",
|
|
3406
|
+
"glory",
|
|
3407
|
+
"glove",
|
|
3408
|
+
"glow",
|
|
3409
|
+
"glue",
|
|
3410
|
+
"goat",
|
|
3411
|
+
"goddess",
|
|
3412
|
+
"gold",
|
|
3413
|
+
"good",
|
|
3414
|
+
"goose",
|
|
3415
|
+
"gorilla",
|
|
3416
|
+
"gospel",
|
|
3417
|
+
"gossip",
|
|
3418
|
+
"govern",
|
|
3419
|
+
"gown",
|
|
3420
|
+
"grab",
|
|
3421
|
+
"grace",
|
|
3422
|
+
"grain",
|
|
3423
|
+
"grant",
|
|
3424
|
+
"grape",
|
|
3425
|
+
"grass",
|
|
3426
|
+
"gravity",
|
|
3427
|
+
"great",
|
|
3428
|
+
"green",
|
|
3429
|
+
"grid",
|
|
3430
|
+
"grief",
|
|
3431
|
+
"grit",
|
|
3432
|
+
"grocery",
|
|
3433
|
+
"group",
|
|
3434
|
+
"grow",
|
|
3435
|
+
"grunt",
|
|
3436
|
+
"guard",
|
|
3437
|
+
"guess",
|
|
3438
|
+
"guide",
|
|
3439
|
+
"guilt",
|
|
3440
|
+
"guitar",
|
|
3441
|
+
"gun",
|
|
3442
|
+
"gym",
|
|
3443
|
+
"habit",
|
|
3444
|
+
"hair",
|
|
3445
|
+
"half",
|
|
3446
|
+
"hammer",
|
|
3447
|
+
"hamster",
|
|
3448
|
+
"hand",
|
|
3449
|
+
"happy",
|
|
3450
|
+
"harbor",
|
|
3451
|
+
"hard",
|
|
3452
|
+
"harsh",
|
|
3453
|
+
"harvest",
|
|
3454
|
+
"hat",
|
|
3455
|
+
"have",
|
|
3456
|
+
"hawk",
|
|
3457
|
+
"hazard",
|
|
3458
|
+
"head",
|
|
3459
|
+
"health",
|
|
3460
|
+
"heart",
|
|
3461
|
+
"heavy",
|
|
3462
|
+
"hedgehog",
|
|
3463
|
+
"height",
|
|
3464
|
+
"hello",
|
|
3465
|
+
"helmet",
|
|
3466
|
+
"help",
|
|
3467
|
+
"hen",
|
|
3468
|
+
"hero",
|
|
3469
|
+
"hidden",
|
|
3470
|
+
"high",
|
|
3471
|
+
"hill",
|
|
3472
|
+
"hint",
|
|
3473
|
+
"hip",
|
|
3474
|
+
"hire",
|
|
3475
|
+
"history",
|
|
3476
|
+
"hobby",
|
|
3477
|
+
"hockey",
|
|
3478
|
+
"hold",
|
|
3479
|
+
"hole",
|
|
3480
|
+
"holiday",
|
|
3481
|
+
"hollow",
|
|
3482
|
+
"home",
|
|
3483
|
+
"honey",
|
|
3484
|
+
"hood",
|
|
3485
|
+
"hope",
|
|
3486
|
+
"horn",
|
|
3487
|
+
"horror",
|
|
3488
|
+
"horse",
|
|
3489
|
+
"hospital",
|
|
3490
|
+
"host",
|
|
3491
|
+
"hotel",
|
|
3492
|
+
"hour",
|
|
3493
|
+
"hover",
|
|
3494
|
+
"hub",
|
|
3495
|
+
"huge",
|
|
3496
|
+
"human",
|
|
3497
|
+
"humble",
|
|
3498
|
+
"humor",
|
|
3499
|
+
"hundred",
|
|
3500
|
+
"hungry",
|
|
3501
|
+
"hunt",
|
|
3502
|
+
"hurdle",
|
|
3503
|
+
"hurry",
|
|
3504
|
+
"hurt",
|
|
3505
|
+
"husband",
|
|
3506
|
+
"hybrid",
|
|
3507
|
+
"ice",
|
|
3508
|
+
"icon",
|
|
3509
|
+
"idea",
|
|
3510
|
+
"identify",
|
|
3511
|
+
"idle",
|
|
3512
|
+
"ignore",
|
|
3513
|
+
"ill",
|
|
3514
|
+
"illegal",
|
|
3515
|
+
"illness",
|
|
3516
|
+
"image",
|
|
3517
|
+
"imitate",
|
|
3518
|
+
"immense",
|
|
3519
|
+
"immune",
|
|
3520
|
+
"impact",
|
|
3521
|
+
"impose",
|
|
3522
|
+
"improve",
|
|
3523
|
+
"impulse",
|
|
3524
|
+
"inch",
|
|
3525
|
+
"include",
|
|
3526
|
+
"income",
|
|
3527
|
+
"increase",
|
|
3528
|
+
"index",
|
|
3529
|
+
"indicate",
|
|
3530
|
+
"indoor",
|
|
3531
|
+
"industry",
|
|
3532
|
+
"infant",
|
|
3533
|
+
"inflict",
|
|
3534
|
+
"inform",
|
|
3535
|
+
"inhale",
|
|
3536
|
+
"inherit",
|
|
3537
|
+
"initial",
|
|
3538
|
+
"inject",
|
|
3539
|
+
"injury",
|
|
3540
|
+
"inmate",
|
|
3541
|
+
"inner",
|
|
3542
|
+
"innocent",
|
|
3543
|
+
"input",
|
|
3544
|
+
"inquiry",
|
|
3545
|
+
"insane",
|
|
3546
|
+
"insect",
|
|
3547
|
+
"inside",
|
|
3548
|
+
"inspire",
|
|
3549
|
+
"install",
|
|
3550
|
+
"intact",
|
|
3551
|
+
"interest",
|
|
3552
|
+
"into",
|
|
3553
|
+
"invest",
|
|
3554
|
+
"invite",
|
|
3555
|
+
"involve",
|
|
3556
|
+
"iron",
|
|
3557
|
+
"island",
|
|
3558
|
+
"isolate",
|
|
3559
|
+
"issue",
|
|
3560
|
+
"item",
|
|
3561
|
+
"ivory",
|
|
3562
|
+
"jacket",
|
|
3563
|
+
"jaguar",
|
|
3564
|
+
"jar",
|
|
3565
|
+
"jazz",
|
|
3566
|
+
"jealous",
|
|
3567
|
+
"jeans",
|
|
3568
|
+
"jelly",
|
|
3569
|
+
"jewel",
|
|
3570
|
+
"job",
|
|
3571
|
+
"join",
|
|
3572
|
+
"joke",
|
|
3573
|
+
"journey",
|
|
3574
|
+
"joy",
|
|
3575
|
+
"judge",
|
|
3576
|
+
"juice",
|
|
3577
|
+
"jump",
|
|
3578
|
+
"jungle",
|
|
3579
|
+
"junior",
|
|
3580
|
+
"junk",
|
|
3581
|
+
"just",
|
|
3582
|
+
"kangaroo",
|
|
3583
|
+
"keen",
|
|
3584
|
+
"keep",
|
|
3585
|
+
"ketchup",
|
|
3586
|
+
"key",
|
|
3587
|
+
"kick",
|
|
3588
|
+
"kid",
|
|
3589
|
+
"kidney",
|
|
3590
|
+
"kind",
|
|
3591
|
+
"kingdom",
|
|
3592
|
+
"kiss",
|
|
3593
|
+
"kit",
|
|
3594
|
+
"kitchen",
|
|
3595
|
+
"kite",
|
|
3596
|
+
"kitten",
|
|
3597
|
+
"kiwi",
|
|
3598
|
+
"knee",
|
|
3599
|
+
"knife",
|
|
3600
|
+
"knock",
|
|
3601
|
+
"know",
|
|
3602
|
+
"lab",
|
|
3603
|
+
"label",
|
|
3604
|
+
"labor",
|
|
3605
|
+
"ladder",
|
|
3606
|
+
"lady",
|
|
3607
|
+
"lake",
|
|
3608
|
+
"lamp",
|
|
3609
|
+
"language",
|
|
3610
|
+
"laptop",
|
|
3611
|
+
"large",
|
|
3612
|
+
"later",
|
|
3613
|
+
"latin",
|
|
3614
|
+
"laugh",
|
|
3615
|
+
"laundry",
|
|
3616
|
+
"lava",
|
|
3617
|
+
"law",
|
|
3618
|
+
"lawn",
|
|
3619
|
+
"lawsuit",
|
|
3620
|
+
"layer",
|
|
3621
|
+
"lazy",
|
|
3622
|
+
"leader",
|
|
3623
|
+
"leaf",
|
|
3624
|
+
"learn",
|
|
3625
|
+
"leave",
|
|
3626
|
+
"lecture",
|
|
3627
|
+
"left",
|
|
3628
|
+
"leg",
|
|
3629
|
+
"legal",
|
|
3630
|
+
"legend",
|
|
3631
|
+
"leisure",
|
|
3632
|
+
"lemon",
|
|
3633
|
+
"lend",
|
|
3634
|
+
"length",
|
|
3635
|
+
"lens",
|
|
3636
|
+
"leopard",
|
|
3637
|
+
"lesson",
|
|
3638
|
+
"letter",
|
|
3639
|
+
"level",
|
|
3640
|
+
"liar",
|
|
3641
|
+
"liberty",
|
|
3642
|
+
"library",
|
|
3643
|
+
"license",
|
|
3644
|
+
"life",
|
|
3645
|
+
"lift",
|
|
3646
|
+
"light",
|
|
3647
|
+
"like",
|
|
3648
|
+
"limb",
|
|
3649
|
+
"limit",
|
|
3650
|
+
"link",
|
|
3651
|
+
"lion",
|
|
3652
|
+
"liquid",
|
|
3653
|
+
"list",
|
|
3654
|
+
"little",
|
|
3655
|
+
"live",
|
|
3656
|
+
"lizard",
|
|
3657
|
+
"load",
|
|
3658
|
+
"loan",
|
|
3659
|
+
"lobster",
|
|
3660
|
+
"local",
|
|
3661
|
+
"lock",
|
|
3662
|
+
"logic",
|
|
3663
|
+
"lonely",
|
|
3664
|
+
"long",
|
|
3665
|
+
"loop",
|
|
3666
|
+
"lottery",
|
|
3667
|
+
"loud",
|
|
3668
|
+
"lounge",
|
|
3669
|
+
"love",
|
|
3670
|
+
"loyal",
|
|
3671
|
+
"lucky",
|
|
3672
|
+
"luggage",
|
|
3673
|
+
"lumber",
|
|
3674
|
+
"lunar",
|
|
3675
|
+
"lunch",
|
|
3676
|
+
"luxury",
|
|
3677
|
+
"lyrics",
|
|
3678
|
+
"machine",
|
|
3679
|
+
"mad",
|
|
3680
|
+
"magic",
|
|
3681
|
+
"magnet",
|
|
3682
|
+
"maid",
|
|
3683
|
+
"mail",
|
|
3684
|
+
"main",
|
|
3685
|
+
"major",
|
|
3686
|
+
"make",
|
|
3687
|
+
"mammal",
|
|
3688
|
+
"man",
|
|
3689
|
+
"manage",
|
|
3690
|
+
"mandate",
|
|
3691
|
+
"mango",
|
|
3692
|
+
"mansion",
|
|
3693
|
+
"manual",
|
|
3694
|
+
"maple",
|
|
3695
|
+
"marble",
|
|
3696
|
+
"march",
|
|
3697
|
+
"margin",
|
|
3698
|
+
"marine",
|
|
3699
|
+
"market",
|
|
3700
|
+
"marriage",
|
|
3701
|
+
"mask",
|
|
3702
|
+
"mass",
|
|
3703
|
+
"master",
|
|
3704
|
+
"match",
|
|
3705
|
+
"material",
|
|
3706
|
+
"math",
|
|
3707
|
+
"matrix",
|
|
3708
|
+
"matter",
|
|
3709
|
+
"maximum",
|
|
3710
|
+
"maze",
|
|
3711
|
+
"meadow",
|
|
3712
|
+
"mean",
|
|
3713
|
+
"measure",
|
|
3714
|
+
"meat",
|
|
3715
|
+
"mechanic",
|
|
3716
|
+
"medal",
|
|
3717
|
+
"media",
|
|
3718
|
+
"melody",
|
|
3719
|
+
"melt",
|
|
3720
|
+
"member",
|
|
3721
|
+
"memory",
|
|
3722
|
+
"mention",
|
|
3723
|
+
"menu",
|
|
3724
|
+
"mercy",
|
|
3725
|
+
"merge",
|
|
3726
|
+
"merit",
|
|
3727
|
+
"merry",
|
|
3728
|
+
"mesh",
|
|
3729
|
+
"message",
|
|
3730
|
+
"metal",
|
|
3731
|
+
"method",
|
|
3732
|
+
"middle",
|
|
3733
|
+
"midnight",
|
|
3734
|
+
"milk",
|
|
3735
|
+
"million",
|
|
3736
|
+
"mimic",
|
|
3737
|
+
"mind",
|
|
3738
|
+
"minimum",
|
|
3739
|
+
"minor",
|
|
3740
|
+
"minute",
|
|
3741
|
+
"miracle",
|
|
3742
|
+
"mirror",
|
|
3743
|
+
"misery",
|
|
3744
|
+
"miss",
|
|
3745
|
+
"mistake",
|
|
3746
|
+
"mix",
|
|
3747
|
+
"mixed",
|
|
3748
|
+
"mixture",
|
|
3749
|
+
"mobile",
|
|
3750
|
+
"model",
|
|
3751
|
+
"modify",
|
|
3752
|
+
"mom",
|
|
3753
|
+
"moment",
|
|
3754
|
+
"monitor",
|
|
3755
|
+
"monkey",
|
|
3756
|
+
"monster",
|
|
3757
|
+
"month",
|
|
3758
|
+
"moon",
|
|
3759
|
+
"moral",
|
|
3760
|
+
"more",
|
|
3761
|
+
"morning",
|
|
3762
|
+
"mosquito",
|
|
3763
|
+
"mother",
|
|
3764
|
+
"motion",
|
|
3765
|
+
"motor",
|
|
3766
|
+
"mountain",
|
|
3767
|
+
"mouse",
|
|
3768
|
+
"move",
|
|
3769
|
+
"movie",
|
|
3770
|
+
"much",
|
|
3771
|
+
"muffin",
|
|
3772
|
+
"mule",
|
|
3773
|
+
"multiply",
|
|
3774
|
+
"muscle",
|
|
3775
|
+
"museum",
|
|
3776
|
+
"mushroom",
|
|
3777
|
+
"music",
|
|
3778
|
+
"must",
|
|
3779
|
+
"mutual",
|
|
3780
|
+
"myself",
|
|
3781
|
+
"mystery",
|
|
3782
|
+
"myth",
|
|
3783
|
+
"naive",
|
|
3784
|
+
"name",
|
|
3785
|
+
"napkin",
|
|
3786
|
+
"narrow",
|
|
3787
|
+
"nasty",
|
|
3788
|
+
"nation",
|
|
3789
|
+
"nature",
|
|
3790
|
+
"near",
|
|
3791
|
+
"neck",
|
|
3792
|
+
"need",
|
|
3793
|
+
"negative",
|
|
3794
|
+
"neglect",
|
|
3795
|
+
"neither",
|
|
3796
|
+
"nephew",
|
|
3797
|
+
"nerve",
|
|
3798
|
+
"nest",
|
|
3799
|
+
"net",
|
|
3800
|
+
"network",
|
|
3801
|
+
"neutral",
|
|
3802
|
+
"never",
|
|
3803
|
+
"news",
|
|
3804
|
+
"next",
|
|
3805
|
+
"nice",
|
|
3806
|
+
"night",
|
|
3807
|
+
"noble",
|
|
3808
|
+
"noise",
|
|
3809
|
+
"nominee",
|
|
3810
|
+
"noodle",
|
|
3811
|
+
"normal",
|
|
3812
|
+
"north",
|
|
3813
|
+
"nose",
|
|
3814
|
+
"notable",
|
|
3815
|
+
"note",
|
|
3816
|
+
"nothing",
|
|
3817
|
+
"notice",
|
|
3818
|
+
"novel",
|
|
3819
|
+
"now",
|
|
3820
|
+
"nuclear",
|
|
3821
|
+
"number",
|
|
3822
|
+
"nurse",
|
|
3823
|
+
"nut",
|
|
3824
|
+
"oak",
|
|
3825
|
+
"obey",
|
|
3826
|
+
"object",
|
|
3827
|
+
"oblige",
|
|
3828
|
+
"obscure",
|
|
3829
|
+
"observe",
|
|
3830
|
+
"obtain",
|
|
3831
|
+
"obvious",
|
|
3832
|
+
"occur",
|
|
3833
|
+
"ocean",
|
|
3834
|
+
"october",
|
|
3835
|
+
"odor",
|
|
3836
|
+
"off",
|
|
3837
|
+
"offer",
|
|
3838
|
+
"office",
|
|
3839
|
+
"often",
|
|
3840
|
+
"oil",
|
|
3841
|
+
"okay",
|
|
3842
|
+
"old",
|
|
3843
|
+
"olive",
|
|
3844
|
+
"olympic",
|
|
3845
|
+
"omit",
|
|
3846
|
+
"once",
|
|
3847
|
+
"one",
|
|
3848
|
+
"onion",
|
|
3849
|
+
"online",
|
|
3850
|
+
"only",
|
|
3851
|
+
"open",
|
|
3852
|
+
"opera",
|
|
3853
|
+
"opinion",
|
|
3854
|
+
"oppose",
|
|
3855
|
+
"option",
|
|
3856
|
+
"orange",
|
|
3857
|
+
"orbit",
|
|
3858
|
+
"orchard",
|
|
3859
|
+
"order",
|
|
3860
|
+
"ordinary",
|
|
3861
|
+
"organ",
|
|
3862
|
+
"orient",
|
|
3863
|
+
"original",
|
|
3864
|
+
"orphan",
|
|
3865
|
+
"ostrich",
|
|
3866
|
+
"other",
|
|
3867
|
+
"outdoor",
|
|
3868
|
+
"outer",
|
|
3869
|
+
"output",
|
|
3870
|
+
"outside",
|
|
3871
|
+
"oval",
|
|
3872
|
+
"oven",
|
|
3873
|
+
"over",
|
|
3874
|
+
"own",
|
|
3875
|
+
"owner",
|
|
3876
|
+
"oxygen",
|
|
3877
|
+
"oyster",
|
|
3878
|
+
"ozone",
|
|
3879
|
+
"pact",
|
|
3880
|
+
"paddle",
|
|
3881
|
+
"page",
|
|
3882
|
+
"pair",
|
|
3883
|
+
"palace",
|
|
3884
|
+
"palm",
|
|
3885
|
+
"panda",
|
|
3886
|
+
"panel",
|
|
3887
|
+
"panic",
|
|
3888
|
+
"panther",
|
|
3889
|
+
"paper",
|
|
3890
|
+
"parade",
|
|
3891
|
+
"parent",
|
|
3892
|
+
"park",
|
|
3893
|
+
"parrot",
|
|
3894
|
+
"party",
|
|
3895
|
+
"pass",
|
|
3896
|
+
"patch",
|
|
3897
|
+
"path",
|
|
3898
|
+
"patient",
|
|
3899
|
+
"patrol",
|
|
3900
|
+
"pattern",
|
|
3901
|
+
"pause",
|
|
3902
|
+
"pave",
|
|
3903
|
+
"payment",
|
|
3904
|
+
"peace",
|
|
3905
|
+
"peanut",
|
|
3906
|
+
"pear",
|
|
3907
|
+
"peasant",
|
|
3908
|
+
"pelican",
|
|
3909
|
+
"pen",
|
|
3910
|
+
"penalty",
|
|
3911
|
+
"pencil",
|
|
3912
|
+
"people",
|
|
3913
|
+
"pepper",
|
|
3914
|
+
"perfect",
|
|
3915
|
+
"permit",
|
|
3916
|
+
"person",
|
|
3917
|
+
"pet",
|
|
3918
|
+
"phone",
|
|
3919
|
+
"photo",
|
|
3920
|
+
"phrase",
|
|
3921
|
+
"physical",
|
|
3922
|
+
"piano",
|
|
3923
|
+
"picnic",
|
|
3924
|
+
"picture",
|
|
3925
|
+
"piece",
|
|
3926
|
+
"pig",
|
|
3927
|
+
"pigeon",
|
|
3928
|
+
"pill",
|
|
3929
|
+
"pilot",
|
|
3930
|
+
"pink",
|
|
3931
|
+
"pioneer",
|
|
3932
|
+
"pipe",
|
|
3933
|
+
"pistol",
|
|
3934
|
+
"pitch",
|
|
3935
|
+
"pizza",
|
|
3936
|
+
"place",
|
|
3937
|
+
"planet",
|
|
3938
|
+
"plastic",
|
|
3939
|
+
"plate",
|
|
3940
|
+
"play",
|
|
3941
|
+
"please",
|
|
3942
|
+
"pledge",
|
|
3943
|
+
"pluck",
|
|
3944
|
+
"plug",
|
|
3945
|
+
"plunge",
|
|
3946
|
+
"poem",
|
|
3947
|
+
"poet",
|
|
3948
|
+
"point",
|
|
3949
|
+
"polar",
|
|
3950
|
+
"pole",
|
|
3951
|
+
"police",
|
|
3952
|
+
"pond",
|
|
3953
|
+
"pony",
|
|
3954
|
+
"pool",
|
|
3955
|
+
"popular",
|
|
3956
|
+
"portion",
|
|
3957
|
+
"position",
|
|
3958
|
+
"possible",
|
|
3959
|
+
"post",
|
|
3960
|
+
"potato",
|
|
3961
|
+
"pottery",
|
|
3962
|
+
"poverty",
|
|
3963
|
+
"powder",
|
|
3964
|
+
"power",
|
|
3965
|
+
"practice",
|
|
3966
|
+
"praise",
|
|
3967
|
+
"predict",
|
|
3968
|
+
"prefer",
|
|
3969
|
+
"prepare",
|
|
3970
|
+
"present",
|
|
3971
|
+
"pretty",
|
|
3972
|
+
"prevent",
|
|
3973
|
+
"price",
|
|
3974
|
+
"pride",
|
|
3975
|
+
"primary",
|
|
3976
|
+
"print",
|
|
3977
|
+
"priority",
|
|
3978
|
+
"prison",
|
|
3979
|
+
"private",
|
|
3980
|
+
"prize",
|
|
3981
|
+
"problem",
|
|
3982
|
+
"process",
|
|
3983
|
+
"produce",
|
|
3984
|
+
"profit",
|
|
3985
|
+
"program",
|
|
3986
|
+
"project",
|
|
3987
|
+
"promote",
|
|
3988
|
+
"proof",
|
|
3989
|
+
"property",
|
|
3990
|
+
"prosper",
|
|
3991
|
+
"protect",
|
|
3992
|
+
"proud",
|
|
3993
|
+
"provide",
|
|
3994
|
+
"public",
|
|
3995
|
+
"pudding",
|
|
3996
|
+
"pull",
|
|
3997
|
+
"pulp",
|
|
3998
|
+
"pulse",
|
|
3999
|
+
"pumpkin",
|
|
4000
|
+
"punch",
|
|
4001
|
+
"pupil",
|
|
4002
|
+
"puppy",
|
|
4003
|
+
"purchase",
|
|
4004
|
+
"purity",
|
|
4005
|
+
"purpose",
|
|
4006
|
+
"purse",
|
|
4007
|
+
"push",
|
|
4008
|
+
"put",
|
|
4009
|
+
"puzzle",
|
|
4010
|
+
"pyramid",
|
|
4011
|
+
"quality",
|
|
4012
|
+
"quantum",
|
|
4013
|
+
"quarter",
|
|
4014
|
+
"question",
|
|
4015
|
+
"quick",
|
|
4016
|
+
"quit",
|
|
4017
|
+
"quiz",
|
|
4018
|
+
"quote",
|
|
4019
|
+
"rabbit",
|
|
4020
|
+
"raccoon",
|
|
4021
|
+
"race",
|
|
4022
|
+
"rack",
|
|
4023
|
+
"radar",
|
|
4024
|
+
"radio",
|
|
4025
|
+
"rail",
|
|
4026
|
+
"rain",
|
|
4027
|
+
"raise",
|
|
4028
|
+
"rally",
|
|
4029
|
+
"ramp",
|
|
4030
|
+
"ranch",
|
|
4031
|
+
"random",
|
|
4032
|
+
"range",
|
|
4033
|
+
"rapid",
|
|
4034
|
+
"rare",
|
|
4035
|
+
"rate",
|
|
4036
|
+
"rather",
|
|
4037
|
+
"raven",
|
|
4038
|
+
"raw",
|
|
4039
|
+
"razor",
|
|
4040
|
+
"ready",
|
|
4041
|
+
"real",
|
|
4042
|
+
"reason",
|
|
4043
|
+
"rebel",
|
|
4044
|
+
"rebuild",
|
|
4045
|
+
"recall",
|
|
4046
|
+
"receive",
|
|
4047
|
+
"recipe",
|
|
4048
|
+
"record",
|
|
4049
|
+
"recycle",
|
|
4050
|
+
"reduce",
|
|
4051
|
+
"reflect",
|
|
4052
|
+
"reform",
|
|
4053
|
+
"refuse",
|
|
4054
|
+
"region",
|
|
4055
|
+
"regret",
|
|
4056
|
+
"regular",
|
|
4057
|
+
"reject",
|
|
4058
|
+
"relax",
|
|
4059
|
+
"release",
|
|
4060
|
+
"relief",
|
|
4061
|
+
"rely",
|
|
4062
|
+
"remain",
|
|
4063
|
+
"remember",
|
|
4064
|
+
"remind",
|
|
4065
|
+
"remove",
|
|
4066
|
+
"render",
|
|
4067
|
+
"renew",
|
|
4068
|
+
"rent",
|
|
4069
|
+
"reopen",
|
|
4070
|
+
"repair",
|
|
4071
|
+
"repeat",
|
|
4072
|
+
"replace",
|
|
4073
|
+
"report",
|
|
4074
|
+
"require",
|
|
4075
|
+
"rescue",
|
|
4076
|
+
"resemble",
|
|
4077
|
+
"resist",
|
|
4078
|
+
"resource",
|
|
4079
|
+
"response",
|
|
4080
|
+
"result",
|
|
4081
|
+
"retire",
|
|
4082
|
+
"retreat",
|
|
4083
|
+
"return",
|
|
4084
|
+
"reunion",
|
|
4085
|
+
"reveal",
|
|
4086
|
+
"review",
|
|
4087
|
+
"reward",
|
|
4088
|
+
"rhythm",
|
|
4089
|
+
"rib",
|
|
4090
|
+
"ribbon",
|
|
4091
|
+
"rice",
|
|
4092
|
+
"rich",
|
|
4093
|
+
"ride",
|
|
4094
|
+
"ridge",
|
|
4095
|
+
"rifle",
|
|
4096
|
+
"right",
|
|
4097
|
+
"rigid",
|
|
4098
|
+
"ring",
|
|
4099
|
+
"riot",
|
|
4100
|
+
"ripple",
|
|
4101
|
+
"risk",
|
|
4102
|
+
"ritual",
|
|
4103
|
+
"rival",
|
|
4104
|
+
"river",
|
|
4105
|
+
"road",
|
|
4106
|
+
"roast",
|
|
4107
|
+
"robot",
|
|
4108
|
+
"robust",
|
|
4109
|
+
"rocket",
|
|
4110
|
+
"romance",
|
|
4111
|
+
"roof",
|
|
4112
|
+
"rookie",
|
|
4113
|
+
"room",
|
|
4114
|
+
"rose",
|
|
4115
|
+
"rotate",
|
|
4116
|
+
"rough",
|
|
4117
|
+
"round",
|
|
4118
|
+
"route",
|
|
4119
|
+
"royal",
|
|
4120
|
+
"rubber",
|
|
4121
|
+
"rude",
|
|
4122
|
+
"rug",
|
|
4123
|
+
"rule",
|
|
4124
|
+
"run",
|
|
4125
|
+
"runway",
|
|
4126
|
+
"rural",
|
|
4127
|
+
"sad",
|
|
4128
|
+
"saddle",
|
|
4129
|
+
"sadness",
|
|
4130
|
+
"safe",
|
|
4131
|
+
"sail",
|
|
4132
|
+
"salad",
|
|
4133
|
+
"salmon",
|
|
4134
|
+
"salon",
|
|
4135
|
+
"salt",
|
|
4136
|
+
"salute",
|
|
4137
|
+
"same",
|
|
4138
|
+
"sample",
|
|
4139
|
+
"sand",
|
|
4140
|
+
"satisfy",
|
|
4141
|
+
"satoshi",
|
|
4142
|
+
"sauce",
|
|
4143
|
+
"sausage",
|
|
4144
|
+
"save",
|
|
4145
|
+
"say",
|
|
4146
|
+
"scale",
|
|
4147
|
+
"scan",
|
|
4148
|
+
"scare",
|
|
4149
|
+
"scatter",
|
|
4150
|
+
"scene",
|
|
4151
|
+
"scheme",
|
|
4152
|
+
"school",
|
|
4153
|
+
"science",
|
|
4154
|
+
"scissors",
|
|
4155
|
+
"scorpion",
|
|
4156
|
+
"scout",
|
|
4157
|
+
"scrap",
|
|
4158
|
+
"screen",
|
|
4159
|
+
"script",
|
|
4160
|
+
"scrub",
|
|
4161
|
+
"sea",
|
|
4162
|
+
"search",
|
|
4163
|
+
"season",
|
|
4164
|
+
"seat",
|
|
4165
|
+
"second",
|
|
4166
|
+
"secret",
|
|
4167
|
+
"section",
|
|
4168
|
+
"security",
|
|
4169
|
+
"seed",
|
|
4170
|
+
"seek",
|
|
4171
|
+
"segment",
|
|
4172
|
+
"select",
|
|
4173
|
+
"sell",
|
|
4174
|
+
"seminar",
|
|
4175
|
+
"senior",
|
|
4176
|
+
"sense",
|
|
4177
|
+
"sentence",
|
|
4178
|
+
"series",
|
|
4179
|
+
"service",
|
|
4180
|
+
"session",
|
|
4181
|
+
"settle",
|
|
4182
|
+
"setup",
|
|
4183
|
+
"seven",
|
|
4184
|
+
"shadow",
|
|
4185
|
+
"shaft",
|
|
4186
|
+
"shallow",
|
|
4187
|
+
"share",
|
|
4188
|
+
"shed",
|
|
4189
|
+
"shell",
|
|
4190
|
+
"sheriff",
|
|
4191
|
+
"shield",
|
|
4192
|
+
"shift",
|
|
4193
|
+
"shine",
|
|
4194
|
+
"ship",
|
|
4195
|
+
"shiver",
|
|
4196
|
+
"shock",
|
|
4197
|
+
"shoe",
|
|
4198
|
+
"shoot",
|
|
4199
|
+
"shop",
|
|
4200
|
+
"short",
|
|
4201
|
+
"shoulder",
|
|
4202
|
+
"shove",
|
|
4203
|
+
"shrimp",
|
|
4204
|
+
"shrug",
|
|
4205
|
+
"shuffle",
|
|
4206
|
+
"shy",
|
|
4207
|
+
"sibling",
|
|
4208
|
+
"sick",
|
|
4209
|
+
"side",
|
|
4210
|
+
"siege",
|
|
4211
|
+
"sight",
|
|
4212
|
+
"sign",
|
|
4213
|
+
"silent",
|
|
4214
|
+
"silk",
|
|
4215
|
+
"silly",
|
|
4216
|
+
"silver",
|
|
4217
|
+
"similar",
|
|
4218
|
+
"simple",
|
|
4219
|
+
"since",
|
|
4220
|
+
"sing",
|
|
4221
|
+
"siren",
|
|
4222
|
+
"sister",
|
|
4223
|
+
"situate",
|
|
4224
|
+
"six",
|
|
4225
|
+
"size",
|
|
4226
|
+
"skate",
|
|
4227
|
+
"sketch",
|
|
4228
|
+
"ski",
|
|
4229
|
+
"skill",
|
|
4230
|
+
"skin",
|
|
4231
|
+
"skirt",
|
|
4232
|
+
"skull",
|
|
4233
|
+
"slab",
|
|
4234
|
+
"slam",
|
|
4235
|
+
"sleep",
|
|
4236
|
+
"slender",
|
|
4237
|
+
"slice",
|
|
4238
|
+
"slide",
|
|
4239
|
+
"slight",
|
|
4240
|
+
"slim",
|
|
4241
|
+
"slogan",
|
|
4242
|
+
"slot",
|
|
4243
|
+
"slow",
|
|
4244
|
+
"slush",
|
|
4245
|
+
"small",
|
|
4246
|
+
"smart",
|
|
4247
|
+
"smile",
|
|
4248
|
+
"smoke",
|
|
4249
|
+
"smooth",
|
|
4250
|
+
"snack",
|
|
4251
|
+
"snake",
|
|
4252
|
+
"snap",
|
|
4253
|
+
"sniff",
|
|
4254
|
+
"snow",
|
|
4255
|
+
"soap",
|
|
4256
|
+
"soccer",
|
|
4257
|
+
"social",
|
|
4258
|
+
"sock",
|
|
4259
|
+
"soda",
|
|
4260
|
+
"soft",
|
|
4261
|
+
"solar",
|
|
4262
|
+
"soldier",
|
|
4263
|
+
"solid",
|
|
4264
|
+
"solution",
|
|
4265
|
+
"solve",
|
|
4266
|
+
"someone",
|
|
4267
|
+
"song",
|
|
4268
|
+
"soon",
|
|
4269
|
+
"sorry",
|
|
4270
|
+
"sort",
|
|
4271
|
+
"soul",
|
|
4272
|
+
"sound",
|
|
4273
|
+
"soup",
|
|
4274
|
+
"source",
|
|
4275
|
+
"south",
|
|
4276
|
+
"space",
|
|
4277
|
+
"spare",
|
|
4278
|
+
"spatial",
|
|
4279
|
+
"spawn",
|
|
4280
|
+
"speak",
|
|
4281
|
+
"special",
|
|
4282
|
+
"speed",
|
|
4283
|
+
"spell",
|
|
4284
|
+
"spend",
|
|
4285
|
+
"sphere",
|
|
4286
|
+
"spice",
|
|
4287
|
+
"spider",
|
|
4288
|
+
"spike",
|
|
4289
|
+
"spin",
|
|
4290
|
+
"spirit",
|
|
4291
|
+
"split",
|
|
4292
|
+
"spoil",
|
|
4293
|
+
"sponsor",
|
|
4294
|
+
"spoon",
|
|
4295
|
+
"sport",
|
|
4296
|
+
"spot",
|
|
4297
|
+
"spray",
|
|
4298
|
+
"spread",
|
|
4299
|
+
"spring",
|
|
4300
|
+
"spy",
|
|
4301
|
+
"square",
|
|
4302
|
+
"squeeze",
|
|
4303
|
+
"squirrel",
|
|
4304
|
+
"stable",
|
|
4305
|
+
"stadium",
|
|
4306
|
+
"staff",
|
|
4307
|
+
"stage",
|
|
4308
|
+
"stairs",
|
|
4309
|
+
"stamp",
|
|
4310
|
+
"stand",
|
|
4311
|
+
"start",
|
|
4312
|
+
"state",
|
|
4313
|
+
"stay",
|
|
4314
|
+
"steak",
|
|
4315
|
+
"steel",
|
|
4316
|
+
"stem",
|
|
4317
|
+
"step",
|
|
4318
|
+
"stereo",
|
|
4319
|
+
"stick",
|
|
4320
|
+
"still",
|
|
4321
|
+
"sting",
|
|
4322
|
+
"stock",
|
|
4323
|
+
"stomach",
|
|
4324
|
+
"stone",
|
|
4325
|
+
"stool",
|
|
4326
|
+
"story",
|
|
4327
|
+
"stove",
|
|
4328
|
+
"strategy",
|
|
4329
|
+
"street",
|
|
4330
|
+
"strike",
|
|
4331
|
+
"strong",
|
|
4332
|
+
"struggle",
|
|
4333
|
+
"student",
|
|
4334
|
+
"stuff",
|
|
4335
|
+
"stumble",
|
|
4336
|
+
"style",
|
|
4337
|
+
"subject",
|
|
4338
|
+
"submit",
|
|
4339
|
+
"subway",
|
|
4340
|
+
"success",
|
|
4341
|
+
"such",
|
|
4342
|
+
"sudden",
|
|
4343
|
+
"suffer",
|
|
4344
|
+
"sugar",
|
|
4345
|
+
"suggest",
|
|
4346
|
+
"suit",
|
|
4347
|
+
"summer",
|
|
4348
|
+
"sun",
|
|
4349
|
+
"sunny",
|
|
4350
|
+
"sunset",
|
|
4351
|
+
"super",
|
|
4352
|
+
"supply",
|
|
4353
|
+
"supreme",
|
|
4354
|
+
"sure",
|
|
4355
|
+
"surface",
|
|
4356
|
+
"surge",
|
|
4357
|
+
"surprise",
|
|
4358
|
+
"surround",
|
|
4359
|
+
"survey",
|
|
4360
|
+
"suspect",
|
|
4361
|
+
"sustain",
|
|
4362
|
+
"swallow",
|
|
4363
|
+
"swamp",
|
|
4364
|
+
"swap",
|
|
4365
|
+
"swarm",
|
|
4366
|
+
"swear",
|
|
4367
|
+
"sweet",
|
|
4368
|
+
"swift",
|
|
4369
|
+
"swim",
|
|
4370
|
+
"swing",
|
|
4371
|
+
"switch",
|
|
4372
|
+
"sword",
|
|
4373
|
+
"symbol",
|
|
4374
|
+
"symptom",
|
|
4375
|
+
"syrup",
|
|
4376
|
+
"system",
|
|
4377
|
+
"table",
|
|
4378
|
+
"tackle",
|
|
4379
|
+
"tag",
|
|
4380
|
+
"tail",
|
|
4381
|
+
"talent",
|
|
4382
|
+
"talk",
|
|
4383
|
+
"tank",
|
|
4384
|
+
"tape",
|
|
4385
|
+
"target",
|
|
4386
|
+
"task",
|
|
4387
|
+
"taste",
|
|
4388
|
+
"tattoo",
|
|
4389
|
+
"taxi",
|
|
4390
|
+
"teach",
|
|
4391
|
+
"team",
|
|
4392
|
+
"tell",
|
|
4393
|
+
"ten",
|
|
4394
|
+
"tenant",
|
|
4395
|
+
"tennis",
|
|
4396
|
+
"tent",
|
|
4397
|
+
"term",
|
|
4398
|
+
"test",
|
|
4399
|
+
"text",
|
|
4400
|
+
"thank",
|
|
4401
|
+
"that",
|
|
4402
|
+
"theme",
|
|
4403
|
+
"then",
|
|
4404
|
+
"theory",
|
|
4405
|
+
"there",
|
|
4406
|
+
"they",
|
|
4407
|
+
"thing",
|
|
4408
|
+
"this",
|
|
4409
|
+
"thought",
|
|
4410
|
+
"three",
|
|
4411
|
+
"thrive",
|
|
4412
|
+
"throw",
|
|
4413
|
+
"thumb",
|
|
4414
|
+
"thunder",
|
|
4415
|
+
"ticket",
|
|
4416
|
+
"tide",
|
|
4417
|
+
"tiger",
|
|
4418
|
+
"tilt",
|
|
4419
|
+
"timber",
|
|
4420
|
+
"time",
|
|
4421
|
+
"tiny",
|
|
4422
|
+
"tip",
|
|
4423
|
+
"tired",
|
|
4424
|
+
"tissue",
|
|
4425
|
+
"title",
|
|
4426
|
+
"toast",
|
|
4427
|
+
"tobacco",
|
|
4428
|
+
"today",
|
|
4429
|
+
"toddler",
|
|
4430
|
+
"toe",
|
|
4431
|
+
"together",
|
|
4432
|
+
"toilet",
|
|
4433
|
+
"token",
|
|
4434
|
+
"tomato",
|
|
4435
|
+
"tomorrow",
|
|
4436
|
+
"tone",
|
|
4437
|
+
"tongue",
|
|
4438
|
+
"tonight",
|
|
4439
|
+
"tool",
|
|
4440
|
+
"tooth",
|
|
4441
|
+
"top",
|
|
4442
|
+
"topic",
|
|
4443
|
+
"topple",
|
|
4444
|
+
"torch",
|
|
4445
|
+
"tornado",
|
|
4446
|
+
"tortoise",
|
|
4447
|
+
"toss",
|
|
4448
|
+
"total",
|
|
4449
|
+
"tourist",
|
|
4450
|
+
"toward",
|
|
4451
|
+
"tower",
|
|
4452
|
+
"town",
|
|
4453
|
+
"toy",
|
|
4454
|
+
"track",
|
|
4455
|
+
"trade",
|
|
4456
|
+
"traffic",
|
|
4457
|
+
"tragic",
|
|
4458
|
+
"train",
|
|
4459
|
+
"transfer",
|
|
4460
|
+
"trap",
|
|
4461
|
+
"trash",
|
|
4462
|
+
"travel",
|
|
4463
|
+
"tray",
|
|
4464
|
+
"treat",
|
|
4465
|
+
"tree",
|
|
4466
|
+
"trend",
|
|
4467
|
+
"trial",
|
|
4468
|
+
"tribe",
|
|
4469
|
+
"trick",
|
|
4470
|
+
"trigger",
|
|
4471
|
+
"trim",
|
|
4472
|
+
"trip",
|
|
4473
|
+
"trophy",
|
|
4474
|
+
"trouble",
|
|
4475
|
+
"truck",
|
|
4476
|
+
"true",
|
|
4477
|
+
"truly",
|
|
4478
|
+
"trumpet",
|
|
4479
|
+
"trust",
|
|
4480
|
+
"truth",
|
|
4481
|
+
"try",
|
|
4482
|
+
"tube",
|
|
4483
|
+
"tuition",
|
|
4484
|
+
"tumble",
|
|
4485
|
+
"tuna",
|
|
4486
|
+
"tunnel",
|
|
4487
|
+
"turkey",
|
|
4488
|
+
"turn",
|
|
4489
|
+
"turtle",
|
|
4490
|
+
"twelve",
|
|
4491
|
+
"twenty",
|
|
4492
|
+
"twice",
|
|
4493
|
+
"twin",
|
|
4494
|
+
"twist",
|
|
4495
|
+
"two",
|
|
4496
|
+
"type",
|
|
4497
|
+
"typical",
|
|
4498
|
+
"ugly",
|
|
4499
|
+
"umbrella",
|
|
4500
|
+
"unable",
|
|
4501
|
+
"unaware",
|
|
4502
|
+
"uncle",
|
|
4503
|
+
"uncover",
|
|
4504
|
+
"under",
|
|
4505
|
+
"undo",
|
|
4506
|
+
"unfair",
|
|
4507
|
+
"unfold",
|
|
4508
|
+
"unhappy",
|
|
4509
|
+
"uniform",
|
|
4510
|
+
"unique",
|
|
4511
|
+
"unit",
|
|
4512
|
+
"universe",
|
|
4513
|
+
"unknown",
|
|
4514
|
+
"unlock",
|
|
4515
|
+
"until",
|
|
4516
|
+
"unusual",
|
|
4517
|
+
"unveil",
|
|
4518
|
+
"update",
|
|
4519
|
+
"upgrade",
|
|
4520
|
+
"uphold",
|
|
4521
|
+
"upon",
|
|
4522
|
+
"upper",
|
|
4523
|
+
"upset",
|
|
4524
|
+
"urban",
|
|
4525
|
+
"urge",
|
|
4526
|
+
"usage",
|
|
4527
|
+
"use",
|
|
4528
|
+
"used",
|
|
4529
|
+
"useful",
|
|
4530
|
+
"useless",
|
|
4531
|
+
"usual",
|
|
4532
|
+
"utility",
|
|
4533
|
+
"vacant",
|
|
4534
|
+
"vacuum",
|
|
4535
|
+
"vague",
|
|
4536
|
+
"valid",
|
|
4537
|
+
"valley",
|
|
4538
|
+
"valve",
|
|
4539
|
+
"van",
|
|
4540
|
+
"vanish",
|
|
4541
|
+
"vapor",
|
|
4542
|
+
"various",
|
|
4543
|
+
"vast",
|
|
4544
|
+
"vault",
|
|
4545
|
+
"vehicle",
|
|
4546
|
+
"velvet",
|
|
4547
|
+
"vendor",
|
|
4548
|
+
"venture",
|
|
4549
|
+
"venue",
|
|
4550
|
+
"verb",
|
|
4551
|
+
"verify",
|
|
4552
|
+
"version",
|
|
4553
|
+
"very",
|
|
4554
|
+
"vessel",
|
|
4555
|
+
"veteran",
|
|
4556
|
+
"viable",
|
|
4557
|
+
"vibrant",
|
|
4558
|
+
"vicious",
|
|
4559
|
+
"victory",
|
|
4560
|
+
"video",
|
|
4561
|
+
"view",
|
|
4562
|
+
"village",
|
|
4563
|
+
"vintage",
|
|
4564
|
+
"violin",
|
|
4565
|
+
"virtual",
|
|
4566
|
+
"virus",
|
|
4567
|
+
"visa",
|
|
4568
|
+
"visit",
|
|
4569
|
+
"visual",
|
|
4570
|
+
"vital",
|
|
4571
|
+
"vivid",
|
|
4572
|
+
"vocal",
|
|
4573
|
+
"voice",
|
|
4574
|
+
"void",
|
|
4575
|
+
"volcano",
|
|
4576
|
+
"volume",
|
|
4577
|
+
"vote",
|
|
4578
|
+
"voyage",
|
|
4579
|
+
"wage",
|
|
4580
|
+
"wagon",
|
|
4581
|
+
"wait",
|
|
4582
|
+
"walk",
|
|
4583
|
+
"wall",
|
|
4584
|
+
"walnut",
|
|
4585
|
+
"want",
|
|
4586
|
+
"warfare",
|
|
4587
|
+
"warm",
|
|
4588
|
+
"warrior",
|
|
4589
|
+
"wash",
|
|
4590
|
+
"wasp",
|
|
4591
|
+
"waste",
|
|
4592
|
+
"water",
|
|
4593
|
+
"wave",
|
|
4594
|
+
"way",
|
|
4595
|
+
"wealth",
|
|
4596
|
+
"weapon",
|
|
4597
|
+
"wear",
|
|
4598
|
+
"weasel",
|
|
4599
|
+
"weather",
|
|
4600
|
+
"web",
|
|
4601
|
+
"wedding",
|
|
4602
|
+
"weekend",
|
|
4603
|
+
"weird",
|
|
4604
|
+
"welcome",
|
|
4605
|
+
"west",
|
|
4606
|
+
"wet",
|
|
4607
|
+
"whale",
|
|
4608
|
+
"what",
|
|
4609
|
+
"wheat",
|
|
4610
|
+
"wheel",
|
|
4611
|
+
"when",
|
|
4612
|
+
"where",
|
|
4613
|
+
"whip",
|
|
4614
|
+
"whisper",
|
|
4615
|
+
"wide",
|
|
4616
|
+
"width",
|
|
4617
|
+
"wife",
|
|
4618
|
+
"wild",
|
|
4619
|
+
"will",
|
|
4620
|
+
"win",
|
|
4621
|
+
"window",
|
|
4622
|
+
"wine",
|
|
4623
|
+
"wing",
|
|
4624
|
+
"wink",
|
|
4625
|
+
"winner",
|
|
4626
|
+
"winter",
|
|
4627
|
+
"wire",
|
|
4628
|
+
"wisdom",
|
|
4629
|
+
"wise",
|
|
4630
|
+
"wish",
|
|
4631
|
+
"witness",
|
|
4632
|
+
"wolf",
|
|
4633
|
+
"woman",
|
|
4634
|
+
"wonder",
|
|
4635
|
+
"wood",
|
|
4636
|
+
"wool",
|
|
4637
|
+
"word",
|
|
4638
|
+
"work",
|
|
4639
|
+
"world",
|
|
4640
|
+
"worry",
|
|
4641
|
+
"worth",
|
|
4642
|
+
"wrap",
|
|
4643
|
+
"wreck",
|
|
4644
|
+
"wrestle",
|
|
4645
|
+
"wrist",
|
|
4646
|
+
"write",
|
|
4647
|
+
"wrong",
|
|
4648
|
+
"yard",
|
|
4649
|
+
"year",
|
|
4650
|
+
"yellow",
|
|
4651
|
+
"you",
|
|
4652
|
+
"young",
|
|
4653
|
+
"youth",
|
|
4654
|
+
"zebra",
|
|
4655
|
+
"zero",
|
|
4656
|
+
"zone",
|
|
4657
|
+
"zoo"
|
|
4658
|
+
];
|
|
4659
|
+
|
|
4660
|
+
// src/account/account.ts
|
|
4661
|
+
var ACCOUNT_LINK_DOMAIN = new TextEncoder().encode(
|
|
4662
|
+
"calimero.mdma.account-link.v1\0"
|
|
4663
|
+
);
|
|
4664
|
+
var ENTROPY_BITS = 256;
|
|
4665
|
+
var CHECKSUM_BITS = ENTROPY_BITS / 32;
|
|
4666
|
+
var PHRASE_WORDS = (ENTROPY_BITS + CHECKSUM_BITS) / 11;
|
|
4667
|
+
async function generateAccountRoot() {
|
|
4668
|
+
const entropy = crypto.getRandomValues(new Uint8Array(ENTROPY_BITS / 8));
|
|
4669
|
+
return withPhrase(hex(entropy), await encodePhrase(entropy));
|
|
4670
|
+
}
|
|
4671
|
+
async function accountRootFromPhrase(phrase) {
|
|
4672
|
+
const words = normalisePhrase(phrase);
|
|
4673
|
+
return withPhrase(hex(await decodePhrase(words)), words.join(" "));
|
|
4674
|
+
}
|
|
4675
|
+
async function accountRootFromSecret(secret) {
|
|
4676
|
+
fromHex(secret, "secret", 32);
|
|
4677
|
+
return {
|
|
4678
|
+
secret,
|
|
4679
|
+
publicKey: hex(await derivePublicKey(secret)),
|
|
4680
|
+
accountId: await accountForRoot(secret)
|
|
4681
|
+
};
|
|
4682
|
+
}
|
|
4683
|
+
async function signAccountLink(input) {
|
|
4684
|
+
if (!input.nonce) throw new Error("nonce is required to sign an account link");
|
|
4685
|
+
const key = await importSigningKey(input.rootSecret);
|
|
4686
|
+
const signature = new Uint8Array(
|
|
4687
|
+
await crypto.subtle.sign(
|
|
4688
|
+
"Ed25519",
|
|
4689
|
+
key,
|
|
4690
|
+
concat(ACCOUNT_LINK_DOMAIN, new TextEncoder().encode(input.nonce))
|
|
4691
|
+
)
|
|
4692
|
+
);
|
|
4693
|
+
return base64(signature);
|
|
4694
|
+
}
|
|
4695
|
+
async function withPhrase(secret, phrase) {
|
|
4696
|
+
return { ...await accountRootFromSecret(secret), phrase };
|
|
4697
|
+
}
|
|
4698
|
+
function normalisePhrase(phrase) {
|
|
4699
|
+
const words = phrase.normalize("NFKD").toLowerCase().trim().split(/\s+/);
|
|
4700
|
+
const count = words[0] === "" ? 0 : words.length;
|
|
4701
|
+
if (count !== PHRASE_WORDS) {
|
|
4702
|
+
throw new Error(
|
|
4703
|
+
`recovery phrase must be ${PHRASE_WORDS} words, got ${count}`
|
|
4704
|
+
);
|
|
4705
|
+
}
|
|
4706
|
+
return words;
|
|
4707
|
+
}
|
|
4708
|
+
async function encodePhrase(entropy) {
|
|
4709
|
+
const bits = bitsOf(entropy) + await checksumBits(entropy);
|
|
4710
|
+
const words = [];
|
|
4711
|
+
for (let i = 0; i < PHRASE_WORDS; i += 1) {
|
|
4712
|
+
const index = Number.parseInt(bits.slice(i * 11, i * 11 + 11), 2);
|
|
4713
|
+
words.push(ENGLISH_WORDLIST[index]);
|
|
4714
|
+
}
|
|
4715
|
+
return words.join(" ");
|
|
4716
|
+
}
|
|
4717
|
+
async function decodePhrase(words) {
|
|
4718
|
+
let bits = "";
|
|
4719
|
+
for (const word of words) {
|
|
4720
|
+
const index = ENGLISH_WORDLIST.indexOf(word);
|
|
4721
|
+
if (index < 0) {
|
|
4722
|
+
throw new Error(`"${word}" is not a word in the recovery phrase list`);
|
|
4723
|
+
}
|
|
4724
|
+
bits += index.toString(2).padStart(11, "0");
|
|
4725
|
+
}
|
|
4726
|
+
const entropy = new Uint8Array(ENTROPY_BITS / 8);
|
|
4727
|
+
for (let i = 0; i < entropy.length; i += 1) {
|
|
4728
|
+
entropy[i] = Number.parseInt(bits.slice(i * 8, i * 8 + 8), 2);
|
|
4729
|
+
}
|
|
4730
|
+
if (bits.slice(ENTROPY_BITS) !== await checksumBits(entropy)) {
|
|
4731
|
+
throw new Error(
|
|
4732
|
+
"recovery phrase checksum failed \u2014 check for a mistyped or transposed word"
|
|
4733
|
+
);
|
|
4734
|
+
}
|
|
4735
|
+
return entropy;
|
|
4736
|
+
}
|
|
4737
|
+
async function checksumBits(entropy) {
|
|
4738
|
+
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", entropy));
|
|
4739
|
+
return bitsOf(digest).slice(0, CHECKSUM_BITS);
|
|
4740
|
+
}
|
|
4741
|
+
function bitsOf(bytes) {
|
|
4742
|
+
let bits = "";
|
|
4743
|
+
for (const byte of bytes) bits += byte.toString(2).padStart(8, "0");
|
|
4744
|
+
return bits;
|
|
4745
|
+
}
|
|
4746
|
+
function base64(bytes) {
|
|
4747
|
+
let binary = "";
|
|
4748
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
4749
|
+
return btoa(binary);
|
|
4750
|
+
}
|
|
4751
|
+
|
|
2318
4752
|
// src/cloud/cloud-client.ts
|
|
2319
4753
|
var DEFAULT_CLOUD_BASE_URL = "https://cloud.calimero.network";
|
|
2320
4754
|
var REFRESH_HEADER = "x-mdma-session-refresh";
|
|
@@ -2432,6 +4866,65 @@ var CloudClient = class {
|
|
|
2432
4866
|
const relays = await this.getNamespaceRelays(namespaceId);
|
|
2433
4867
|
return relays.find((r) => r.authorshipReady && r.relayUrl !== null && r.executorAccount !== null) ?? null;
|
|
2434
4868
|
}
|
|
4869
|
+
/**
|
|
4870
|
+
* Where to reach a namespace without owning it: one read, both verbs.
|
|
4871
|
+
*
|
|
4872
|
+
* **Anonymous.** A joiner is by construction not the namespace owner and holds
|
|
4873
|
+
* no cloud session — needing one is exactly what this path exists to avoid.
|
|
4874
|
+
* Discovery is not authorization: merod refuses an `/admit` call unless the
|
|
4875
|
+
* relaying node's account is on the invitation's signed `admitters` list, and
|
|
4876
|
+
* refuses an intent unless the warrant is genuinely the member's, so naming a
|
|
4877
|
+
* node grants the caller nothing it did not already have.
|
|
4878
|
+
*
|
|
4879
|
+
* A keyholder resolves a namespace to a node ONCE and then admits, reads and
|
|
4880
|
+
* posts intents against that same node, which is why admission and writability
|
|
4881
|
+
* are answered together rather than across two endpoints — the per-context
|
|
4882
|
+
* read needs a context id a joiner does not yet have.
|
|
4883
|
+
*
|
|
4884
|
+
* An empty `nodes` list is a state, not an error: a namespace with no fleet
|
|
4885
|
+
* assignment has no cloud node, and the joiner must use one of the
|
|
4886
|
+
* invitation's other admitters — another admin's node, or a self-hosted peer.
|
|
4887
|
+
*/
|
|
4888
|
+
async getNamespaceRouting(namespaceId) {
|
|
4889
|
+
const body = await this.request("GET", `/api/cloud/namespaces/${encodeURIComponent(namespaceId)}/admitters`, {
|
|
4890
|
+
anonymous: true
|
|
4891
|
+
});
|
|
4892
|
+
return {
|
|
4893
|
+
namespaceId: String(body.namespace_id ?? namespaceId),
|
|
4894
|
+
nodes: (body.admitters ?? []).map((row) => ({
|
|
4895
|
+
peerId: String(row.peer_id ?? ""),
|
|
4896
|
+
account: row.account ?? null,
|
|
4897
|
+
relayUrl: row.relay_url ?? null,
|
|
4898
|
+
admitUrl: row.admit_url ?? null,
|
|
4899
|
+
status: String(row.status ?? ""),
|
|
4900
|
+
fresh: row.fresh === true,
|
|
4901
|
+
canAdmit: row.can_admit === true,
|
|
4902
|
+
authorshipReady: row.authorship_ready === true,
|
|
4903
|
+
canExecute: row.can_execute === true
|
|
4904
|
+
})),
|
|
4905
|
+
servable: body.servable === true,
|
|
4906
|
+
writable: body.writable === true
|
|
4907
|
+
};
|
|
4908
|
+
}
|
|
4909
|
+
/**
|
|
4910
|
+
* The node to send a signed join to, chosen from those an invitation names.
|
|
4911
|
+
*
|
|
4912
|
+
* Pass the invitation's `admitters` and the intersection is done here, because
|
|
4913
|
+
* skipping it is the failure this method exists to prevent: the cloud lists
|
|
4914
|
+
* every node assigned to the namespace, while `admitters` is a snapshot signed
|
|
4915
|
+
* when the invitation was minted. A node added afterwards looks perfect in
|
|
4916
|
+
* every field here and answers 403.
|
|
4917
|
+
*
|
|
4918
|
+
* Omit `admitters` only for an invitation that names none — an empty list on
|
|
4919
|
+
* the wire authorises any node to admit.
|
|
4920
|
+
*/
|
|
4921
|
+
async findAdmitter(namespaceId, admitters) {
|
|
4922
|
+
const { nodes } = await this.getNamespaceRouting(namespaceId);
|
|
4923
|
+
const allowed = admitters && admitters.length > 0 ? new Set(admitters.map((a) => a.toLowerCase())) : null;
|
|
4924
|
+
return nodes.find(
|
|
4925
|
+
(n) => n.canAdmit && (allowed === null || n.account !== null && allowed.has(n.account.toLowerCase()))
|
|
4926
|
+
) ?? null;
|
|
4927
|
+
}
|
|
2435
4928
|
/**
|
|
2436
4929
|
* Every attested machine currently serving something this account owns.
|
|
2437
4930
|
*
|
|
@@ -2558,6 +5051,93 @@ var CloudClient = class {
|
|
|
2558
5051
|
window.open(`${this.baseUrl}/disable-ha?${params.toString()}`);
|
|
2559
5052
|
}
|
|
2560
5053
|
/** Record a freshly-issued session and tell the app to persist it. */
|
|
5054
|
+
/**
|
|
5055
|
+
* Link a Calimero account to this cloud login, proving possession of its root.
|
|
5056
|
+
*
|
|
5057
|
+
* Two hops, folded into one call because they are useless apart: fetch a
|
|
5058
|
+
* single-use challenge, then sign it with the account root and post the proof.
|
|
5059
|
+
* The secret never leaves this process — only a signature over a nonce the
|
|
5060
|
+
* cloud minted does.
|
|
5061
|
+
*
|
|
5062
|
+
* This is the binding the cloud bills against. A relay does not need it to run
|
|
5063
|
+
* an intent; the cloud needs it to know whose plan a hosted node is spending,
|
|
5064
|
+
* and to sign that account back in later.
|
|
5065
|
+
*
|
|
5066
|
+
* @param rootSecret the account root's signing secret, 64 hex — from
|
|
5067
|
+
* {@link generateAccountRoot}, from a restored recovery phrase, or from a
|
|
5068
|
+
* desktop app or hardware key that already holds one.
|
|
5069
|
+
*
|
|
5070
|
+
* Idempotent for the same login. An account already linked to a *different*
|
|
5071
|
+
* cloud login is a `409`; a replayed or expired challenge is a `403`; and
|
|
5072
|
+
* exceeding the plan's account limit is a `402`.
|
|
5073
|
+
*/
|
|
5074
|
+
async linkAccount(rootSecret) {
|
|
5075
|
+
const root = await accountRootFromSecret(rootSecret);
|
|
5076
|
+
const { nonce } = await this.getAccountLinkChallenge();
|
|
5077
|
+
return this.submitAccountLink({
|
|
5078
|
+
accountId: root.accountId,
|
|
5079
|
+
rootPublicKey: root.publicKey,
|
|
5080
|
+
nonce,
|
|
5081
|
+
signature: await signAccountLink({ rootSecret, nonce })
|
|
5082
|
+
});
|
|
5083
|
+
}
|
|
5084
|
+
/**
|
|
5085
|
+
* Mint a single-use challenge for an account root to sign.
|
|
5086
|
+
*
|
|
5087
|
+
* The split half of {@link linkAccount}, for the case that call cannot serve:
|
|
5088
|
+
* a root held by a desktop app, a hardware key or an air-gapped machine, which
|
|
5089
|
+
* signs without the secret ever reaching this process. Fetch the challenge
|
|
5090
|
+
* here, have the holder sign it, then hand the proof to
|
|
5091
|
+
* {@link submitAccountLink}.
|
|
5092
|
+
*
|
|
5093
|
+
* Bound to the signed-in login and short-lived, so it is not a standing
|
|
5094
|
+
* capability if it leaks — but it IS single-use, so a challenge fetched and
|
|
5095
|
+
* abandoned is spent.
|
|
5096
|
+
*/
|
|
5097
|
+
async getAccountLinkChallenge() {
|
|
5098
|
+
const body = await this.request("GET", "/api/cloud/me/accounts/challenge");
|
|
5099
|
+
return { nonce: body.nonce, expiresAtMs: body.expires_at_ms ?? null };
|
|
5100
|
+
}
|
|
5101
|
+
/**
|
|
5102
|
+
* Post a proof assembled elsewhere. The other half of
|
|
5103
|
+
* {@link getAccountLinkChallenge}.
|
|
5104
|
+
*
|
|
5105
|
+
* `accountId` must be the account `rootPublicKey` names — the cloud refuses a
|
|
5106
|
+
* valid signature by a key that names a different account, or a caller could
|
|
5107
|
+
* prove one root and link somebody else's account. Derive both from the same
|
|
5108
|
+
* key rather than letting a user type either.
|
|
5109
|
+
*/
|
|
5110
|
+
async submitAccountLink(proof) {
|
|
5111
|
+
const body = await this.request(
|
|
5112
|
+
"POST",
|
|
5113
|
+
"/api/cloud/me/accounts",
|
|
5114
|
+
{
|
|
5115
|
+
body: {
|
|
5116
|
+
account_id: proof.accountId,
|
|
5117
|
+
root_public_key: proof.rootPublicKey,
|
|
5118
|
+
nonce: proof.nonce,
|
|
5119
|
+
signature: proof.signature
|
|
5120
|
+
}
|
|
5121
|
+
}
|
|
5122
|
+
);
|
|
5123
|
+
return {
|
|
5124
|
+
accountId: String(body.account_id ?? proof.accountId),
|
|
5125
|
+
linkedAt: body.linked_at ?? null,
|
|
5126
|
+
alreadyLinked: body.already_linked === true
|
|
5127
|
+
};
|
|
5128
|
+
}
|
|
5129
|
+
/** The accounts linked to this login, and how many the plan allows. */
|
|
5130
|
+
async getMyAccounts() {
|
|
5131
|
+
const body = await this.request("GET", "/api/cloud/me/accounts");
|
|
5132
|
+
return {
|
|
5133
|
+
accounts: (body.accounts ?? []).map((row) => ({
|
|
5134
|
+
accountId: String(row.account_id ?? ""),
|
|
5135
|
+
linkedAt: row.linked_at ?? null,
|
|
5136
|
+
hasRecoveryEnvelope: row.has_recovery_envelope === true
|
|
5137
|
+
})),
|
|
5138
|
+
limit: body.limit ?? null
|
|
5139
|
+
};
|
|
5140
|
+
}
|
|
2561
5141
|
adoptSession(body) {
|
|
2562
5142
|
this.session = {
|
|
2563
5143
|
sessionToken: body.session_token,
|
|
@@ -3037,105 +5617,6 @@ var LocalStorageTokenStore = class {
|
|
|
3037
5617
|
}
|
|
3038
5618
|
};
|
|
3039
5619
|
|
|
3040
|
-
// src/crypto/internal.ts
|
|
3041
|
-
var PKCS8_ED25519_PREFIX = new Uint8Array([
|
|
3042
|
-
48,
|
|
3043
|
-
46,
|
|
3044
|
-
2,
|
|
3045
|
-
1,
|
|
3046
|
-
0,
|
|
3047
|
-
48,
|
|
3048
|
-
5,
|
|
3049
|
-
6,
|
|
3050
|
-
3,
|
|
3051
|
-
43,
|
|
3052
|
-
101,
|
|
3053
|
-
112,
|
|
3054
|
-
4,
|
|
3055
|
-
34,
|
|
3056
|
-
4,
|
|
3057
|
-
32
|
|
3058
|
-
]);
|
|
3059
|
-
function u32le(value) {
|
|
3060
|
-
const out = new Uint8Array(4);
|
|
3061
|
-
new DataView(out.buffer).setUint32(0, value, true);
|
|
3062
|
-
return out;
|
|
3063
|
-
}
|
|
3064
|
-
function hex(bytes) {
|
|
3065
|
-
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
3066
|
-
}
|
|
3067
|
-
function fromHex(value, label, expectedBytes) {
|
|
3068
|
-
const clean = value.trim();
|
|
3069
|
-
if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {
|
|
3070
|
-
throw new Error(
|
|
3071
|
-
`${label} must be ${expectedBytes * 2} hex characters, got ${clean.length}`
|
|
3072
|
-
);
|
|
3073
|
-
}
|
|
3074
|
-
const bytes = new Uint8Array(expectedBytes);
|
|
3075
|
-
for (let i = 0; i < expectedBytes; i += 1) {
|
|
3076
|
-
bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
3077
|
-
}
|
|
3078
|
-
return bytes;
|
|
3079
|
-
}
|
|
3080
|
-
function u64le(value) {
|
|
3081
|
-
const out = new Uint8Array(8);
|
|
3082
|
-
new DataView(out.buffer).setBigUint64(0, BigInt(value), true);
|
|
3083
|
-
return out;
|
|
3084
|
-
}
|
|
3085
|
-
function concat(...parts) {
|
|
3086
|
-
const out = new Uint8Array(parts.reduce((total, p) => total + p.length, 0));
|
|
3087
|
-
let offset = 0;
|
|
3088
|
-
for (const part of parts) {
|
|
3089
|
-
out.set(part, offset);
|
|
3090
|
-
offset += part.length;
|
|
3091
|
-
}
|
|
3092
|
-
return out;
|
|
3093
|
-
}
|
|
3094
|
-
async function domainHash(domain, parts) {
|
|
3095
|
-
const chunks = [u64le(domain.length), domain];
|
|
3096
|
-
for (const part of parts) {
|
|
3097
|
-
chunks.push(u64le(part.length), part);
|
|
3098
|
-
}
|
|
3099
|
-
return new Uint8Array(
|
|
3100
|
-
await crypto.subtle.digest("SHA-256", concat(...chunks))
|
|
3101
|
-
);
|
|
3102
|
-
}
|
|
3103
|
-
async function importSigningKey(secretHex) {
|
|
3104
|
-
const seed = fromHex(secretHex, "deviceSecret", 32);
|
|
3105
|
-
const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
|
|
3106
|
-
try {
|
|
3107
|
-
return await crypto.subtle.importKey(
|
|
3108
|
-
"pkcs8",
|
|
3109
|
-
pkcs8,
|
|
3110
|
-
{ name: "Ed25519" },
|
|
3111
|
-
false,
|
|
3112
|
-
["sign"]
|
|
3113
|
-
);
|
|
3114
|
-
} catch (cause) {
|
|
3115
|
-
const detail = cause instanceof Error ? `: ${cause.message}` : "";
|
|
3116
|
-
throw new Error(
|
|
3117
|
-
"this runtime has no WebCrypto Ed25519, so a warrant cannot be signed here. Node 18.4+, Safari 17+, Firefox 129+ and Chrome 137+ have it; otherwise mint the warrant with `merod account warrant`" + detail
|
|
3118
|
-
);
|
|
3119
|
-
}
|
|
3120
|
-
}
|
|
3121
|
-
async function derivePublicKey(secretHex) {
|
|
3122
|
-
const seed = fromHex(secretHex, "deviceSecret", 32);
|
|
3123
|
-
const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
|
|
3124
|
-
const key = await crypto.subtle.importKey(
|
|
3125
|
-
"pkcs8",
|
|
3126
|
-
pkcs8,
|
|
3127
|
-
{ name: "Ed25519" },
|
|
3128
|
-
true,
|
|
3129
|
-
["sign"]
|
|
3130
|
-
);
|
|
3131
|
-
const jwk = await crypto.subtle.exportKey("jwk", key);
|
|
3132
|
-
const raw = jwk.x;
|
|
3133
|
-
return Uint8Array.from(
|
|
3134
|
-
atob(raw.replace(/-/g, "+").replace(/_/g, "/")),
|
|
3135
|
-
(c) => c.charCodeAt(0)
|
|
3136
|
-
);
|
|
3137
|
-
}
|
|
3138
|
-
|
|
3139
5620
|
// src/warrant/warrant.ts
|
|
3140
5621
|
var SIGN_DOMAIN = new TextEncoder().encode("calimero.warrant.v2");
|
|
3141
5622
|
var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
|
|
@@ -3436,7 +5917,7 @@ function explainNoRelay(namespace, relays) {
|
|
|
3436
5917
|
}
|
|
3437
5918
|
const waitingOnGrant = relays.filter((r) => !r.authorshipReady);
|
|
3438
5919
|
if (waitingOnGrant.length === relays.length) {
|
|
3439
|
-
return `every relay on namespace ${namespace.namespaceId} is waiting for the authorship grant: an admin of the namespace must grant CAN_AUTHOR_ON_BEHALF to ${waitingOnGrant.map((r) => r.executorAccount ?? r.peerId).join(", ") || "the relay account"}`;
|
|
5920
|
+
return `every relay on namespace ${namespace.namespaceId} is waiting for the authorship grant: an admin of the namespace must grant CAN_AUTHOR_ON_BEHALF to ${waitingOnGrant.map((r) => r.executorAccount ?? r.peerId).join(", ") || "the relay account"} \u2014 with AdminClient.grantAuthorship(namespaceId, account) for these relays, and AdminClient.openToDelegatedExecution(namespaceId) so relays assigned later need no further op`;
|
|
3440
5921
|
}
|
|
3441
5922
|
return `namespace ${namespace.namespaceId} has ${relays.length} relay(s), but none reported both a URL and an executor account yet \u2014 retry shortly`;
|
|
3442
5923
|
}
|
|
@@ -3449,83 +5930,6 @@ async function defaultNonceSource(deviceSecret) {
|
|
|
3449
5930
|
}
|
|
3450
5931
|
}
|
|
3451
5932
|
|
|
3452
|
-
// src/device-cert/device-cert.ts
|
|
3453
|
-
var CERT_DOMAIN = new TextEncoder().encode("calimero.device.cert.v1");
|
|
3454
|
-
var ACCOUNT_ID_DOMAIN = new TextEncoder().encode("calimero.account.genesis.v1");
|
|
3455
|
-
var DEVICE_ID_DOMAIN = new TextEncoder().encode("calimero.device.id.v1");
|
|
3456
|
-
var ACCOUNT_GENESIS_VERSION = 2;
|
|
3457
|
-
async function mintDeviceId(account, nonce) {
|
|
3458
|
-
if (nonce.length !== 16) {
|
|
3459
|
-
throw new Error(`nonce must be 16 bytes, got ${nonce.length}`);
|
|
3460
|
-
}
|
|
3461
|
-
const accountBytes = fromHex(account, "account", 32);
|
|
3462
|
-
return hex(await domainHash(DEVICE_ID_DOMAIN, [accountBytes, nonce]));
|
|
3463
|
-
}
|
|
3464
|
-
async function deviceCertPayload(input) {
|
|
3465
|
-
return domainHash(CERT_DOMAIN, [
|
|
3466
|
-
fromHex(input.account, "account", 32),
|
|
3467
|
-
fromHex(input.device, "device", 32),
|
|
3468
|
-
fromHex(input.signPublicKey, "signPublicKey", 32),
|
|
3469
|
-
fromHex(input.kemPublicKey, "kemPublicKey", 32),
|
|
3470
|
-
u32le(input.keyEpoch),
|
|
3471
|
-
u32le(input.deviceEpoch)
|
|
3472
|
-
]);
|
|
3473
|
-
}
|
|
3474
|
-
function accountProofBytes(input) {
|
|
3475
|
-
return concat(
|
|
3476
|
-
new Uint8Array([ACCOUNT_GENESIS_VERSION]),
|
|
3477
|
-
input.rootPublicKey,
|
|
3478
|
-
u32le(0),
|
|
3479
|
-
fromHex(input.account, "account", 32),
|
|
3480
|
-
fromHex(input.device, "device", 32),
|
|
3481
|
-
fromHex(input.signPublicKey, "signPublicKey", 32),
|
|
3482
|
-
fromHex(input.kemPublicKey, "kemPublicKey", 32),
|
|
3483
|
-
u32le(input.keyEpoch),
|
|
3484
|
-
u32le(input.deviceEpoch),
|
|
3485
|
-
input.signature
|
|
3486
|
-
);
|
|
3487
|
-
}
|
|
3488
|
-
async function signDeviceCert(input) {
|
|
3489
|
-
const rootPublicKey = await derivePublicKey(input.rootSecret);
|
|
3490
|
-
const account = hex(
|
|
3491
|
-
await domainHash(ACCOUNT_ID_DOMAIN, [
|
|
3492
|
-
concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey)
|
|
3493
|
-
])
|
|
3494
|
-
);
|
|
3495
|
-
const keyEpoch = 0;
|
|
3496
|
-
const payload = await deviceCertPayload({
|
|
3497
|
-
account,
|
|
3498
|
-
device: input.device,
|
|
3499
|
-
signPublicKey: input.signPublicKey,
|
|
3500
|
-
kemPublicKey: input.kemPublicKey,
|
|
3501
|
-
keyEpoch,
|
|
3502
|
-
deviceEpoch: input.deviceEpoch
|
|
3503
|
-
});
|
|
3504
|
-
const key = await importSigningKey(input.rootSecret);
|
|
3505
|
-
const signature = new Uint8Array(
|
|
3506
|
-
await crypto.subtle.sign("Ed25519", key, payload)
|
|
3507
|
-
);
|
|
3508
|
-
const credential = accountProofBytes({
|
|
3509
|
-
rootPublicKey,
|
|
3510
|
-
account,
|
|
3511
|
-
device: input.device,
|
|
3512
|
-
signPublicKey: input.signPublicKey,
|
|
3513
|
-
kemPublicKey: input.kemPublicKey,
|
|
3514
|
-
keyEpoch,
|
|
3515
|
-
deviceEpoch: input.deviceEpoch,
|
|
3516
|
-
signature
|
|
3517
|
-
});
|
|
3518
|
-
return hex(credential);
|
|
3519
|
-
}
|
|
3520
|
-
async function accountForRoot(rootSecret) {
|
|
3521
|
-
const rootPublicKey = await derivePublicKey(rootSecret);
|
|
3522
|
-
return hex(
|
|
3523
|
-
await domainHash(ACCOUNT_ID_DOMAIN, [
|
|
3524
|
-
concat(new Uint8Array([ACCOUNT_GENESIS_VERSION]), rootPublicKey)
|
|
3525
|
-
])
|
|
3526
|
-
);
|
|
3527
|
-
}
|
|
3528
|
-
|
|
3529
5933
|
// src/namespace-op/namespace-op.ts
|
|
3530
5934
|
var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 8;
|
|
3531
5935
|
var NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode("calimero.namespace.v1");
|
|
@@ -3800,41 +6204,6 @@ async function login(config) {
|
|
|
3800
6204
|
};
|
|
3801
6205
|
}
|
|
3802
6206
|
|
|
3803
|
-
// src/capabilities.ts
|
|
3804
|
-
var CAPABILITIES = {
|
|
3805
|
-
CAN_CREATE_CONTEXT: 1 << 0,
|
|
3806
|
-
CAN_INVITE_MEMBERS: 1 << 1,
|
|
3807
|
-
CAN_JOIN_OPEN_SUBGROUPS: 1 << 2,
|
|
3808
|
-
MANAGE_MEMBERS: 1 << 3,
|
|
3809
|
-
MANAGE_APPLICATION: 1 << 4,
|
|
3810
|
-
CAN_CREATE_SUBGROUP: 1 << 5,
|
|
3811
|
-
CAN_DELETE_SUBGROUP: 1 << 6,
|
|
3812
|
-
CAN_MANAGE_VISIBILITY: 1 << 7,
|
|
3813
|
-
CAN_MANAGE_METADATA: 1 << 8,
|
|
3814
|
-
/**
|
|
3815
|
-
* Publish writes attributed to ANOTHER member, under a warrant that member
|
|
3816
|
-
* signed — the grant delegated execution runs on.
|
|
3817
|
-
*
|
|
3818
|
-
* Implied by nothing: not by membership, not by admin, and not propagated by
|
|
3819
|
-
* the subgroup-admit cascade. So every group is authorship-closed until an
|
|
3820
|
-
* admin sets this bit, and a relay without it is refused at
|
|
3821
|
-
* `performIntent` before anything executes. That is why it is worth naming
|
|
3822
|
-
* here rather than leaving callers to write `1 << 9`: a client granting it
|
|
3823
|
-
* has to be able to say what it is granting.
|
|
3824
|
-
*/
|
|
3825
|
-
CAN_AUTHOR_ON_BEHALF: 1 << 9
|
|
3826
|
-
};
|
|
3827
|
-
function hasCap(mask, cap) {
|
|
3828
|
-
const capU32 = cap >>> 0;
|
|
3829
|
-
return (mask & capU32) >>> 0 === capU32;
|
|
3830
|
-
}
|
|
3831
|
-
function withCap(mask, cap) {
|
|
3832
|
-
return (mask | cap) >>> 0;
|
|
3833
|
-
}
|
|
3834
|
-
function withoutCap(mask, cap) {
|
|
3835
|
-
return (mask & ~cap) >>> 0;
|
|
3836
|
-
}
|
|
3837
|
-
|
|
3838
6207
|
// src/nodeDiscovery.ts
|
|
3839
6208
|
var DEFAULT_LOCAL_NODE_PORTS = [2428, 2429, 2528, 2529];
|
|
3840
6209
|
var LOCAL_HOST = "localhost";
|
|
@@ -3908,6 +6277,8 @@ export {
|
|
|
3908
6277
|
WebHttpClient,
|
|
3909
6278
|
WsClient,
|
|
3910
6279
|
accountForRoot,
|
|
6280
|
+
accountRootFromPhrase,
|
|
6281
|
+
accountRootFromSecret,
|
|
3911
6282
|
buildAuthLoginUrl,
|
|
3912
6283
|
combineSignals,
|
|
3913
6284
|
compareSemver,
|
|
@@ -3932,6 +6303,7 @@ export {
|
|
|
3932
6303
|
deviceCertPayload,
|
|
3933
6304
|
discoverLocalNodes,
|
|
3934
6305
|
encodeSignedInvitation,
|
|
6306
|
+
generateAccountRoot,
|
|
3935
6307
|
generateSessionKey,
|
|
3936
6308
|
hasCap,
|
|
3937
6309
|
intentHash,
|
|
@@ -3942,6 +6314,7 @@ export {
|
|
|
3942
6314
|
nodeEndpoint,
|
|
3943
6315
|
parseAuthCallback,
|
|
3944
6316
|
probeNodeHealth,
|
|
6317
|
+
signAccountLink,
|
|
3945
6318
|
signDeviceCert,
|
|
3946
6319
|
signLoginStatement,
|
|
3947
6320
|
signMemberJoinOp,
|