diff --git a/src/crypto.mjs b/src/crypto.mjs
index f662b162575d27ae90cb93a0fbde2e2f92419ca7..b6b60b03f6740b1a8a734c9051f542a64cd7aec0 100644
--- a/src/crypto.mjs
+++ b/src/crypto.mjs
@@ -2,7 +2,7 @@
 // Alt deps :  import scrypt from "ecma-nacl/build/lib/scrypt/scrypt.js";
 import nacl from '../generated/vendors/nacl.mjs';
 // Alt import * as ed25519 from '../node_modules/noble-ed25519/index.mjs';
-import {b58,b64} from './basex.mjs';
+import {b58,b64 as _b64} from './basex.mjs';
 
 export {b58};
 import sha from '../node_modules/js-sha256/src/sha256.mjs';
@@ -12,6 +12,25 @@ const sha256 = sha();
 const generateKeypair = nacl.sign.keyPair.fromSeed;
 import scrypt from '../generated/vendors/scrypt.mjs';
 
+export const b64 = {
+	encode:(source)=>{
+		const size = Math.ceil(source.length/3)*3;
+		const sizedArray = new Uint8Array(size);
+
+		if(typeof source === 'string') sizedArray.set((new TextEncoder()).encode(source));
+		else sizedArray.set(source);
+
+		const b64str = _b64.encode(sizedArray).split('');
+		for(let i = 0;i<size-source.length;i++) b64str[b64str.length-1-i] = '=';
+		return b64str.join('');
+	},
+	decode:(b64str)=> {
+		const rawArray = _b64.decode(b64str.replace(/=/g,'A'));
+		const targetSize = Math.trunc(3*b64str.length/4 - ( b64str.length - b64str.replace(/=/g,'').length ));
+		return rawArray.slice(0,targetSize);
+	}
+}
+
 export async function idSecPass2rawAll(idSec, pass) {
 	const rawSeed = await saltPass2seed(idSec, pass);
 	const keyPair = await seed2keyPair(rawSeed);
@@ -114,9 +133,7 @@ export function checkKey(pubKeyWithChecksum) {
 
 export function sign(unsignedDocument,secretKey){
 	const encoder = new TextEncoder();
-	const decoder = new TextDecoder();
-	const rawSign = nacl.sign.detached(encoder.encode(unsignedDocument.trim()), b58secretKey2bin(secretKey));
+	const rawSign = nacl.sign.detached(encoder.encode(unsignedDocument.trim()+'\n'), b58secretKey2bin(secretKey));
 	const b64Sign = b64.encode(rawSign);
-
 	return `${unsignedDocument.trim()}\n${b64Sign}`;
 }
diff --git a/src/crypto.test.mjs b/src/crypto.test.mjs
index 61eac96b8984729468cf5e59b4f58739a3bc1c9e..cca871960fcf6d3f3dcfd7ae00a71046dce11e38 100644
--- a/src/crypto.test.mjs
+++ b/src/crypto.test.mjs
@@ -7,24 +7,30 @@ const mdp = 'b';
 const pubKey = 'AoxVA41dGL2s4ogMNdbCw3FFYjFo5FPK36LuiW1tjGbG';
 const secretKey = '3ZsmZhnRv137dS1s7Q3jFGKLTDyhkwguPHfnWBxzDCTTHKWGnYw9zBk3gcCUJCc72TEUuyzM7cqpo7c5LYhs1Qtv';
 const seed = '9eADqX8V6VcPdJCHCVYiE1Vnift9nFNrvr9aTaXA5RJc';
-const unsignedDocument = `
-Version: 10
+const unsignedDocument = `Version: 10
 Type: Identity
 Currency: duniter_unit_test_currency
 Issuer: AoxVA41dGL2s4ogMNdbCw3FFYjFo5FPK36LuiW1tjGbG
 UniqueID: tic
 Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
 `;
-const signedDocument = `
-Version: 10
+const signedDocument = `Version: 10
 Type: Identity
 Currency: duniter_unit_test_currency
 Issuer: AoxVA41dGL2s4ogMNdbCw3FFYjFo5FPK36LuiW1tjGbG
 UniqueID: tic
 Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
-???
-`;
-test.skip('sign document', async t => t.is(await app.sign(unsignedDocument,secretKey), signedDocument));
+8BZ2NE/d4YO2rOFpJFZdEYTIoSL4uSX9zo6tacpHBcCIlSlhkHTIHbSJNuzLl9uVBIO0skI7NZPxEYXIJGQYBg==`;
+test('sign document', async t => t.is(await app.sign(unsignedDocument,secretKey), signedDocument));
+
+test('b64 should encode Man as TWFu', t => t.is(app.b64.encode('Man'), 'TWFu'));
+test('b64 should encode Ma as TWE=', t => t.is(app.b64.encode('Ma'), 'TWE='));
+test('b64 should encode M as TQ==', t => t.is(app.b64.encode('M'), 'TQ=='));
+test('b64 should decode TWFu as Man', t => t.is((new TextDecoder()).decode(app.b64.decode('TWFu')), 'Man'));
+test('b64 should decode TWE= as Ma', t => t.is((new TextDecoder()).decode(app.b64.decode('TWE=')), 'Ma'));
+// Won't fix test('b64 should decode TWE as Ma', t => t.is((new TextDecoder()).decode(app.b64.decode('TWE')), 'Ma'));
+test('b64 should decode TQ== as M', t => t.is((new TextDecoder()).decode(app.b64.decode('TQ==')), 'M'));
+// Won't fix test('b64 should decode TQ as M', t => t.is((new TextDecoder()).decode(app.b64.decode('TQ')), 'M'));
 
 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'));