@tacet-ink/journal-core 0.1.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.
@@ -0,0 +1,264 @@
1
+ /**
2
+ * wordlist.ts — BIP39 英文詞表(2048 詞,標準常數;非任何套件的碼)。
3
+ * 源:BIP39 官方 english wordlist(經 @scure/bip39 v2.4.0 wordlists/english.js 校對)。
4
+ * MIT (c) 2022 Patricio Palladino, Paul Miller(@scure/bip39)。
5
+ * 契約:全小寫 a-z、恰 2048 詞、索引即 11-bit 編碼值;只供 kit 轉寫層使用。
6
+ */
7
+ export const wordlist: readonly string[] = Object.freeze([
8
+ 'abandon', 'ability', 'able', 'about', 'above', 'absent', 'absorb', 'abstract',
9
+ 'absurd', 'abuse', 'access', 'accident', 'account', 'accuse', 'achieve', 'acid',
10
+ 'acoustic', 'acquire', 'across', 'act', 'action', 'actor', 'actress', 'actual',
11
+ 'adapt', 'add', 'addict', 'address', 'adjust', 'admit', 'adult', 'advance',
12
+ 'advice', 'aerobic', 'affair', 'afford', 'afraid', 'again', 'age', 'agent',
13
+ 'agree', 'ahead', 'aim', 'air', 'airport', 'aisle', 'alarm', 'album',
14
+ 'alcohol', 'alert', 'alien', 'all', 'alley', 'allow', 'almost', 'alone',
15
+ 'alpha', 'already', 'also', 'alter', 'always', 'amateur', 'amazing', 'among',
16
+ 'amount', 'amused', 'analyst', 'anchor', 'ancient', 'anger', 'angle', 'angry',
17
+ 'animal', 'ankle', 'announce', 'annual', 'another', 'answer', 'antenna', 'antique',
18
+ 'anxiety', 'any', 'apart', 'apology', 'appear', 'apple', 'approve', 'april',
19
+ 'arch', 'arctic', 'area', 'arena', 'argue', 'arm', 'armed', 'armor',
20
+ 'army', 'around', 'arrange', 'arrest', 'arrive', 'arrow', 'art', 'artefact',
21
+ 'artist', 'artwork', 'ask', 'aspect', 'assault', 'asset', 'assist', 'assume',
22
+ 'asthma', 'athlete', 'atom', 'attack', 'attend', 'attitude', 'attract', 'auction',
23
+ 'audit', 'august', 'aunt', 'author', 'auto', 'autumn', 'average', 'avocado',
24
+ 'avoid', 'awake', 'aware', 'away', 'awesome', 'awful', 'awkward', 'axis',
25
+ 'baby', 'bachelor', 'bacon', 'badge', 'bag', 'balance', 'balcony', 'ball',
26
+ 'bamboo', 'banana', 'banner', 'bar', 'barely', 'bargain', 'barrel', 'base',
27
+ 'basic', 'basket', 'battle', 'beach', 'bean', 'beauty', 'because', 'become',
28
+ 'beef', 'before', 'begin', 'behave', 'behind', 'believe', 'below', 'belt',
29
+ 'bench', 'benefit', 'best', 'betray', 'better', 'between', 'beyond', 'bicycle',
30
+ 'bid', 'bike', 'bind', 'biology', 'bird', 'birth', 'bitter', 'black',
31
+ 'blade', 'blame', 'blanket', 'blast', 'bleak', 'bless', 'blind', 'blood',
32
+ 'blossom', 'blouse', 'blue', 'blur', 'blush', 'board', 'boat', 'body',
33
+ 'boil', 'bomb', 'bone', 'bonus', 'book', 'boost', 'border', 'boring',
34
+ 'borrow', 'boss', 'bottom', 'bounce', 'box', 'boy', 'bracket', 'brain',
35
+ 'brand', 'brass', 'brave', 'bread', 'breeze', 'brick', 'bridge', 'brief',
36
+ 'bright', 'bring', 'brisk', 'broccoli', 'broken', 'bronze', 'broom', 'brother',
37
+ 'brown', 'brush', 'bubble', 'buddy', 'budget', 'buffalo', 'build', 'bulb',
38
+ 'bulk', 'bullet', 'bundle', 'bunker', 'burden', 'burger', 'burst', 'bus',
39
+ 'business', 'busy', 'butter', 'buyer', 'buzz', 'cabbage', 'cabin', 'cable',
40
+ 'cactus', 'cage', 'cake', 'call', 'calm', 'camera', 'camp', 'can',
41
+ 'canal', 'cancel', 'candy', 'cannon', 'canoe', 'canvas', 'canyon', 'capable',
42
+ 'capital', 'captain', 'car', 'carbon', 'card', 'cargo', 'carpet', 'carry',
43
+ 'cart', 'case', 'cash', 'casino', 'castle', 'casual', 'cat', 'catalog',
44
+ 'catch', 'category', 'cattle', 'caught', 'cause', 'caution', 'cave', 'ceiling',
45
+ 'celery', 'cement', 'census', 'century', 'cereal', 'certain', 'chair', 'chalk',
46
+ 'champion', 'change', 'chaos', 'chapter', 'charge', 'chase', 'chat', 'cheap',
47
+ 'check', 'cheese', 'chef', 'cherry', 'chest', 'chicken', 'chief', 'child',
48
+ 'chimney', 'choice', 'choose', 'chronic', 'chuckle', 'chunk', 'churn', 'cigar',
49
+ 'cinnamon', 'circle', 'citizen', 'city', 'civil', 'claim', 'clap', 'clarify',
50
+ 'claw', 'clay', 'clean', 'clerk', 'clever', 'click', 'client', 'cliff',
51
+ 'climb', 'clinic', 'clip', 'clock', 'clog', 'close', 'cloth', 'cloud',
52
+ 'clown', 'club', 'clump', 'cluster', 'clutch', 'coach', 'coast', 'coconut',
53
+ 'code', 'coffee', 'coil', 'coin', 'collect', 'color', 'column', 'combine',
54
+ 'come', 'comfort', 'comic', 'common', 'company', 'concert', 'conduct', 'confirm',
55
+ 'congress', 'connect', 'consider', 'control', 'convince', 'cook', 'cool', 'copper',
56
+ 'copy', 'coral', 'core', 'corn', 'correct', 'cost', 'cotton', 'couch',
57
+ 'country', 'couple', 'course', 'cousin', 'cover', 'coyote', 'crack', 'cradle',
58
+ 'craft', 'cram', 'crane', 'crash', 'crater', 'crawl', 'crazy', 'cream',
59
+ 'credit', 'creek', 'crew', 'cricket', 'crime', 'crisp', 'critic', 'crop',
60
+ 'cross', 'crouch', 'crowd', 'crucial', 'cruel', 'cruise', 'crumble', 'crunch',
61
+ 'crush', 'cry', 'crystal', 'cube', 'culture', 'cup', 'cupboard', 'curious',
62
+ 'current', 'curtain', 'curve', 'cushion', 'custom', 'cute', 'cycle', 'dad',
63
+ 'damage', 'damp', 'dance', 'danger', 'daring', 'dash', 'daughter', 'dawn',
64
+ 'day', 'deal', 'debate', 'debris', 'decade', 'december', 'decide', 'decline',
65
+ 'decorate', 'decrease', 'deer', 'defense', 'define', 'defy', 'degree', 'delay',
66
+ 'deliver', 'demand', 'demise', 'denial', 'dentist', 'deny', 'depart', 'depend',
67
+ 'deposit', 'depth', 'deputy', 'derive', 'describe', 'desert', 'design', 'desk',
68
+ 'despair', 'destroy', 'detail', 'detect', 'develop', 'device', 'devote', 'diagram',
69
+ 'dial', 'diamond', 'diary', 'dice', 'diesel', 'diet', 'differ', 'digital',
70
+ 'dignity', 'dilemma', 'dinner', 'dinosaur', 'direct', 'dirt', 'disagree', 'discover',
71
+ 'disease', 'dish', 'dismiss', 'disorder', 'display', 'distance', 'divert', 'divide',
72
+ 'divorce', 'dizzy', 'doctor', 'document', 'dog', 'doll', 'dolphin', 'domain',
73
+ 'donate', 'donkey', 'donor', 'door', 'dose', 'double', 'dove', 'draft',
74
+ 'dragon', 'drama', 'drastic', 'draw', 'dream', 'dress', 'drift', 'drill',
75
+ 'drink', 'drip', 'drive', 'drop', 'drum', 'dry', 'duck', 'dumb',
76
+ 'dune', 'during', 'dust', 'dutch', 'duty', 'dwarf', 'dynamic', 'eager',
77
+ 'eagle', 'early', 'earn', 'earth', 'easily', 'east', 'easy', 'echo',
78
+ 'ecology', 'economy', 'edge', 'edit', 'educate', 'effort', 'egg', 'eight',
79
+ 'either', 'elbow', 'elder', 'electric', 'elegant', 'element', 'elephant', 'elevator',
80
+ 'elite', 'else', 'embark', 'embody', 'embrace', 'emerge', 'emotion', 'employ',
81
+ 'empower', 'empty', 'enable', 'enact', 'end', 'endless', 'endorse', 'enemy',
82
+ 'energy', 'enforce', 'engage', 'engine', 'enhance', 'enjoy', 'enlist', 'enough',
83
+ 'enrich', 'enroll', 'ensure', 'enter', 'entire', 'entry', 'envelope', 'episode',
84
+ 'equal', 'equip', 'era', 'erase', 'erode', 'erosion', 'error', 'erupt',
85
+ 'escape', 'essay', 'essence', 'estate', 'eternal', 'ethics', 'evidence', 'evil',
86
+ 'evoke', 'evolve', 'exact', 'example', 'excess', 'exchange', 'excite', 'exclude',
87
+ 'excuse', 'execute', 'exercise', 'exhaust', 'exhibit', 'exile', 'exist', 'exit',
88
+ 'exotic', 'expand', 'expect', 'expire', 'explain', 'expose', 'express', 'extend',
89
+ 'extra', 'eye', 'eyebrow', 'fabric', 'face', 'faculty', 'fade', 'faint',
90
+ 'faith', 'fall', 'false', 'fame', 'family', 'famous', 'fan', 'fancy',
91
+ 'fantasy', 'farm', 'fashion', 'fat', 'fatal', 'father', 'fatigue', 'fault',
92
+ 'favorite', 'feature', 'february', 'federal', 'fee', 'feed', 'feel', 'female',
93
+ 'fence', 'festival', 'fetch', 'fever', 'few', 'fiber', 'fiction', 'field',
94
+ 'figure', 'file', 'film', 'filter', 'final', 'find', 'fine', 'finger',
95
+ 'finish', 'fire', 'firm', 'first', 'fiscal', 'fish', 'fit', 'fitness',
96
+ 'fix', 'flag', 'flame', 'flash', 'flat', 'flavor', 'flee', 'flight',
97
+ 'flip', 'float', 'flock', 'floor', 'flower', 'fluid', 'flush', 'fly',
98
+ 'foam', 'focus', 'fog', 'foil', 'fold', 'follow', 'food', 'foot',
99
+ 'force', 'forest', 'forget', 'fork', 'fortune', 'forum', 'forward', 'fossil',
100
+ 'foster', 'found', 'fox', 'fragile', 'frame', 'frequent', 'fresh', 'friend',
101
+ 'fringe', 'frog', 'front', 'frost', 'frown', 'frozen', 'fruit', 'fuel',
102
+ 'fun', 'funny', 'furnace', 'fury', 'future', 'gadget', 'gain', 'galaxy',
103
+ 'gallery', 'game', 'gap', 'garage', 'garbage', 'garden', 'garlic', 'garment',
104
+ 'gas', 'gasp', 'gate', 'gather', 'gauge', 'gaze', 'general', 'genius',
105
+ 'genre', 'gentle', 'genuine', 'gesture', 'ghost', 'giant', 'gift', 'giggle',
106
+ 'ginger', 'giraffe', 'girl', 'give', 'glad', 'glance', 'glare', 'glass',
107
+ 'glide', 'glimpse', 'globe', 'gloom', 'glory', 'glove', 'glow', 'glue',
108
+ 'goat', 'goddess', 'gold', 'good', 'goose', 'gorilla', 'gospel', 'gossip',
109
+ 'govern', 'gown', 'grab', 'grace', 'grain', 'grant', 'grape', 'grass',
110
+ 'gravity', 'great', 'green', 'grid', 'grief', 'grit', 'grocery', 'group',
111
+ 'grow', 'grunt', 'guard', 'guess', 'guide', 'guilt', 'guitar', 'gun',
112
+ 'gym', 'habit', 'hair', 'half', 'hammer', 'hamster', 'hand', 'happy',
113
+ 'harbor', 'hard', 'harsh', 'harvest', 'hat', 'have', 'hawk', 'hazard',
114
+ 'head', 'health', 'heart', 'heavy', 'hedgehog', 'height', 'hello', 'helmet',
115
+ 'help', 'hen', 'hero', 'hidden', 'high', 'hill', 'hint', 'hip',
116
+ 'hire', 'history', 'hobby', 'hockey', 'hold', 'hole', 'holiday', 'hollow',
117
+ 'home', 'honey', 'hood', 'hope', 'horn', 'horror', 'horse', 'hospital',
118
+ 'host', 'hotel', 'hour', 'hover', 'hub', 'huge', 'human', 'humble',
119
+ 'humor', 'hundred', 'hungry', 'hunt', 'hurdle', 'hurry', 'hurt', 'husband',
120
+ 'hybrid', 'ice', 'icon', 'idea', 'identify', 'idle', 'ignore', 'ill',
121
+ 'illegal', 'illness', 'image', 'imitate', 'immense', 'immune', 'impact', 'impose',
122
+ 'improve', 'impulse', 'inch', 'include', 'income', 'increase', 'index', 'indicate',
123
+ 'indoor', 'industry', 'infant', 'inflict', 'inform', 'inhale', 'inherit', 'initial',
124
+ 'inject', 'injury', 'inmate', 'inner', 'innocent', 'input', 'inquiry', 'insane',
125
+ 'insect', 'inside', 'inspire', 'install', 'intact', 'interest', 'into', 'invest',
126
+ 'invite', 'involve', 'iron', 'island', 'isolate', 'issue', 'item', 'ivory',
127
+ 'jacket', 'jaguar', 'jar', 'jazz', 'jealous', 'jeans', 'jelly', 'jewel',
128
+ 'job', 'join', 'joke', 'journey', 'joy', 'judge', 'juice', 'jump',
129
+ 'jungle', 'junior', 'junk', 'just', 'kangaroo', 'keen', 'keep', 'ketchup',
130
+ 'key', 'kick', 'kid', 'kidney', 'kind', 'kingdom', 'kiss', 'kit',
131
+ 'kitchen', 'kite', 'kitten', 'kiwi', 'knee', 'knife', 'knock', 'know',
132
+ 'lab', 'label', 'labor', 'ladder', 'lady', 'lake', 'lamp', 'language',
133
+ 'laptop', 'large', 'later', 'latin', 'laugh', 'laundry', 'lava', 'law',
134
+ 'lawn', 'lawsuit', 'layer', 'lazy', 'leader', 'leaf', 'learn', 'leave',
135
+ 'lecture', 'left', 'leg', 'legal', 'legend', 'leisure', 'lemon', 'lend',
136
+ 'length', 'lens', 'leopard', 'lesson', 'letter', 'level', 'liar', 'liberty',
137
+ 'library', 'license', 'life', 'lift', 'light', 'like', 'limb', 'limit',
138
+ 'link', 'lion', 'liquid', 'list', 'little', 'live', 'lizard', 'load',
139
+ 'loan', 'lobster', 'local', 'lock', 'logic', 'lonely', 'long', 'loop',
140
+ 'lottery', 'loud', 'lounge', 'love', 'loyal', 'lucky', 'luggage', 'lumber',
141
+ 'lunar', 'lunch', 'luxury', 'lyrics', 'machine', 'mad', 'magic', 'magnet',
142
+ 'maid', 'mail', 'main', 'major', 'make', 'mammal', 'man', 'manage',
143
+ 'mandate', 'mango', 'mansion', 'manual', 'maple', 'marble', 'march', 'margin',
144
+ 'marine', 'market', 'marriage', 'mask', 'mass', 'master', 'match', 'material',
145
+ 'math', 'matrix', 'matter', 'maximum', 'maze', 'meadow', 'mean', 'measure',
146
+ 'meat', 'mechanic', 'medal', 'media', 'melody', 'melt', 'member', 'memory',
147
+ 'mention', 'menu', 'mercy', 'merge', 'merit', 'merry', 'mesh', 'message',
148
+ 'metal', 'method', 'middle', 'midnight', 'milk', 'million', 'mimic', 'mind',
149
+ 'minimum', 'minor', 'minute', 'miracle', 'mirror', 'misery', 'miss', 'mistake',
150
+ 'mix', 'mixed', 'mixture', 'mobile', 'model', 'modify', 'mom', 'moment',
151
+ 'monitor', 'monkey', 'monster', 'month', 'moon', 'moral', 'more', 'morning',
152
+ 'mosquito', 'mother', 'motion', 'motor', 'mountain', 'mouse', 'move', 'movie',
153
+ 'much', 'muffin', 'mule', 'multiply', 'muscle', 'museum', 'mushroom', 'music',
154
+ 'must', 'mutual', 'myself', 'mystery', 'myth', 'naive', 'name', 'napkin',
155
+ 'narrow', 'nasty', 'nation', 'nature', 'near', 'neck', 'need', 'negative',
156
+ 'neglect', 'neither', 'nephew', 'nerve', 'nest', 'net', 'network', 'neutral',
157
+ 'never', 'news', 'next', 'nice', 'night', 'noble', 'noise', 'nominee',
158
+ 'noodle', 'normal', 'north', 'nose', 'notable', 'note', 'nothing', 'notice',
159
+ 'novel', 'now', 'nuclear', 'number', 'nurse', 'nut', 'oak', 'obey',
160
+ 'object', 'oblige', 'obscure', 'observe', 'obtain', 'obvious', 'occur', 'ocean',
161
+ 'october', 'odor', 'off', 'offer', 'office', 'often', 'oil', 'okay',
162
+ 'old', 'olive', 'olympic', 'omit', 'once', 'one', 'onion', 'online',
163
+ 'only', 'open', 'opera', 'opinion', 'oppose', 'option', 'orange', 'orbit',
164
+ 'orchard', 'order', 'ordinary', 'organ', 'orient', 'original', 'orphan', 'ostrich',
165
+ 'other', 'outdoor', 'outer', 'output', 'outside', 'oval', 'oven', 'over',
166
+ 'own', 'owner', 'oxygen', 'oyster', 'ozone', 'pact', 'paddle', 'page',
167
+ 'pair', 'palace', 'palm', 'panda', 'panel', 'panic', 'panther', 'paper',
168
+ 'parade', 'parent', 'park', 'parrot', 'party', 'pass', 'patch', 'path',
169
+ 'patient', 'patrol', 'pattern', 'pause', 'pave', 'payment', 'peace', 'peanut',
170
+ 'pear', 'peasant', 'pelican', 'pen', 'penalty', 'pencil', 'people', 'pepper',
171
+ 'perfect', 'permit', 'person', 'pet', 'phone', 'photo', 'phrase', 'physical',
172
+ 'piano', 'picnic', 'picture', 'piece', 'pig', 'pigeon', 'pill', 'pilot',
173
+ 'pink', 'pioneer', 'pipe', 'pistol', 'pitch', 'pizza', 'place', 'planet',
174
+ 'plastic', 'plate', 'play', 'please', 'pledge', 'pluck', 'plug', 'plunge',
175
+ 'poem', 'poet', 'point', 'polar', 'pole', 'police', 'pond', 'pony',
176
+ 'pool', 'popular', 'portion', 'position', 'possible', 'post', 'potato', 'pottery',
177
+ 'poverty', 'powder', 'power', 'practice', 'praise', 'predict', 'prefer', 'prepare',
178
+ 'present', 'pretty', 'prevent', 'price', 'pride', 'primary', 'print', 'priority',
179
+ 'prison', 'private', 'prize', 'problem', 'process', 'produce', 'profit', 'program',
180
+ 'project', 'promote', 'proof', 'property', 'prosper', 'protect', 'proud', 'provide',
181
+ 'public', 'pudding', 'pull', 'pulp', 'pulse', 'pumpkin', 'punch', 'pupil',
182
+ 'puppy', 'purchase', 'purity', 'purpose', 'purse', 'push', 'put', 'puzzle',
183
+ 'pyramid', 'quality', 'quantum', 'quarter', 'question', 'quick', 'quit', 'quiz',
184
+ 'quote', 'rabbit', 'raccoon', 'race', 'rack', 'radar', 'radio', 'rail',
185
+ 'rain', 'raise', 'rally', 'ramp', 'ranch', 'random', 'range', 'rapid',
186
+ 'rare', 'rate', 'rather', 'raven', 'raw', 'razor', 'ready', 'real',
187
+ 'reason', 'rebel', 'rebuild', 'recall', 'receive', 'recipe', 'record', 'recycle',
188
+ 'reduce', 'reflect', 'reform', 'refuse', 'region', 'regret', 'regular', 'reject',
189
+ 'relax', 'release', 'relief', 'rely', 'remain', 'remember', 'remind', 'remove',
190
+ 'render', 'renew', 'rent', 'reopen', 'repair', 'repeat', 'replace', 'report',
191
+ 'require', 'rescue', 'resemble', 'resist', 'resource', 'response', 'result', 'retire',
192
+ 'retreat', 'return', 'reunion', 'reveal', 'review', 'reward', 'rhythm', 'rib',
193
+ 'ribbon', 'rice', 'rich', 'ride', 'ridge', 'rifle', 'right', 'rigid',
194
+ 'ring', 'riot', 'ripple', 'risk', 'ritual', 'rival', 'river', 'road',
195
+ 'roast', 'robot', 'robust', 'rocket', 'romance', 'roof', 'rookie', 'room',
196
+ 'rose', 'rotate', 'rough', 'round', 'route', 'royal', 'rubber', 'rude',
197
+ 'rug', 'rule', 'run', 'runway', 'rural', 'sad', 'saddle', 'sadness',
198
+ 'safe', 'sail', 'salad', 'salmon', 'salon', 'salt', 'salute', 'same',
199
+ 'sample', 'sand', 'satisfy', 'satoshi', 'sauce', 'sausage', 'save', 'say',
200
+ 'scale', 'scan', 'scare', 'scatter', 'scene', 'scheme', 'school', 'science',
201
+ 'scissors', 'scorpion', 'scout', 'scrap', 'screen', 'script', 'scrub', 'sea',
202
+ 'search', 'season', 'seat', 'second', 'secret', 'section', 'security', 'seed',
203
+ 'seek', 'segment', 'select', 'sell', 'seminar', 'senior', 'sense', 'sentence',
204
+ 'series', 'service', 'session', 'settle', 'setup', 'seven', 'shadow', 'shaft',
205
+ 'shallow', 'share', 'shed', 'shell', 'sheriff', 'shield', 'shift', 'shine',
206
+ 'ship', 'shiver', 'shock', 'shoe', 'shoot', 'shop', 'short', 'shoulder',
207
+ 'shove', 'shrimp', 'shrug', 'shuffle', 'shy', 'sibling', 'sick', 'side',
208
+ 'siege', 'sight', 'sign', 'silent', 'silk', 'silly', 'silver', 'similar',
209
+ 'simple', 'since', 'sing', 'siren', 'sister', 'situate', 'six', 'size',
210
+ 'skate', 'sketch', 'ski', 'skill', 'skin', 'skirt', 'skull', 'slab',
211
+ 'slam', 'sleep', 'slender', 'slice', 'slide', 'slight', 'slim', 'slogan',
212
+ 'slot', 'slow', 'slush', 'small', 'smart', 'smile', 'smoke', 'smooth',
213
+ 'snack', 'snake', 'snap', 'sniff', 'snow', 'soap', 'soccer', 'social',
214
+ 'sock', 'soda', 'soft', 'solar', 'soldier', 'solid', 'solution', 'solve',
215
+ 'someone', 'song', 'soon', 'sorry', 'sort', 'soul', 'sound', 'soup',
216
+ 'source', 'south', 'space', 'spare', 'spatial', 'spawn', 'speak', 'special',
217
+ 'speed', 'spell', 'spend', 'sphere', 'spice', 'spider', 'spike', 'spin',
218
+ 'spirit', 'split', 'spoil', 'sponsor', 'spoon', 'sport', 'spot', 'spray',
219
+ 'spread', 'spring', 'spy', 'square', 'squeeze', 'squirrel', 'stable', 'stadium',
220
+ 'staff', 'stage', 'stairs', 'stamp', 'stand', 'start', 'state', 'stay',
221
+ 'steak', 'steel', 'stem', 'step', 'stereo', 'stick', 'still', 'sting',
222
+ 'stock', 'stomach', 'stone', 'stool', 'story', 'stove', 'strategy', 'street',
223
+ 'strike', 'strong', 'struggle', 'student', 'stuff', 'stumble', 'style', 'subject',
224
+ 'submit', 'subway', 'success', 'such', 'sudden', 'suffer', 'sugar', 'suggest',
225
+ 'suit', 'summer', 'sun', 'sunny', 'sunset', 'super', 'supply', 'supreme',
226
+ 'sure', 'surface', 'surge', 'surprise', 'surround', 'survey', 'suspect', 'sustain',
227
+ 'swallow', 'swamp', 'swap', 'swarm', 'swear', 'sweet', 'swift', 'swim',
228
+ 'swing', 'switch', 'sword', 'symbol', 'symptom', 'syrup', 'system', 'table',
229
+ 'tackle', 'tag', 'tail', 'talent', 'talk', 'tank', 'tape', 'target',
230
+ 'task', 'taste', 'tattoo', 'taxi', 'teach', 'team', 'tell', 'ten',
231
+ 'tenant', 'tennis', 'tent', 'term', 'test', 'text', 'thank', 'that',
232
+ 'theme', 'then', 'theory', 'there', 'they', 'thing', 'this', 'thought',
233
+ 'three', 'thrive', 'throw', 'thumb', 'thunder', 'ticket', 'tide', 'tiger',
234
+ 'tilt', 'timber', 'time', 'tiny', 'tip', 'tired', 'tissue', 'title',
235
+ 'toast', 'tobacco', 'today', 'toddler', 'toe', 'together', 'toilet', 'token',
236
+ 'tomato', 'tomorrow', 'tone', 'tongue', 'tonight', 'tool', 'tooth', 'top',
237
+ 'topic', 'topple', 'torch', 'tornado', 'tortoise', 'toss', 'total', 'tourist',
238
+ 'toward', 'tower', 'town', 'toy', 'track', 'trade', 'traffic', 'tragic',
239
+ 'train', 'transfer', 'trap', 'trash', 'travel', 'tray', 'treat', 'tree',
240
+ 'trend', 'trial', 'tribe', 'trick', 'trigger', 'trim', 'trip', 'trophy',
241
+ 'trouble', 'truck', 'true', 'truly', 'trumpet', 'trust', 'truth', 'try',
242
+ 'tube', 'tuition', 'tumble', 'tuna', 'tunnel', 'turkey', 'turn', 'turtle',
243
+ 'twelve', 'twenty', 'twice', 'twin', 'twist', 'two', 'type', 'typical',
244
+ 'ugly', 'umbrella', 'unable', 'unaware', 'uncle', 'uncover', 'under', 'undo',
245
+ 'unfair', 'unfold', 'unhappy', 'uniform', 'unique', 'unit', 'universe', 'unknown',
246
+ 'unlock', 'until', 'unusual', 'unveil', 'update', 'upgrade', 'uphold', 'upon',
247
+ 'upper', 'upset', 'urban', 'urge', 'usage', 'use', 'used', 'useful',
248
+ 'useless', 'usual', 'utility', 'vacant', 'vacuum', 'vague', 'valid', 'valley',
249
+ 'valve', 'van', 'vanish', 'vapor', 'various', 'vast', 'vault', 'vehicle',
250
+ 'velvet', 'vendor', 'venture', 'venue', 'verb', 'verify', 'version', 'very',
251
+ 'vessel', 'veteran', 'viable', 'vibrant', 'vicious', 'victory', 'video', 'view',
252
+ 'village', 'vintage', 'violin', 'virtual', 'virus', 'visa', 'visit', 'visual',
253
+ 'vital', 'vivid', 'vocal', 'voice', 'void', 'volcano', 'volume', 'vote',
254
+ 'voyage', 'wage', 'wagon', 'wait', 'walk', 'wall', 'walnut', 'want',
255
+ 'warfare', 'warm', 'warrior', 'wash', 'wasp', 'waste', 'water', 'wave',
256
+ 'way', 'wealth', 'weapon', 'wear', 'weasel', 'weather', 'web', 'wedding',
257
+ 'weekend', 'weird', 'welcome', 'west', 'wet', 'whale', 'what', 'wheat',
258
+ 'wheel', 'when', 'where', 'whip', 'whisper', 'wide', 'width', 'wife',
259
+ 'wild', 'will', 'win', 'window', 'wine', 'wing', 'wink', 'winner',
260
+ 'winter', 'wire', 'wisdom', 'wise', 'wish', 'witness', 'wolf', 'woman',
261
+ 'wonder', 'wood', 'wool', 'word', 'work', 'world', 'worry', 'worth',
262
+ 'wrap', 'wreck', 'wrestle', 'wrist', 'write', 'wrong', 'yard', 'year',
263
+ 'yellow', 'you', 'young', 'youth', 'zebra', 'zero', 'zone', 'zoo',
264
+ ]);
package/src/index.ts ADDED
@@ -0,0 +1,83 @@
1
+ /**
2
+ * index.ts — 公開 API barrel。
3
+ *
4
+ * 客戶端原語(WebCrypto;Argon2id 瀏覽器載體見 argon2.ts 檔頭 setArgonLoader):
5
+ */
6
+ export {
7
+ makeHeldKey,
8
+ generateNoteKey,
9
+ encryptNote,
10
+ decryptNote,
11
+ wrapNoteKey,
12
+ unwrapNoteKey,
13
+ wrapNoteKeyWithRecToken,
14
+ unwrapNoteKeyWithRecToken,
15
+ wrapNoteKeyDual,
16
+ unwrapNoteKeyDual,
17
+ storeLocalWrap,
18
+ ph1Of,
19
+ normalizePin,
20
+ recTokenHash,
21
+ generateRecToken,
22
+ PBKDF2_ITERATIONS,
23
+ PIN_PBKDF2_ITERATIONS,
24
+ type NoteCryptoConfig,
25
+ type IdentityProvider,
26
+ type HeldKey,
27
+ } from './client/note-crypto.ts';
28
+ export {
29
+ setArgonLoader,
30
+ verifyArgonKat,
31
+ wrapNoteKey3,
32
+ unwrapNoteKey3,
33
+ wrapNoteKeyDual3,
34
+ unwrapNoteKeyDual3,
35
+ wrapNoteKeyShare3,
36
+ unwrapNoteKeyShare3,
37
+ derivePh1Argon,
38
+ ARGON_MEMORY_KIB,
39
+ ARGON_ITERATIONS,
40
+ ARGON_PARALLELISM,
41
+ ARGON_TAG_LEN,
42
+ type Argon3Config,
43
+ } from './client/argon2.ts';
44
+ export {
45
+ wrapNoteKeyPinLock,
46
+ unwrapNoteKeyPinLock,
47
+ PINLOCK_ITERATIONS,
48
+ type PinLockConfig,
49
+ } from './client/pinlock.ts';
50
+ export {
51
+ generateBip39Words,
52
+ wordsToRecToken,
53
+ recTokenToWords,
54
+ spotCheckIndexes,
55
+ } from './client/bip39.ts';
56
+ export { makeKeyStore, type KeyStore, type KeyStoreConfig } from './client/keys.ts';
57
+ export { wordlist } from './client/wordlist.ts';
58
+
59
+ /** 伺服器端原語(Cloudflare Workers + D1)。 */
60
+ export {
61
+ makeInboundCipher,
62
+ isCipherFor,
63
+ validWrappedKey,
64
+ validHash64,
65
+ validSalt,
66
+ pickKeyPackage,
67
+ loginRouteCore,
68
+ errResponse,
69
+ AUTH_RATE,
70
+ type AuthRow,
71
+ type AuthStore,
72
+ type CipherFormats,
73
+ type KeyPackage,
74
+ } from './server/auth.ts';
75
+ export { checkRate, type RateWindow } from './server/ratelimit.ts';
76
+ export { corsResponse, CORS_HEADERS } from './server/cors.ts';
77
+ export {
78
+ sha256Hex,
79
+ hashString,
80
+ generateSessionToken,
81
+ timingSafeEq,
82
+ } from './server/hash.ts';
83
+ export type { Env } from './server/env.ts';
@@ -0,0 +1,146 @@
1
+ /**
2
+ * auth.ts — 零知識伺服器端 auth 核心邏輯(品牌/schema 參數化)。
3
+ *
4
+ * 不變量(勿破壞):
5
+ * - pass 明文永不過線:線上憑證送 PH1(雜湊形),伺服器存 PH2 = SHA-256(PH1)。
6
+ * PH1 派生方式由各產品自定義(快雜湊或 Argon2id 派生皆可)——本層只驗
7
+ * hex64 形,不驗 PH1 派生方式(伺服器零知識,無從也無需區分形別)。
8
+ * - hash-ladder 雙軌:舊式存 PH1 直比 → 命中即「順手升級」寫回 PH2
9
+ * - 常數時間比較(timingSafeEq)防時序側信道
10
+ * - 密語重設 = 舊憑證可能已洩漏 → 撤銷該身份全部 session
11
+ * - 金鑰包裹欄組(wrapped+salt)缺一整組放棄;rec 包裹與種子 hash 必須成對出現
12
+ *
13
+ * 與單一產品設計的結構差異(identity 模型已入型別):
14
+ * - identity 由伺服器端生成(隨機 account_id),不由客戶端帶入 soulKey——
15
+ * 本核心以 identityCallback 抽象兩種模型,schema 欄位名由各 fork 自訂。
16
+ */
17
+
18
+ import { corsResponse } from './cors.ts';
19
+ import { sha256Hex, generateSessionToken } from './hash.ts';
20
+ import { checkRate, type RateWindow } from './ratelimit.ts';
21
+ import type { Env } from './env';
22
+
23
+ // ── 格式驗證(自 noteCrypt.ts 抽出;前綴由 config 注入) ─────────────────────
24
+
25
+ export interface CipherFormats {
26
+ /** 密文前綴家族 regex 來源字串,如 '^jr1[gb]\.'。 */
27
+ cipherPrefixes: [string, string];
28
+ /** 金鑰包裹前綴,如 'jr1w.'。 */
29
+ wrapPrefix: string;
30
+ /** 密文位元組上限(入庫原樣、禁截斷密文)。 */
31
+ cipherMax: number;
32
+ }
33
+
34
+ const BASE64_RE = /^[A-Za-z0-9+/]+={0,2}$/;
35
+ const BINARY_RE = /[\x00-\x08\x0e-\x1f]/;
36
+ const HASH64_RE = /^[0-9a-f]{64}$/;
37
+ const SALT32_RE = /^[0-9a-f]{32}$/;
38
+
39
+ function cipherRe(c: CipherFormats): RegExp {
40
+ const escaped = c.cipherPrefixes.map(p => p.replace('.', '\\.'));
41
+ return new RegExp(`^(${escaped.join('|')})[A-Za-z0-9+/]+={0,2}$`);
42
+ }
43
+
44
+ /**
45
+ * 入庫前校正:前綴密文原樣入庫;超限密文/編碼丟棄(截斷必壞)、明文截到上限照收。
46
+ * plainMax:明文相容層上限(入庫原樣、禁截斷密文;無明文相容層的產品可設 0)。
47
+ */
48
+ export function makeInboundCipher(c: CipherFormats) {
49
+ const RE = new RegExp(`^(${c.cipherPrefixes.map(p => p.replace('.', '\\.')).join('|')})[A-Za-z0-9+/]+={0,2}$`);
50
+ return function inboundCipher(raw: unknown): string | null {
51
+ if (typeof raw !== 'string') return null;
52
+ const text = raw.trim();
53
+ if (!text) return null;
54
+ if (text.length > c.cipherMax) {
55
+ return RE.test(text) || BASE64_RE.test(text)
56
+ ? null // 密文/編碼超限:截斷必壞,直接丟棄
57
+ : text.slice(0, c.cipherMax); // 純明文(舊版客戶端):截到上限照收
58
+ }
59
+ if (RE.test(text)) return text; // 前綴密文:原樣入庫
60
+ if (BASE64_RE.test(text) && text.length > 40) return text; // 舊客戶端 b64 慣例:照收
61
+ if (BINARY_RE.test(text)) return null; // 控制字元垃圾:丟棄
62
+ return text; // 真明文:照收(舊版相容)
63
+ };
64
+ }
65
+
66
+ export function isCipherFor(text: string | null | undefined, c: CipherFormats): boolean {
67
+ if (typeof text !== 'string') return false;
68
+ return text.startsWith(c.cipherPrefixes[0]) || text.startsWith(c.cipherPrefixes[1]);
69
+ }
70
+
71
+ export function validWrappedKey(v: unknown, wrapPrefix: string | string[]): string | null {
72
+ const prefixes = Array.isArray(wrapPrefix) ? wrapPrefix : [wrapPrefix];
73
+ const escaped = prefixes.map(p => p.replace('.', '\\.'));
74
+ const re = new RegExp(`^(${escaped.join('|')})[A-Za-z0-9+/]+={0,2}$`);
75
+ return typeof v === 'string' && v.length <= 200 && re.test(v) ? v : null;
76
+ }
77
+
78
+ export function validHash64(v: unknown): string | null {
79
+ return typeof v === 'string' && HASH64_RE.test(v) ? v : null;
80
+ }
81
+
82
+ export function validSalt(v: unknown): string | null {
83
+ return typeof v === 'string' && SALT32_RE.test(v) ? v : null;
84
+ }
85
+
86
+ /** 綁定/復原共用的金鑰包裹欄組:wrapped 與 salt 必須成對,缺一整組放棄。 */
87
+ export function pickKeyPackage(body: any, wrapPrefix: string | string[]): { wrapped: string | null; salt: string | null } {
88
+ const wrapped = validWrappedKey(body?.note_wrapped ?? body?.wrapped, wrapPrefix);
89
+ const salt = validSalt(body?.note_salt ?? body?.salt);
90
+ return { wrapped: wrapped && salt ? wrapped : null, salt: wrapped && salt ? salt : null };
91
+ }
92
+
93
+ // ── 介面:各 fork 接線自己的 schema 欄位 ─────────────────────────────────────
94
+
95
+ export interface KeyPackage {
96
+ wrapped: string;
97
+ salt: string;
98
+ }
99
+
100
+ export interface AuthStore {
101
+ /** 以 PH2 查身份(PH2 UNIQUE;tacet:隨機 account_id 在此建立)。 */
102
+ findByIdentityQuery(ph2: string): Promise<AuthRow | null>;
103
+ /** 建立(identity 由本層 identityCallback 決定:隨機 account_id 或客戶端帶入語意)。 */
104
+ createUser(ph2: string): Promise<string>;
105
+ getByUserKey(key: string): Promise<AuthRow | null>;
106
+ getByRecHash(recHash: string): Promise<AuthRow | null>;
107
+ setWrapped(userKey: string, ph2: string, pkg: KeyPackage, recPkg: string | null, recHash: string | null): Promise<void>;
108
+ revokeAllSessions(userKey: string): Promise<void>;
109
+ insertSession(tokenHash: string, userKey: string, expiresAt: number): Promise<void>;
110
+ }
111
+
112
+ export interface AuthRow {
113
+ userKey: string; // identity(account_id / user id)
114
+ ph2: string | null; // SHA-256(PH1);null = 未綁定 guest
115
+ salt: string | null;
116
+ wrapped: string | null;
117
+ wrappedRec: string | null;
118
+ recHash: string | null;
119
+ /** 訂閱方案(tacet:users.plan,'free'/'paid');兄弟 fork 無訂閱面時預設 'free'。 */
120
+ plan?: string;
121
+ }
122
+
123
+ export const AUTH_RATE: RateWindow = { table: 'login_rate', windowMs: 60_000, max: 10 };
124
+
125
+ export function errResponse(code: string, status: number): Response {
126
+ return corsResponse(new Response(code, { status }));
127
+ }
128
+
129
+ // ── /auth/login:PH1 進站 → PH2 查詢(UNIQUE)→ session ─────────────────────
130
+
131
+ export async function loginRouteCore(env: Env & Record<string, unknown>, store: AuthStore, ip: string, ph1In: unknown): Promise<Response> {
132
+ if (!(await checkRate(env, AUTH_RATE, ip))) return errResponse('ERR_RATE_LIMITED', 429);
133
+ const ph1 = validHash64(ph1In);
134
+ if (!ph1) return errResponse('ERR_BAD_REQUEST', 400);
135
+ const ph2 = await sha256Hex(ph1);
136
+ const user = await store.findByIdentityQuery(ph2);
137
+ const userKey: string = user ? user.userKey : await store.createUser(ph2);
138
+ const token = generateSessionToken();
139
+ const expiresAt = Date.now() + 30 * 24 * 60 * 60 * 1000; // PWA:30 天
140
+ await store.insertSession(await sha256Hex(token), userKey, expiresAt);
141
+ return corsResponse(new Response(JSON.stringify({
142
+ sessionToken: token,
143
+ userKey,
144
+ status: user?.ph2 ? 'ready' : 'require_binding',
145
+ }), { headers: { 'Content-Type': 'application/json' } }));
146
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * cors.ts — 共用 CORS 本體(多產品 diff 證實完全一致,直取)。
3
+ */
4
+ export const CORS_HEADERS = {
5
+ 'Access-Control-Allow-Origin': '*',
6
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
7
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
8
+ };
9
+
10
+ export function corsResponse(res: Response): Response {
11
+ const newHeaders = new Headers(res.headers);
12
+ Object.entries(CORS_HEADERS).forEach(([k, v]) => newHeaders.set(k, v));
13
+ return new Response(res.body, {
14
+ status: res.status,
15
+ statusText: res.statusText,
16
+ headers: newHeaders,
17
+ });
18
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * env.ts — core 對 Worker Env 的最小介面。各 fork 的 Env 以此為基底擴充。
3
+ */
4
+ export interface Env {
5
+ DB: D1Database;
6
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * hash.ts — 品牌無關的雜湊/token 工具。
3
+ * 產品專屬 obfuscate/deobfuscate 不入 core(透明品牌裁定:明文 JSON + TLS)。
4
+ */
5
+
6
+ export async function sha256Hex(text: string): Promise<string> {
7
+ const data = new TextEncoder().encode(text);
8
+ const digest = await crypto.subtle.digest('SHA-256', data);
9
+ return Array.from(new Uint8Array(digest)).map(b => b.toString(16).padStart(2, '0')).join('');
10
+ }
11
+
12
+ /** 相容別名:姊妹產品呼叫點用此名。 */
13
+ export const hashString = sha256Hex;
14
+
15
+ /** 256-bit 隨機 session token(hex)。伺服器只存 SHA-256。 */
16
+ export function generateSessionToken(): string {
17
+ return Array.from(crypto.getRandomValues(new Uint8Array(32)))
18
+ .map(b => b.toString(16).padStart(2, '0'))
19
+ .join('');
20
+ }
21
+
22
+ /** 常數時間字串比較(防時序側信道;多產品共用抽出)。 */
23
+ export function timingSafeEq(a: string, b: string): boolean {
24
+ if (a.length !== b.length) return false;
25
+ let diff = 0;
26
+ for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
27
+ return diff === 0;
28
+ }