diff --git a/package-lock.json b/package-lock.json
index 21b859af0b9bf6d9526e35959bfc9883193d773c..1157beef786c5335156da283869029c3bf37e78d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -547,19 +547,6 @@
         "defer-to-connect": "^1.0.1"
       }
     },
-    "@thi.ng/base-n": {
-      "version": "0.1.6",
-      "resolved": "https://registry.npmjs.org/@thi.ng/base-n/-/base-n-0.1.6.tgz",
-      "integrity": "sha512-vvN0bhnSbuqk7i4BAeajdqZYwfqN4ESZjC/F216AXtg66BUhQp3zuIZh5u1PEsvFr59Z2T8U6HJgT5/PY0daxg==",
-      "requires": {
-        "@thi.ng/hex": "^0.2.5"
-      }
-    },
-    "@thi.ng/hex": {
-      "version": "0.2.5",
-      "resolved": "https://registry.npmjs.org/@thi.ng/hex/-/hex-0.2.5.tgz",
-      "integrity": "sha512-ziJHsLH7zUBjDlZD+q+HszUVMfx9uFE+spSrRTSnt4/fCmXuUxn6hlMAskGifNGBzpE4LB40OG1nvE+0kSYdDw=="
-    },
     "@types/clean-css": {
       "version": "4.2.3",
       "resolved": "https://registry.npmjs.org/@types/clean-css/-/clean-css-4.2.3.tgz",
@@ -1210,14 +1197,6 @@
         "yargs": "^16.2.0"
       }
     },
-    "b58": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/b58/-/b58-4.0.3.tgz",
-      "integrity": "sha512-VDtdiomm0ywbL8YzgevOZ9pcx6LuOZ3d9qYTPDcYUPf7dRYNA8wvK6epYy0FKMWIM5uaDwd3kWt1x+1S9scB1Q==",
-      "requires": {
-        "base-x": "^3.0.2"
-      }
-    },
     "babel-walk": {
       "version": "3.0.0-canary-5",
       "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz",
@@ -1300,14 +1279,6 @@
         }
       }
     },
-    "base-x": {
-      "version": "3.0.8",
-      "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz",
-      "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==",
-      "requires": {
-        "safe-buffer": "^5.0.1"
-      }
-    },
     "base64-js": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -2026,14 +1997,6 @@
         "node-releases": "^1.1.70"
       }
     },
-    "bs58": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
-      "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
-      "requires": {
-        "base-x": "^3.0.2"
-      }
-    },
     "buf-compare": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/buf-compare/-/buf-compare-1.0.1.tgz",
@@ -6525,6 +6488,10 @@
         "is-object": "^1.0.1"
       }
     },
+    "js-sha256": {
+      "version": "git+https://github.com/1000i100/js-sha256.git#87e8a41a4259eb45b219d170ece3c9e937351735",
+      "from": "git+https://github.com/1000i100/js-sha256.git#master"
+    },
     "js-string-escape": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",
@@ -9267,7 +9234,8 @@
     "safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+      "dev": true
     },
     "safe-regex": {
       "version": "2.1.1",
diff --git a/package.json b/package.json
index 8d5e9a5f97476ee2db8a7c92b5993f83b2afc1ed..60283de72373af72bb881641642182f6ceab9267 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
 		"test:dev:duplication": "jscpd ./ -s",
 		"xtest:dev:complexity": "codehawk ./",
 		"test:production": "run-s test:production:**",
-		"test:production:qualityCheck": "xo",
+		"xtest:production:qualityCheck": "xo",
 		"test:production:duplication": "jscpd ./",
 		"test:production:complexity": "./node_modules/.bin/es6-plato -r -d generated/maintainability ./src/*",
 		"test:production:complexity:badgesAndThreshold": "node CI/plato-badges.js",
@@ -35,13 +35,10 @@
 		"watch2null": "chokidar src/* -c \"npm run test:dev:runTests 2>/dev/null\""
 	},
 	"dependencies": {
-		"@thi.ng/base-n": "^0.1.6",
-		"b58": "^4.0.3",
-		"base-x": "^3.0.8",
-		"bs58": "^4.0.1",
 		"latinize-to-ascii": "^0.5.2",
 		"scrypt-async-modern": "^3.0.12",
-		"tweetnacl": "^1.0.3"
+		"tweetnacl": "^1.0.3",
+		"js-sha256": "https://github.com/1000i100/js-sha256#master"
 	},
 	"devDependencies": {
 		"@jscpd/badge-reporter": "^3.3.23",
diff --git a/src/crypto.mjs b/src/crypto.mjs
index f75a50b197414407fd60bd01fb74e4011d89ad3f..5c2173f9115a2a408be0507046e8789ff2f73297 100644
--- a/src/crypto.mjs
+++ b/src/crypto.mjs
@@ -1,8 +1,10 @@
-export {b58, saltPass2seed, seed2keyPair, idSecPass2rawAll, raw2b58, idSecPass2cleanKeys};
+export {b58, saltPass2seed, seed2keyPair, idSecPass2rawAll, raw2b58, idSecPass2cleanKeys, pubKey2shortKey};
 // Alt deps :  import {generate_keypair} from "ecma-nacl/build/lib/signing/sign.js";
 // Alt deps :  import scrypt from "ecma-nacl/build/lib/scrypt/scrypt.js";
 import nacl from '../generated/vendors/nacl.mjs';
 import {b58} from './basex.mjs';
+import sha from '../node_modules/js-sha256/src/sha256.mjs';
+const sha256 = sha();
 
 const generateKeypair = nacl.sign.keyPair.fromSeed;
 import scrypt from '../generated/vendors/scrypt.mjs';
@@ -42,3 +44,11 @@ async function saltPass2seed(idSec, pass) {
 	};
 	return scrypt(pass.normalize('NFKC'), idSec.normalize('NFKC'), options);
 }
+
+function pubKey2shortKey(pubkey) {
+	const checksum = b58.encode(sha256.digest(sha256.digest(b58.decode(pubkey))));
+	const pubKeyBegin = pubkey.substr(0, 4);
+	const pubKeyEnd = pubkey.substr(-4, 4);
+	const hashBegin = checksum.substr(0, 3);
+	return `${pubKeyBegin}…${pubKeyEnd}:${hashBegin}`;
+}
diff --git a/src/crypto.test.mjs b/src/crypto.test.mjs
index e4acd5f9bdce11f49b44ca33e63c951604f8938e..ff180a1289972aa4cac08e7bf7c8ec4b3b113c3d 100644
--- a/src/crypto.test.mjs
+++ b/src/crypto.test.mjs
@@ -28,3 +28,13 @@ test('idSecPass2cleanKeys should output clean base58 keys and seed', async t =>
 	t.is(r.idSec, idSec);
 	t.is(r.password, mdp);
 });
+test('pubKey2shortKey match D2me…wRaU:76W', t => {
+	const pubKey = 'D2meevcAHFTS2gQMvmRW5Hzi25jDdikk4nC4u1FkwRaU';
+	const shortKey = 'D2me…wRaU:76W';
+	t.is(app.pubKey2shortKey(pubKey), shortKey);
+});
+test('pubKey2shortKey match RML1…zvSY:3k4', t => {
+	const pubKey = 'RML12butzV3xZmkWnNAmRwuepKPYvzQ4euHwhHhzvSY';
+	const shortKey = 'RML1…zvSY:3k4';
+	t.is(app.pubKey2shortKey(pubKey), shortKey);
+});
diff --git a/src/dictionary-builder.test.mjs b/src/dictionary-builder.test.mjs
index 2ba749b055ef1458b906b34abbaca043e8802d18..0f1ada9332a7a50950ec4f3a4a07775a1fca4dfe 100644
--- a/src/dictionary-builder.test.mjs
+++ b/src/dictionary-builder.test.mjs
@@ -14,7 +14,7 @@ test('add multi word case variants', t => {
 test('regLikeVariants remove ref:: lines', t => {
 	t.deepEqual(app.regLikeVariants('ref::truc'), []);
 });
-//TODO: handle ref infinite loop by returning §infiniteRecursion§
+// TODO: handle ref infinite loop by returning §infiniteRecursion§
 test('regLikeVariants handle <ref>', t => {
 	t.deepEqual(app.regLikeVariants('<ref> <ref>', ['ref::truc', 'ref::bidule', '<ref> <ref>']), ['truc truc', 'bidule truc', 'truc bidule', 'bidule bidule']);
 	t.deepEqual(app.regLikeVariants('<ref> <ref>', ['ref::(truc|bidule)', '<ref> <ref>']), ['truc truc', 'bidule truc', 'truc bidule', 'bidule bidule']);
@@ -67,8 +67,3 @@ test('regLikeVariants handle [\\]*]', t => {
 test('regLikeVariants handle escaping common chr \\a', t => {
 	t.deepEqual(app.regLikeVariants('\\a'), ['a']);
 });
-/*
-test('how do you handle that ? -> parcours en largeur. Est-ce pertinant ? -> en fait, parcours avec redondance et suppression de doublon qui imite le parcours en largeur', t => {
-	t.deepEqual(app.regLikeVariants('(a(b@@@@c|d)|(e|f)|g|h@@@@i)'), []);
-});
-*/