Create wallet.js
Browse files- static/wallet.js +70 -0
static/wallet.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// 簡易ED25519ウォレット(デモ用)
|
| 2 |
+
// 鍵は localStorage に保存(本番はセキュアストレージやOSキーチェーン等を検討)
|
| 3 |
+
const LS_KEY = 'demo_wallet_ed25519';
|
| 4 |
+
|
| 5 |
+
function toBase58(bytes){ return bs58.encode(bytes); }
|
| 6 |
+
function fromBase58(str){ return bs58.decode(str); }
|
| 7 |
+
|
| 8 |
+
// 軽量 Base58(必要部分のみ)
|
| 9 |
+
const bs58 = (function(){
|
| 10 |
+
const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
| 11 |
+
const ALPHABET_MAP = new Uint8Array(256); ALPHABET_MAP.fill(255);
|
| 12 |
+
for (let i = 0; i < ALPHABET.length; i++) ALPHABET_MAP[ALPHABET.charCodeAt(i)] = i;
|
| 13 |
+
function encode(buffer){
|
| 14 |
+
if (buffer.length === 0) return '';
|
| 15 |
+
let zeros = 0, i = 0; while (i < buffer.length && buffer[i] === 0) { zeros++; i++; }
|
| 16 |
+
const size = ((buffer.length - i) * 138 / 100 + 1) >>> 0; const b58 = new Uint8Array(size);
|
| 17 |
+
let length = 0;
|
| 18 |
+
while (i < buffer.length){
|
| 19 |
+
let carry = buffer[i]; let j = 0;
|
| 20 |
+
for (let k = size - 1; (carry !== 0 || j < length) && (k >= 0); k--, j++){
|
| 21 |
+
carry += 256 * b58[k]; b58[k] = carry % 58; carry = (carry / 58) | 0;
|
| 22 |
+
}
|
| 23 |
+
length = j; i++;
|
| 24 |
+
}
|
| 25 |
+
let j = size - length; while (j < size && b58[j] === 0) j++;
|
| 26 |
+
let str = '1'.repeat(zeros) + Array.from(b58.slice(j), (c) => '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'[c]).join('');
|
| 27 |
+
return str;
|
| 28 |
+
}
|
| 29 |
+
function decode(string){
|
| 30 |
+
if (string.length === 0) return new Uint8Array();
|
| 31 |
+
let zeros = 0, i = 0; while (i < string.length && string[i] === '1') { zeros++; i++; }
|
| 32 |
+
const size = ((string.length - i) * 733 / 1000 + 1) >>> 0; const b256 = new Uint8Array(size);
|
| 33 |
+
let length = 0;
|
| 34 |
+
while (i < string.length){
|
| 35 |
+
let carry = ALPHABET_MAP[string.charCodeAt(i)]; if (carry === 255) throw new Error('invalid base58');
|
| 36 |
+
let j = 0;
|
| 37 |
+
for (let k = size - 1; (carry !== 0 || j < length) && (k >= 0); k--, j++){
|
| 38 |
+
carry += 58 * b256[k]; b256[k] = carry % 256; carry = (carry / 256) | 0;
|
| 39 |
+
}
|
| 40 |
+
length = j; i++;
|
| 41 |
+
}
|
| 42 |
+
let j = size - length; while (j < size && b256[j] === 0) j++;
|
| 43 |
+
const out = new Uint8Array(zeros + (size - j)); out.fill(0, 0, zeros); out.set(b256.slice(j), zeros); return out;
|
| 44 |
+
}
|
| 45 |
+
return { encode, decode };
|
| 46 |
+
})();
|
| 47 |
+
|
| 48 |
+
function getOrCreateWallet(){
|
| 49 |
+
const stored = localStorage.getItem(LS_KEY);
|
| 50 |
+
if (stored){ return JSON.parse(stored); }
|
| 51 |
+
const kp = nacl.sign.keyPair();
|
| 52 |
+
const address = toBase58(kp.publicKey);
|
| 53 |
+
const wallet = { address, publicKey: Array.from(kp.publicKey), secretKey: Array.from(kp.secretKey) };
|
| 54 |
+
localStorage.setItem(LS_KEY, JSON.stringify(wallet));
|
| 55 |
+
return wallet;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
function getWallet(){
|
| 59 |
+
const stored = localStorage.getItem(LS_KEY);
|
| 60 |
+
return stored ? JSON.parse(stored) : null;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
async function signMessage(message){
|
| 64 |
+
const w = getWallet() || getOrCreateWallet();
|
| 65 |
+
const secret = new Uint8Array(w.secretKey);
|
| 66 |
+
const sig = nacl.sign.detached(new TextEncoder().encode(message), secret);
|
| 67 |
+
return btoa(String.fromCharCode(...sig)); // base64
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
window.Wallet = { getOrCreateWallet, getWallet, signMessage };
|