diff --git a/compact_chapoly.py b/compact_xchapoly.py similarity index 76% rename from compact_chapoly.py rename to compact_xchapoly.py index f87cf7a..ca4c045 100644 --- a/compact_chapoly.py +++ b/compact_xchapoly.py @@ -4,23 +4,27 @@ unu=lambda n,l:bytes(n>>i&255 for i in range(0,l,8)) add=lambda x,y:x+y&0xffffffff rotl=lambda x,n:x<>32-n def qr(a,b,c,d):a=add(a,b);d^=a;d=rotl(d,16);c=add(c,d);b^=c;b=rotl(b,12);a=add(a,b);d^=a;d=rotl(d,8);c=add(c,d);b^=c;b=rotl(b,7);return a,b,c,d -def ccb(k,c,n): +def ccb(k,c,n,f): s=[0x61707865,0x3320646e,0x79622d32,0x6b206574,u(k[:4]),u(k[4:8]),u(k[8:12]),u(k[12:16]),u(k[16:20]),u(k[20:24]),u(k[24:28]),u(k[28:]),c,u(n[:4]),u(n[4:8]),u(n[8:])] o=s[:] + if f:o=[0]*16 def x(a,b,c,d):s[a],s[b],s[c],s[d]=qr(s[a],s[b],s[c],s[d]) for _ in range(10):x(0,4,8,12);x(1,5,9,13);x(2,6,10,14);x(3,7,11,15);x(0,5,10,15);x(1,6,11,12);x(2,7,8,13);x(3,4,9,14) return b''.join(unu(add(o[i],s[i]),32)for i in range(len(s))) cd=lambda a,b:a//b if a%b==0 else a//b+1 def chacha20(k,c,n,m): - for i in range(cd(len(m),64)):yield from(a^b for a,b in zip(m[i*64:i*64+64],ccb(k,c+i,n))) + for i in range(cd(len(m),64)):yield from(a^b for a,b in zip(m[i*64:i*64+64],ccb(k,c+i,n,0))) def poly1305(m,k): r=bytearray(k[:16]);r[3]&=15;r[7]&=15;r[11]&=15;r[15]&=15;r[4]&=252;r[8]&=252;r[12]&=252;r=u(r);s=u(k[16:]);P=2**130-5;a=0 for i in range(cd(len(m),16)):a=(a+u(m[i*16:i*16+16]+b'\x01'))*r%P return unu(a+s,128) p16=lambda x:b'\x00'*(-len(x)%16) -tag=lambda a,k,n,c:poly1305(b''.join((a,p16(a),c,p16(c),unu(len(a),64),unu(len(c),64))),ccb(k,0,n)[:32]) -def enc(a,k,n,p):c=bytes(chacha20(k,1,n,p));return c+tag(a,k,n,c) -def dec(a,k,n,e): +tag=lambda a,k,n,c:poly1305(b''.join((a,p16(a),c,p16(c),unu(len(a),64),unu(len(c),64))),ccb(k,0,n,0)[:32]) +def cpe(a,k,n,p):c=bytes(chacha20(k,1,n,p));return c+tag(a,k,n,c) +def cpd(a,k,n,e): c=e[:-16] if not secrets.compare_digest(e[-16:],tag(a,k,n,c)):return None return bytes(chacha20(k,1,n,c)) +def hchacha20(k,n):s=ccb(k,u(n[:4]),n[4:],1);return s[:16]+s[48:] +def enc(a,k,n,p):k=hchacha20(k, n[:16]);n=b'\x00'*4+n[16:];return cpe(a,k,n,p) +def dec(a,k,n,c):k=hchacha20(k, n[:16]);n=b'\x00'*4+n[16:];return cpd(a,k,n,c) diff --git a/test.py b/test.py index c6fb439..13c870a 100644 --- a/test.py +++ b/test.py @@ -1,4 +1,4 @@ -import compact_chapoly +import compact_xchapoly import compact_ecdh_curve25519 def test_chacha20_poly1305(): @@ -11,10 +11,22 @@ def test_chacha20_poly1305(): for test_vector in test_vectors: key, nonce, plaintext, ad, ciphertext, tag = map(bytes.fromhex, test_vector) - assert compact_chapoly.enc(ad, key, nonce, plaintext) == ciphertext + tag - assert compact_chapoly.dec(ad, key, nonce, ciphertext + tag) == plaintext + assert compact_xchapoly.cpe(ad, key, nonce, plaintext) == ciphertext + tag + assert compact_xchapoly.cpd(ad, key, nonce, ciphertext + tag) == plaintext print('chacha20-poly1305: Ok') +def test_xchacha_poly1305(): + test_vectors = [ + ('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f', '404142434445464748494a4b4c4d4e4f5051525354555657', '4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e', '50515253c0c1c2c3c4c5c6c7', 'bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b4522f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff921f9664c97637da9768812f615c68b13b52e', 'c0875924c1c7987947deafd8780acf49'), + ('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f', '404142434445464748494a4b4c4d4e4f5051525354555657', '4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e', '50515253c0c1c2c3c4c5c6c7', 'bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b4522f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff921f9664c97637da9768812f615c68b13b52e', 'c0875924c1c7987947deafd8780acf49') + ] + + for test_vector in test_vectors: + key, nonce, plaintext, ad, ciphertext, tag = map(bytes.fromhex, test_vector) + assert compact_xchapoly.enc(ad, key, nonce, plaintext) == ciphertext + tag + assert compact_xchapoly.dec(ad, key, nonce, ciphertext + tag) == plaintext + print('xchacha20-poly1305: Ok') + def test_ecdh_curve25519(): alice_sk = bytes.fromhex('77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a') alice_pk = compact_ecdh_curve25519.pubkey(alice_sk) @@ -27,4 +39,5 @@ def test_ecdh_curve25519(): if __name__ == '__main__': test_chacha20_poly1305() + test_xchacha_poly1305() test_ecdh_curve25519()