diff --git a/CHANGELOG.fr.md b/CHANGELOG.fr.md
index 6190c5ae2336e773f922ba569dd8a47b8719907b..49cb6007aa0836a072cfeb6a7db611b6ab4c8ddd 100644
--- a/CHANGELOG.fr.md
+++ b/CHANGELOG.fr.md
@@ -13,6 +13,10 @@ et ce projet adhère au [versionnage sémantique](https://semver.org/spec/v2.0.0
 
 ## [Non-publié/Non-Stabilisé] (par [1000i100])
 
+### Ajouté
+- crypto.checkKey(pubKeyWithChecksum)
+- crypto.pubKey2checksum(b58pubKey, optionalBool:b58viewDependant, optionalBool:checksumWithoutLeadingZero)
+
 ## [Version 3.1.0] - 2021-04-01 (par [1000i100] & [Hugo])
 ### Ajouté
 - génération du [format court d'affichage de pubKey](https://forum.duniter.org/t/format-de-checksum/7616)
diff --git a/CI/vanityLike.mjs b/CI/vanityLike.mjs
new file mode 100644
index 0000000000000000000000000000000000000000..783aea8c28b4d24a8a81c61946678655faa1916d
--- /dev/null
+++ b/CI/vanityLike.mjs
@@ -0,0 +1,34 @@
+import * as app from "../src/crypto.mjs";
+
+function main() {
+	for (let x = 1; true; x++) {
+		const strX = ('' + x).replace(/0/g, '');
+		if (
+			app.pubKey2checksum('pubKey' + strX) !== app.pubKey2checksum('pubKey' + strX, false, true)
+			&&
+			app.pubKey2checksum('pubKey' + strX, true) !== app.pubKey2checksum('pubKey' + strX, true, true)
+			/*&&
+			app.pubKey2checksum('pubKey'+strX).includes('11')
+			&&
+			app.pubKey2checksum('pubKey'+strX,true).includes('11')
+			*/
+		) {
+			console.log('pubKey' + strX,
+				app.pubKey2checksum('pubKey' + strX),
+				app.pubKey2checksum('pubKey' + strX, false, true),
+				app.pubKey2checksum('pubKey' + strX, true),
+				app.pubKey2checksum('pubKey' + strX, true, true)
+			);
+			console.log('11111111111111111111111pubKey49311',
+				app.pubKey2checksum('11111111111111111111111pubKey49311'),
+				app.pubKey2checksum('11111111111111111111111pubKey49311', false, true),
+				app.pubKey2checksum('11111111111111111111111pubKey49311', true),
+				app.pubKey2checksum('11111111111111111111111pubKey49311', true, true)
+			);
+			return 'pubKey' + strX;
+		}
+		if (strX.includes('99999')) console.log('pubKey' + strX);
+	}
+}
+
+main();
diff --git a/src/crypto.mjs b/src/crypto.mjs
index 5c2173f9115a2a408be0507046e8789ff2f73297..e02e9d05f196fe74b545246f535da831c1357e70 100644
--- a/src/crypto.mjs
+++ b/src/crypto.mjs
@@ -1,15 +1,17 @@
-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';
+
+export {b58};
 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';
 
-async function idSecPass2rawAll(idSec, pass) {
+export async function idSecPass2rawAll(idSec, pass) {
 	const rawSeed = await saltPass2seed(idSec, pass);
 	const keyPair = seed2keyPair(rawSeed);
 	return {
@@ -25,16 +27,16 @@ function raw2b58(raws) {
 	return result;
 }
 
-async function idSecPass2cleanKeys(idSec, pass) {
+export async function idSecPass2cleanKeys(idSec, pass) {
 	const raw = await idSecPass2rawAll(idSec, pass);
 	return Object.assign(raw2b58(raw), {idSec, password: pass});
 }
 
-function seed2keyPair(seed) {
+export function seed2keyPair(seed) {
 	return generateKeypair(seed);
 }
 
-async function saltPass2seed(idSec, pass) {
+export async function saltPass2seed(idSec, pass) {
 	const options = {
 		logN: 12,
 		r: 16,
@@ -45,10 +47,41 @@ 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}`;
+export function pubKey2shortKey(pubKey) {
+	const pubKeyBegin = pubKey.substr(0, 4);
+	const pubKeyEnd = pubKey.substr(-4, 4);
+	const checksum = pubKey2checksum(pubKey);
+	return `${pubKeyBegin}…${pubKeyEnd}:${checksum}`;
+}
+
+export function pubKey2checksum(b58pubKey, b58viewDependant = false, checksumWithoutLeadingZero = false) {
+	let binPubKey;
+	if (b58viewDependant) binPubKey = b58.decode(b58pubKey);
+	else binPubKey = b58pubKey2bin(b58pubKey);
+	const hash = sha256.digest(sha256.digest(binPubKey));
+	if (checksumWithoutLeadingZero) {
+		let zero = 0
+		while (hash[zero] === 0) zero++;
+		const shorterHash = hash.slice(zero);
+		return b58.encode(shorterHash).substr(0, 3);
+	}
+	return b58.encode(hash).substr(0, 3);
+}
+
+function b58pubKey2bin(b58pubKey) {
+	const binPubKey = new Uint8Array(32);
+	const decoded = b58.decode(b58pubKey);
+	binPubKey.set(decoded, 32 - decoded.length);
+	return binPubKey;
+}
+
+export function checkKey(pubKeyWithChecksum) {
+	const part = pubKeyWithChecksum.split(':');
+	const b58pubKey = part[0];
+	const checkSum = part[1];
+	if (pubKey2checksum(b58pubKey) === checkSum) return true;
+	if (pubKey2checksum(b58pubKey, true) === checkSum) return true;
+	if (pubKey2checksum(b58pubKey, false, true) === checkSum) return true;
+	if (pubKey2checksum(b58pubKey, true, true) === checkSum) return true;
+	throw new Error('Bad checksum');
 }
diff --git a/src/crypto.test.mjs b/src/crypto.test.mjs
index 439c6c10957f58864b20ee70567c23c758599726..6aa4f7ff646de71878261f350b883b09ea6e59da 100644
--- a/src/crypto.test.mjs
+++ b/src/crypto.test.mjs
@@ -1,5 +1,6 @@
 import test from 'ava';
 import * as app from './crypto.mjs';
+import {b58} from "./crypto.mjs";
 
 const idSec = 'a';
 const mdp = 'b';
@@ -8,9 +9,10 @@ const pubKey = 'AoxVA41dGL2s4ogMNdbCw3FFYjFo5FPK36LuiW1tjGbG';
 const secretKey = '3ZsmZhnRv137dS1s7Q3jFGKLTDyhkwguPHfnWBxzDCTTHKWGnYw9zBk3gcCUJCc72TEUuyzM7cqpo7c5LYhs1Qtv';
 const seed = '9eADqX8V6VcPdJCHCVYiE1Vnift9nFNrvr9aTaXA5RJc';
 
-test('b58 should decode/encode well', t => {
-	t.is(app.b58.encode(app.b58.decode(pubKey)), pubKey);
-});
+test('b58 should decode/encode well', t => t.is(app.b58.encode(app.b58.decode(pubKey)), pubKey));
+test('b58 on pubKey with leading 1', t => t.is(app.b58.encode(app.b58.decode('12BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx')), '12BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx'));
+test('b58 on pubKey without leading 1', t => t.is(app.b58.encode(app.b58.decode('2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx')), '2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx'));
+
 test('saltPass2seed should convert salt & password to seed with scrypt', async t => {
 	t.is(app.b58.encode(await app.saltPass2seed(idSec, mdp)), seed);
 });
@@ -38,3 +40,34 @@ test('pubKey2shortKey match RML1…zvSY:3k4', t => {
 	const shortKey = 'RML1…zvSY:3k4';
 	t.is(app.pubKey2shortKey(pubKey), shortKey);
 });
+test('pubKey2checksum RML12butz : 3k4', t => t.is(app.pubKey2checksum('RML12butzV3xZmkWnNAmRwuepKPYvzQ4euHwhHhzvSY'), '3k4'));
+test('pubKey2checksum 12Bj : 8pQ', t => t.is(app.pubKey2checksum('12BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx'), '8pQ'));
+test('pubKey2checksum 2Bjy : 8pQ', t => t.is(app.pubKey2checksum('2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx'), '8pQ'));
+test('pubKey2checksum ascii 2Bjy : 5vi', t => t.is(app.pubKey2checksum('2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx', true), '5vi'));
+test('pubKey2checksum 1111 : 3ud', t => t.is(app.pubKey2checksum('11111111111111111111111111111111'), '3ud'));
+test('pubKey2checksum "" : 3ud', t => t.is(app.pubKey2checksum(''), '3ud'));
+test('pubKey2checksum 1pubKey542 : 1ML', t => t.is(app.pubKey2checksum('1pubKey542'), '1ML'));
+test('pubKey2checksum pubKey542 : 1ML', t => t.is(app.pubKey2checksum('pubKey542'), '1ML'));
+test('pubKey2checksum ascii 1111111111111111111111111pubKey542 : 1ML', t => t.is(app.pubKey2checksum('1111111111111111111111111pubKey542', true), '1ML'));
+test('pubKey2checksum ascii 1pubKey542 : DSs', t => t.is(app.pubKey2checksum('1pubKey542', true), 'DSs'));
+test('pubKey2checksum ascii pubKey542 : DEE', t => t.is(app.pubKey2checksum('pubKey542', true), 'DEE'));
+test('pubKey2checksum checksumWithoutLeadingZero 1pubKey542 : MLT', t => t.is(app.pubKey2checksum('pubKey542', false, true), 'MLT'));
+
+test('checkKey pubKey542:1ML', t => t.true(app.checkKey('pubKey542:1ML')));
+test('checkKey pubKey542:MLT', t => t.true(app.checkKey('pubKey542:MLT')));
+test('checkKey pubKey542:DEE', t => t.true(app.checkKey('pubKey542:DEE')));
+
+test('checkKey 11111111111111111111111pubKey49311:14R', t => t.true(app.checkKey('11111111111111111111111pubKey49311:14R')));
+test('checkKey 11111111111111111111111pubKey49311:4Ru', t => t.true(app.checkKey('11111111111111111111111pubKey49311:4Ru')));
+test('checkKey 111pubKey49311:14R', t => t.true(app.checkKey('111pubKey49311:14R')));
+test('checkKey 11pubKey49311:14R', t => t.true(app.checkKey('11pubKey49311:14R')));
+test('checkKey 1pubKey49311:14R', t => t.true(app.checkKey('1pubKey49311:14R')));
+test('checkKey pubKey49311:14R', t => t.true(app.checkKey('pubKey49311:14R')));
+test('checkKey pubKey49311:4Ru', t => t.true(app.checkKey('pubKey49311:4Ru')));
+test('checkKey pubKey49311:12p', t => t.true(app.checkKey('pubKey49311:12p')));
+test('checkKey pubKey49311:2p7', t => t.true(app.checkKey('pubKey49311:2p7')));
+test('checkKey false 11111111111111111111111pubKey49311:12p', t => t.throws(() => app.checkKey('11111111111111111111111pubKey49311:12p')));
+test('checkKey false 11111111111111111111111pubKey49311:2p7', t => t.throws(() => app.checkKey('11111111111111111111111pubKey49311:2p7')));
+test('checkKey false pubKey49311:111', t => t.throws(() => app.checkKey('pubKey49311:111')));
+
+test('checkKey false 0pubKey49311:any', t => t.throws(() => app.checkKey('0pubKey49311:any')));