on master help sign in
Use Urbit @ob-style syllable encoding for public keys in UI
commit78fb9ef453b7114fe0864ce8ef3476a4d907b74b authoriko <mail@iko.soy> dateFri 10 Apr 2026, 15:04 (6 months ago) parentf4f8a00
5 files changed+149−8
client/App.fs+25−6 client/Phonemic.fs+121 client/Skrepka.fsproj+1 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfo.fs+1−1 client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfoInputs.cache+1−1
client/App.fs+25−6
@@ -92,7 +92,17 @@ module App =
9292 let private truncate maxLen (s: string) =
9393 if s.Length > maxLen then s.[..maxLen - 1] + "..." else s
9494
95− let private truncKey (hex: string) = truncate 16 hex
95+ let private hexToOb (hex: string) =
96+ Crypto.fromHex hex |> Phonemic.toOb
97+
98+ let private truncKey (hex: string) =
99+ let ob = hexToOb hex
100+ match ob.IndexOf('-') with
101+ | -1 -> ob
102+ | i ->
103+ match ob.IndexOf('-', i + 1) with
104+ | -1 -> ob
105+ | j -> ob.[..j - 1]
96106
97107 let private contactName (contacts: Contact list) (pk: string) =
98108 contacts
@@ -219,7 +229,15 @@ module App =
219229 | DoSaveContact ->
220230 match model.Page with
221231 | AddContact(pk, nn) when pk <> "" && nn <> "" ->
222− let contact: Contact = { Pubkey = pk; Nickname = nn }
232+ let pubkeyHex =
233+ if pk.Contains("-") then
234+ match Phonemic.fromOb pk with
235+ | Some bytes -> Crypto.toHex bytes
236+ | None -> pk
237+ else
238+ pk
239+
240+ let contact: Contact = { Pubkey = pubkeyHex; Nickname = nn }
223241
224242 let model' =
225243 { model with
@@ -232,7 +250,7 @@ module App =
232250 | CopyPubKey ->
233251 model,
234252 [ match model.Auth with
235− | Identified(id, _) -> CmdCopyToClipboard id.PubKeyHex
253+ | Identified(id, _) -> CmdCopyToClipboard(hexToOb id.PubKeyHex)
236254 | NoIdentity -> () ]
237255
238256 | DismissError -> { model with Error = None }, []
@@ -397,8 +415,8 @@ module App =
397415
398416 Label("Your Public Key:")
399417
400− Label(pubKeyHex model)
401− .font(size = 9.)
418+ Label(hexToOb (pubKeyHex model))
419+ .font(size = 11.)
402420
403421 Button("Copy Public Key", CopyPubKey)
404422
@@ -535,8 +553,9 @@ module App =
535553 .font(size = 20.)
536554 }
537555
538− Label("Public Key (hex):")
556+ Label("Public Key:")
539557 Entry(pk, fun t -> SetPage(AddContact(t, nn)))
558+ .placeholder("sampel-palnet-...")
540559
541560 Label("Nickname:")
542561 Entry(nn, fun t -> SetPage(AddContact(pk, t)))
client/Phonemic.fsnew file+121
@@ -0,0 +1,121 @@
1+namespace Skrepka
2+
3+module Phonemic =
4+
5+ // Urbit @p syllable tables (256 prefixes, 256 suffixes)
6+ // Each byte pair encodes as prefix[hi] + suffix[lo]
7+
8+ let private prefixes =
9+ [| "doz"; "mar"; "bin"; "wan"; "sam"; "lit"; "sig"; "hid"
10+ "fid"; "lis"; "sog"; "dir"; "wac"; "sab"; "wis"; "sib"
11+ "rig"; "sol"; "dop"; "mod"; "fog"; "lid"; "hop"; "dar"
12+ "dor"; "lor"; "hod"; "fol"; "rin"; "tog"; "sil"; "mir"
13+ "hol"; "pas"; "lac"; "rov"; "liv"; "dal"; "sat"; "lib"
14+ "tab"; "han"; "tic"; "pid"; "tor"; "bol"; "fos"; "dot"
15+ "los"; "dil"; "for"; "pil"; "ram"; "tir"; "win"; "tad"
16+ "bic"; "dif"; "roc"; "wid"; "bis"; "das"; "mid"; "lop"
17+ "ril"; "nar"; "dap"; "mol"; "san"; "loc"; "nov"; "sit"
18+ "nid"; "tip"; "sic"; "rop"; "wit"; "nat"; "pan"; "min"
19+ "rit"; "pod"; "mot"; "tam"; "tol"; "sav"; "pos"; "nap"
20+ "nop"; "som"; "fin"; "fon"; "ban"; "mor"; "wor"; "sip"
21+ "ron"; "nor"; "bot"; "wic"; "soc"; "wat"; "dol"; "mag"
22+ "pic"; "dav"; "bid"; "bal"; "tim"; "tas"; "mal"; "lig"
23+ "siv"; "tag"; "pad"; "sal"; "div"; "dac"; "tan"; "sid"
24+ "fab"; "tar"; "mon"; "ran"; "nis"; "wol"; "mis"; "pal"
25+ "las"; "dis"; "map"; "rab"; "tob"; "rol"; "lat"; "lon"
26+ "nod"; "nav"; "fig"; "nom"; "nib"; "pag"; "sop"; "ral"
27+ "bil"; "had"; "doc"; "rid"; "moc"; "pac"; "rav"; "rip"
28+ "fal"; "tod"; "til"; "tin"; "hap"; "mic"; "fan"; "pat"
29+ "tac"; "lab"; "mog"; "sim"; "son"; "pin"; "lom"; "ric"
30+ "tap"; "fir"; "has"; "bos"; "bat"; "poc"; "hac"; "tid"
31+ "hav"; "sap"; "lin"; "dib"; "hos"; "dab"; "bit"; "bar"
32+ "rac"; "par"; "lod"; "dos"; "bor"; "toc"; "hil"; "mac"
33+ "tom"; "dig"; "fil"; "fas"; "mit"; "hob"; "har"; "mig"
34+ "hin"; "rad"; "mas"; "hal"; "rag"; "lag"; "fad"; "top"
35+ "mop"; "hab"; "nil"; "nos"; "mil"; "fop"; "fam"; "dat"
36+ "nol"; "din"; "hat"; "nac"; "ris"; "fot"; "rib"; "hoc"
37+ "nim"; "lar"; "fit"; "wal"; "rap"; "sar"; "nal"; "mos"
38+ "lan"; "don"; "dan"; "lad"; "dov"; "riv"; "bac"; "pol"
39+ "lap"; "tal"; "pit"; "nam"; "bon"; "ros"; "ton"; "fod"
40+ "pon"; "sov"; "noc"; "sor"; "lav"; "mat"; "mip"; "fip" |]
41+
42+ let private suffixes =
43+ [| "zod"; "nec"; "bud"; "wes"; "sev"; "per"; "sut"; "let"
44+ "ful"; "pen"; "syt"; "dur"; "wep"; "ser"; "wyl"; "sun"
45+ "ryp"; "syx"; "dyr"; "nup"; "heb"; "peg"; "lup"; "dep"
46+ "dys"; "put"; "lug"; "hec"; "ryt"; "tyv"; "syd"; "nex"
47+ "lun"; "mep"; "lut"; "sep"; "pes"; "del"; "sul"; "ped"
48+ "tem"; "led"; "tul"; "met"; "wen"; "byn"; "hex"; "feb"
49+ "pyl"; "dul"; "het"; "mev"; "rut"; "tyl"; "wyd"; "tep"
50+ "bes"; "dex"; "sef"; "wyc"; "bur"; "der"; "nep"; "pur"
51+ "rys"; "reb"; "den"; "nut"; "sub"; "pet"; "rul"; "syn"
52+ "reg"; "tyd"; "sup"; "sem"; "wyn"; "rec"; "meg"; "net"
53+ "sec"; "mul"; "nym"; "tev"; "web"; "sum"; "mut"; "nyx"
54+ "rex"; "teb"; "fus"; "hep"; "ben"; "mus"; "wyx"; "sym"
55+ "sel"; "ruc"; "dec"; "wex"; "syr"; "wet"; "dyl"; "myn"
56+ "mes"; "det"; "bet"; "bel"; "tux"; "tug"; "myr"; "pel"
57+ "syp"; "ter"; "meb"; "set"; "dut"; "deg"; "tex"; "sur"
58+ "fel"; "tud"; "nux"; "rux"; "ren"; "wyt"; "nub"; "med"
59+ "lyt"; "dus"; "neb"; "rum"; "tyn"; "seg"; "lyx"; "pun"
60+ "res"; "red"; "fun"; "rev"; "ref"; "mec"; "ted"; "rus"
61+ "bex"; "leb"; "dux"; "ryn"; "num"; "pyx"; "ryg"; "ryx"
62+ "fep"; "tyr"; "tus"; "tyc"; "leg"; "nem"; "fer"; "mer"
63+ "ten"; "lus"; "nus"; "syl"; "tec"; "mex"; "pub"; "rym"
64+ "tuc"; "fyl"; "lep"; "deb"; "ber"; "mug"; "hut"; "tun"
65+ "byl"; "sud"; "pem"; "dev"; "lur"; "def"; "bus"; "bep"
66+ "run"; "mel"; "pex"; "dyt"; "byt"; "typ"; "lev"; "myl"
67+ "wed"; "duc"; "fur"; "fex"; "nul"; "luc"; "len"; "ner"
68+ "lex"; "rup"; "ned"; "lec"; "ryd"; "lyd"; "fen"; "wel"
69+ "nyd"; "hus"; "rel"; "rud"; "nes"; "hes"; "fet"; "des"
70+ "ret"; "dun"; "ler"; "nyr"; "seb"; "hul"; "ryl"; "lud"
71+ "rem"; "lys"; "fyn"; "wer"; "ryc"; "sug"; "nys"; "nyl"
72+ "lyn"; "dyn"; "dem"; "lux"; "fed"; "sed"; "bec"; "mun"
73+ "lyr"; "tes"; "mud"; "nyt"; "byr"; "sen"; "weg"; "fyr"
74+ "mur"; "tel"; "rep"; "teg"; "pec"; "nel"; "nev"; "fes" |]
75+
76+ let private prefixMap =
77+ prefixes |> Array.mapi (fun i s -> s, byte i) |> Map.ofArray
78+
79+ let private suffixMap =
80+ suffixes |> Array.mapi (fun i s -> s, byte i) |> Map.ofArray
81+
82+ let toOb (bytes: byte[]) : string =
83+ let sb = System.Text.StringBuilder()
84+
85+ for i in 0..2 .. bytes.Length - 1 do
86+ let pair = i / 2
87+
88+ if pair > 0 then
89+ sb.Append('-') |> ignore
90+
91+ sb.Append(prefixes.[int bytes.[i]]).Append(suffixes.[int bytes.[i + 1]])
92+ |> ignore
93+
94+ sb.ToString()
95+
96+ let fromOb (s: string) : byte[] option =
97+ let s = s.Trim('-')
98+
99+ if s = "" then
100+ None
101+ else
102+ let pairs = s.Split('-') |> Array.filter (fun p -> p <> "")
103+
104+ let results =
105+ pairs
106+ |> Array.map (fun sp ->
107+ if sp.Length = 6 then
108+ match Map.tryFind sp.[0..2] prefixMap, Map.tryFind sp.[3..5] suffixMap with
109+ | Some hi, Some lo -> Some(hi, lo)
110+ | _ -> None
111+ else
112+ None)
113+
114+ if results |> Array.forall Option.isSome then
115+ results
116+ |> Array.collect (fun r ->
117+ let hi, lo = r.Value
118+ [| hi; lo |])
119+ |> Some
120+ else
121+ None
client/Skrepka.fsproj+1
@@ -23,6 +23,7 @@
2323 <ItemGroup>
2424 <Compile Include="Crypto.fs" />
2525 <Compile Include="ApiClient.fs" />
26+ <Compile Include="Phonemic.fs" />
2627 <Compile Include="Store.fs" />
2728 <Compile Include="App.fs" />
2829 <Compile Include="MauiProgram.fs" />
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfo.fs+1−1
@@ -10,7 +10,7 @@ open System.Reflection
1010[<assembly: System.Reflection.AssemblyCompanyAttribute("Skrepka")>]
1111[<assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")>]
1212[<assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")>]
13−[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+c0cce11a1754909d3aa01c81e84df143a9bcd275")>]
13+[<assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0+f4f8a00e43e943aaf1ab17647f6d1e4f055c7d3a")>]
1414[<assembly: System.Reflection.AssemblyProductAttribute("Skrepka")>]
1515[<assembly: System.Reflection.AssemblyTitleAttribute("Skrepka")>]
1616[<assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")>]
client/obj/Debug/net10.0-maccatalyst/maccatalyst-arm64/Skrepka.AssemblyInfoInputs.cache+1−1
@@ -1 +1 @@
1−f6ed10664c2343267ee52965047bd52c638d641ef55e392d09d2476f8f4fbb69
1+d1e3dd8bf6923e3c33b8e7c46138a01be4bdfd2c1de6dfe8e4da64444b301b79