Skip to content

tlsnotary/circuits

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This repo contains macros to be assembled into circuits for use in TLSNotary's 2PC.
The main entrypoints are 6 circuits c1.casm ... c7.casm.
Each macro contains a description about what it does.

To assemble the macros into Bristol Fashion circuits 
(https://homes.esat.kuleuven.be/~nsmart/MPC/), run:

node assemble.js 


SOURCES:

casmbundle.js was created from:
    git clone https://github.com/wyatt-howe/macro-circuit-assembler
    cd macro-circuit-assembler/
    git pull origin pull/3/head
    # (this PR hasn't been merged at the time of writing)
    # then comment out line 4 in casm.js --> //const fs = require('fs');
    browserify --ignore fs --standalone CASM casm.js > casmbundle.js

adder64.txt --> https://homes.esat.kuleuven.be/~nsmart/MPC/adder64.txt
aes-128-reverse.txt --> https://github.com/multiparty/jigg/blob/master/circuits/bristol/aes-128-reverse.txt
sha256.txt --> https://homes.esat.kuleuven.be/~nsmart/MPC/sha256.txt


## License
All circuits in this repository are licensed under either of

- [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
- [MIT license](http://opensource.org/licenses/MIT)

at your option.


The circuits c1, c2, c3, c4, c5 compute TLS's PRF starting from the pre-master 
secret and computing "master secret", "expanded keys", "verify_data" for 
Client_Finished, "verify_data" for Server_Finished.
The reason why there are separate circuits instead of one monolithic circuit is 
that some intermediate computations can be done outside of the circuit, 
significantly reducing the size of the circuit.
Here is the description of the all the steps to compute TLS PRF both inside and 
outside the circuit:

1. Parties, having their shares of PMS (the pre-master secret) will compute MS 
(master secret). The corresponding python code is:

seed = str.encode("master secret") + client_random + server_random
a0 = seed
a1 = hmac.new(pms, a0, hashlib.sha256).digest()
a2 = hmac.new(pms, a1, hashlib.sha256).digest()
p1 = hmac.new(pms, a1+seed, hashlib.sha256).digest()
p2 = hmac.new(pms, a2+seed, hashlib.sha256).digest()
ms = (p1+p2)[0:48]

We will be using the notation from https://en.wikipedia.org/wiki/HMAC to explain 
the internals of the HMAC function. HMAC computes an inner hash and an outer hash.

2. Parties provide their inputs for circuit c1. N provides his PMS share and C 
provides his PMS share. The circuit outputs H(pms xor opad) called "pms outer 
hash state" to N and also outputs H(pms xor ipad) called "pms inner hash state" 
to C.

3. The following steps happen outside of the circuit: C computes 
H((pms xor ipad) || a0) called "inner hash" of a1 and passes it to N.

4. N computes a1 and passes it to C.

5. C computes inner hash of a2 and passes it to N.

6. N computes a2 and passes it to C.

7. C computes inner hash of p2 and passes it to N.

8. N computes p2 and passes it to C.
Note that p2 is obtained in the clear, thus both parties know the last 16 bytes 
of MS. It is possible to put this step inside the circuit if needed. But we 
think that revealing 16 bytes of MS while keeping the other 32 bytes secret 
provides adequate security.

9. C computes inner hash of p1.

10. Parties provide their inputs for circuit c2. N provides "pms outer hash 
state" and C provides p2 and inner hash of p1. The circuit computes the master 
secret (MS).

11. The parties proceed to compute the expanded keys (EK). The corresponding 
python code is:

seed = str.encode("key expansion") + server_random + client_random
a0 = seed
a1 = hmac.new(ms , a0, hashlib.sha256).digest()
a2 = hmac.new(ms , a1, hashlib.sha256).digest()
p1 = hmac.new(ms, a1+seed, hashlib.sha256).digest()
p2 = hmac.new(ms, a2+seed, hashlib.sha256).digest()
ek = (p1 + p2)[:40]
client_write_key = ek[:16]
server_write_key = ek[16:32]
client_write_IV = ek[32:36]
server_write_IV = ek[36:40]


12. While still inside the circuit, having computed MS, the circuit now outputs 
H(ms xor opad) called "ms outer hash state" to N and also outputs H(ms xor ipad) 
called "ms inner hash state" to C.

13. The following steps happen outside of the circuit: C computes inner hash of 
a1 and sends it to N.

14. N computes a1 and sends it to C.

15. C computes inner hash of a2 and sends it to N.

16. N computes a2 and sends it to C.

17. C computes inner state of p1 and inner state of p2.

18. The parties provide their inputs to circuit c3. N provides "ms outer hash 
state" (from Step 10) and C provides inner state of p1 and inner state of p2. 
Inside the circuit, p1 and p2 are computed. The circuit outputs xor shares of 
keys and IVs to each party.
The parties provide their shares of keys and IVs to circuit c4. The circuit 
outputs data needed to encrypt and authenticate the Client_Finished.

19. The parties proceed to compute verify_data for the Client_Finished message 
outside of the circuit. The corresponding python code is:

(handshake_hash) is a sha256 hash of all TLS handshake message up to this point
seed = str.encode('client finished') + handshake_hash
a0 = seed
a1 = hmac.new(ms, a0, hashlib.sha256).digest()
p1 = hmac.new(ms, a1+seed, hashlib.sha256).digest()
verify_data = p1[:12]

20. C computes inner hash of a1 and sends it to N.

21. N (who has "ms outer hash state" from Step 10) computes a1 and sends it to C.

22. C computes inner hash of p1 and sends it to N.

23. N computes p1 and gets verify_data and sends it to C.
Note that N's knowing the verify_data for CF does not pose a threat of N 
impersonating the webserver. In the next step C will check the Server_Finished 
for correctness. Since N does not know server_write_key and server_write_iv, 
N cannot forge the Server_Finished.

24. Upon C's receiving the Server_Finished (SF), the parties proceed to compute 
verify_data for SF to check that the received SF is correct. The corresponding 
python code is:

(handshake_hash) is a sha256 hash of all TLS handshake message up to this point
seed = str.encode('server finished') + handshake_hash
a0 = seed
a1 = hmac.new(ms, a0, hashlib.sha256).digest()
p1 = hmac.new(ms, a1+seed, hashlib.sha256).digest()
verify_data = p1[:12]

25. Outside of the circuit, C computes inner hash of a1 and sends it to N.

26. N (who has "ms outer hash state" from Step 10) computes a1 and sends it to C.

27. C computes inner hash of p1.

28. The parties provide their inputs to circuit c5. N provides "ms outer hash 
state" (from Step 10) and C provides inner hash of p1. The circuit outputs 
verify_data for Server_Finished to C.

About

Circuits used for TLSNotary's 2PC

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published