pax_global_header00006660000000000000000000000064147412172700014517gustar00rootroot0000000000000052 comment=960e5969b66c3239d2c7206b6c62a1d45c4f414c liboprf-0.6.1/000077500000000000000000000000001474121727000131605ustar00rootroot00000000000000liboprf-0.6.1/.github/000077500000000000000000000000001474121727000145205ustar00rootroot00000000000000liboprf-0.6.1/.github/workflows/000077500000000000000000000000001474121727000165555ustar00rootroot00000000000000liboprf-0.6.1/.github/workflows/codeql-analysis.yml000066400000000000000000000025611474121727000223740ustar00rootroot00000000000000name: "CodeQL" on: push: branches: [master] pull_request: # The branches below must be a subset of the branches above branches: [master] schedule: - cron: '0 3 * * 2' jobs: analyze: name: Analyze runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 # Override language selection by uncommenting this and choosing your languages # with: # languages: go, javascript, csharp, python, cpp, java # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) #- name: Autobuild # uses: github/codeql-action/autobuild@v1 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language - run: | sudo apt update sudo apt install -y libsodium-dev pkgconf # build-essential git # main liboprf cd src make test - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 liboprf-0.6.1/.github/workflows/python-app.yml000066400000000000000000000025111474121727000213760ustar00rootroot00000000000000# This workflow will install Python dependencies, run tests and lint with a single version of Python # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python name: Python application on: push: branches: [ "master" ] pull_request: branches: [ "master" ] permissions: contents: read jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python 3.10 uses: actions/setup-python@v3 with: python-version: "3.10" - name: Install dependencies run: | python -m pip install --upgrade pip pip install flake8 pytest sudo apt update sudo apt install -y libsodium-dev pkgconf # build-essential git pip install python/ pysodium SecureString cd src sudo PREFIX=/usr make install cd .. - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test with pytest run: | pytest -s -v python/tests/test.py liboprf-0.6.1/.gitignore000066400000000000000000000001401474121727000151430ustar00rootroot00000000000000liboprf.a *.o .arch bench *.pdf matrices liboprf.so dkg thmult toprf tuokms uokms attack tp-dkg liboprf-0.6.1/LICENSE000066400000000000000000000167441474121727000142010ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. liboprf-0.6.1/README.md000066400000000000000000000027021474121727000144400ustar00rootroot00000000000000# liboprf This library implements the basic OPRF(ristretto255, SHA-512) variant from the IRTF CFRG Draft: https://github.com/cfrg/draft-irtf-cfrg-voprf/ Additionally it implements a threshold OPRF variant based on https://eprint.iacr.org/2017/363 by Krawczyk et al. which is compatible with the CFRG OPRF(ristretto255, SHA-512) variant. Furthermore it also implements the 3hashTDH from https://eprint.iacr.org/2024/1455 "Threshold PAKE with Security against Compromise of all Servers" by Gu, Jarecki, Kedzior, Nazarian, Xu. This too is compatible with the CFRG OPRF(ristretto255, SHA-512) variant. For the threshold OPRF this library also provides distributed key-generation (DKG) implementation that is based on a trusted party handling the broadcasts necessary for the DKG, this is based on the JF-DKG (fig 1.) a variant on Pedersens DKG from the paper "Secure Distributed Key Generation for Discrete-Log Based Cryptosystems" by R. Gennaro, S. Jarecki, H. Krawczyk, and T. Rabin. In order to update a threshold OPRF instantiation this library contains the multi-party multiplication is based on Fig. 2 from R. Gennaro, M. O. Rabin, and T. Rabin. "Simplified VSS and fact-track multiparty computations with applications to threshold cryptography" In B. A. Coan and Y. Afek, editors, 17th ACM PODC, pages 101–111. ACM, June / July 1998. Additionally a python wrapper is provided, which can be installed using `pip install pyoprf` This library depends on libsodium. liboprf-0.6.1/docs/000077500000000000000000000000001474121727000141105ustar00rootroot00000000000000liboprf-0.6.1/docs/tp-dkg.txt000066400000000000000000000676531474121727000160600ustar00rootroot00000000000000Trusted-party (TP) Distributed Key Generation (DKG) This document specifies a proposal for a non-robust DKG that can work for small deployments with a small number of parties and infrequent DKG executions. Non-robust means that the protocol succeeds only if no party aborts. If someone aborts then the protocol needs to run again, possibly after kicking out misbehaving parties. This protocol does support maximum 127 peers. This is probably already too much for a non-robust protocol, but it might work in very special circumstances. Broadcast is implemented by the trusted party (TP) opening a channel to each peer secured by the peers long-term encryption key. Every message is routed through the TP. Peer long-term encryption keys can be either TLS-based, or Noise_XK-based (https://noiseexplorer.com/patterns/XK/). In the latter case the long-term public keys must be known and validated in advance by the TP. The basis for this protocol is JF-DKG (fig 1.) a variant on Pedersens DKG from the 2006 paper "Secure Distributed Key Generation for Discrete-Log Based Cryptosystems" by R. Gennaro, S. Jarecki, H. Krawczyk, and T. Rabin [GJKR06]. The algorithm JF-DKG is presented in the paper as a reduced example how an adversary can influence the bits in the generated secret by manipulating the complaints and thus the final composition of the QUAL set, gaining a 3/4 chance to influence a bit. Since in our TP variant is non-robust, we do not allow individual disqualifications of peers, - either all peers qualify or the protocol fails - this mitigates the case where an adversary can adaptively disqualify a peer. Thus the JF-DKG is a simple and sufficient algorithm for our purposes. ------<=[ Rationale ]=>----------- Traditionally DKGs are used in setting where all parties are equal and are using the distributed key together, without having any one party having a different role in the protocol utilizing the shared key. This does not translate entirely to threshold OPRFs (tOPRF) and protocols based on these. In an OPRF there is normally two parties, one holding the key, and another one holding the input and learning the output. In a tOPRF the party holding the key is a group of peers that hold shares of the key in a threshold setting. The whole point of OPRFs is to be able to learn the output for a certain input, without being able to do so without the contribution of the party/parties holding (parts of) the key. Hence the party with the input is in a kind of trusted role, and in many protocols based on OPRFs it is in the best interest of the input-holding party to not learn the key (or its parts) - otherwise the input-holding party could just deploy a PRF instead. And if the input holding party is in such a trusted role, there is two options to generate a threshold shared key: 1. the trusted input-holding party just generates a secret and shares it with the key-holding parties using Shamir's Secret Sharing. This is a very simple approach, with one drawback, the secret itself is however briefly know at the input-holding TP. 2. The input-holding TP can run the simple non-robust DKG specified below. This has the benefit that as long as the protocol is followed precisely the secret is never "assembled" and thus cannot leak, and is never exposed to the TP. Drawback of this is, that the protocol below consists of many rounds of communication. The protocol in this document allows for a variant, were each keyshare-holder generates a completely new set of ephemeral (encryption and signature) keys, and thus allows complete anonymity between the keyshare-holders from each other. While only the TP is aware of the identities of each of the keyshare-holders (by knowing their long-term signature and encryption keys). This increases the security of the whole scheme, as an attacker compromising one keyshare-holder will not be able to learn the identity of the other parties - and more importantly the location of the other keyshares. If this keyshare-holder anonymity is not necessary, steps 3, 4 and the first half of step 5 in the following protocol can be skipped. ------<=[ Prototocol Phases ]=>----------- The protocol has the following phases: 1. Initialization and introduction (step 1 - 5) 2. Setup secure P2P channels (step 5 - 10) 3. core DKG (step 11 - 17) 4. Finish with failure: complaint resolution (only if there are complaints) (step 17 - 19) 5. Finish with success: verification of transcript and completion of protocol (step 20 - 22) ------<=[ Simplified API ]=>----------- Since the protocol consists of many steps, it is recommended to abstract the API to the following schema: 0. Initialize While not done and not error: 1. Allocate input buffers 2. input = receive() 3. allocate output buffer 4. run next step of protocol 5. if there is output: send(output) 6. Post-processing This simple schema simplifies the load of an implementer using this protocol, reducing opportunities for errors and provides strict security. The reference implementation in tp-dkg.c follows this schema for both the TP and the peers. ------<=[ Protocol transcript ]=>----------- Transcript - all broadcast messages are accumulated into a transcript by each peer and the trusted party, at the end of the protocol all parties publish their signed transcripts and only if all signatures are correct and the transcripts match, is the protocol successful. The transcript is a hash, that is initialized with the string: "tp dkg session transcript" in pseudo-code: transcript_state = hash_init("tp dkg session transcript") Updating the transcript first updates the hash with the canonical 32bit size of the message to be added to the transcript, then the message itself is added to the hash. transcript_state = hash_update(transcript_state, I2OSP(len(msg)) transcript_state = hash_update(transcript_state, msg) The signature of each message is similarly added to the transcript. A function `update_ts` can be used as a high-level interface to updating the transcript with messages and their signatures: ``` update_ts(state,msg,sig) state = hash_update(state, I2OSP(len(msg)) state = hash_update(state, msg) state = hash_update(state, I2OSP(len(sig)) state = hash_update(state, sig) return state ``` ------<=[ Session id ]=>----------- Every execution of the protocol starts by the TP sending out a message with a unique and fresh session id, this is to ensure that no messages can be replayed. The session id is a 256 bit (32B) random value of cryptographic quality. ------<=[ Message header ]=>----------- All messages have a message header: uint8 messageno uint32 len uint8 from uint8 to uint64 timestamp uint8 sessionid[32] The first field in the header is really a state identifier. A recipient MUST verify that the messageno is matching with the expected number related to the state of the protocol. The len field MUST be equal to the size of the packet received on the network including the packet header. The `from` field is simply the index of the peer, since peers are indexed starting from 1, the value 0 is used for the trusted party. Any value greater than 128 is invalid. The state defines from whom to receive messages, and thus the from field MUST be validated against these expectations. The `to` field is similar to the `from` field, with the difference that the value 0xff is reserved for broadcast messages. The peer (or TP) MUST validate that it is indeed the recipient of a given message. The timestamp field is just a 64bit timestamp as seconds elapsed since 1970/01/01, for peers that have no accurate clock themselves but do have an RTC, the first initiating message from the TP SHOULD be used as a reference for synchronizing during the protocol. ------<=[ Message signatures ]=>----------- Every message MUST be signed using the sender peers ephemeral signing key. The signature is made over the message and the appended session id. The session id is announced by the TP in the first message. ------<=[ Verifying messages ]=>----------- Whenever a message is received by any participant, they first MUST check the correctness of the signature: ``` msg, sig = recv() sign_pk = sign_keys[expected_sender_id] assert(verify(sign_pk, msg, sig)) ``` The recipient MUST also assert the correctness of all the other header fields: ``` assert(msg.messageno == expected_messageno) assert(msg.from == expected_sender_id) assert(msg.to == (own_peer_id or 0xff)) assert(ref_ts <= msg.ts < ref_ts + timeout)) ref_ts = msg.ts ``` The value `timeout` should be configurable and be set to the smallest value that doesn't cause protocol aborts due to slow responses. If at any step of the protocol the TP receives one or more messages that fail these checks, the TP MUST abort the protocol and report all violating peers to the user. ------<=[ Message transmission ]=>----------- A higher level message transmission interface can be provided, for sending: ``` msg, sig = send_msg(msgno, from, to, sign_sk, session_id, data) ts = timestamp() msg = messageno: msgno, len: len(header) + len(data) + len(sig), from: from, to: to, ts: ts, data sig = sign(sign_sk, msg) return msg, sig ``` And for validating incoming messages: ``` data = recv_msg(msgno, from, to, ref_ts, sign_pk, session_id, msg, sig) assert(verify(sign_pk, msg, sig) assert(msg.messageno == msgno) assert(msg.len == len(msg|sig)) assert(msg.from == from) assert(msg.to == to) assert(ref_ts < msg.ts < ref_ts + timeout)) if msg.to == 0xff: update_ts(state,msg,sig) ``` The parameters `msgno`, `from`, `to`, `session_id` should be the values expected according to the current protocol state. ------<=[ Cheater detection ]=>----------- The TP MUST report to the user all errors that can identify cheating peers in a given step. For each detected cheating peer the TP MUST record the following information: - the current protocol step, - the violating peer, - the other peer involved, and - the type of violation In order to detect other misbehaving peers in the current step, processing for the rest of the SHOULD peers continue until the end of the current step. Any further violations should be recorded as above. Before the next message to the peers is sent, the TP must check if there are no noted violations, if so the TP aborts and reports all violators with their parameters to the user. Abort conditions include any errors detected by recv_msg(), or when the number of complaints is more than t for one peer, or more than t^2 in total, as well any of the checks of the JF-DKG algorithm from GJKR06. ------<=[ The protocol ]=>----------- ------<=[ 0. Precondition ]=>----------- Peers use TLS or TP knows long-term encryption keys for all peers. Client knows long-term signing keys of all peers. ------<=[ 1. DKG Announcement - TP(peers, t, proto_name) ]=>---------- The protocol starts by asking the trusted party (TP) to initiate a new run of the DKG protocol by providing it with: - a list of the peers, - a threshold value, and - protocol instance name used as a domain separation token. The TP then sanity checks these parameters: ``` n = len(peers) assert(2<=t0) ``` The TP then generates a fresh session id, and a hash of the DST. The TP then creates a broadcast message containing the session id, a hash (so that the message is always of fixed size) of the DST, the values N and T and its own public signing key: ``` dst_str = "TP DKG for protocol %s" % proto_name dst = hash(I2OSP(len(dst_str)) | dst_str) sessionid = random_bytes(32) data = {dst, n, t, tp_sign_pk} msg_0, sig_0 = send_msg(0, 0, 0xff, tp_sign_sk, session_id, data) broadcast(msg_0 | sig_0) ``` The TPs copy of the transcript is initialized by the TP, and updated with the value of the 1st broadcast message: ``` state = hash_init("tp dkg session transcript") state = update_ts(state, msg, sig) ``` Since the order of the peers is random, and important for the protocol a custom message is created for each peer by the TP and sent individually notifying each peer of their index in this protocol run. This is essentially an empty message consisting only of a header. The msg.to field conveys the index of the peer. ``` # sending each peer its index for i in 1..n: msg_1, sig_1 = send_msg(1, 0, i, tp_sign_sk, session_id, {}) send(i, msg_1 | sig_1) ``` ------<=[ 2. each peer(msg_0, sig_0) ]=>------------ In this step each peer receives the initial parameter broadcast, verifies it, initializes the transcript and adds the initial message. Then receives the message assigning its index. ``` msg_0, sig_0 = recv() assert(recv_msg(0, 0, 0xff, ref_ts, msg.data.tp_sign_pk, session_id, msg_0, sig_0)) ``` If the peer has no accurate internal clock but has at least an RTC, it SHOULD set the ref_ts to the message timestamp: ``` ref_ts = msg_0.ts ``` Furthermore the peer MUST also verify that the N&T parameters are sane, and if possible the peer SHOULD also check if the session id is fresh (if it is not possible, isfresh() MAY always return true. ``` assert(2 <= msg_0.t < n) assert(isfresh(msg_0,sessionid)) ``` The transcript MUST be initialized by the peer, and updated with the value of the 1st broadcast message: ``` state = hash_init("tp dkg session transcript") state = update_ts(state, msg, sig) ``` After processing the broadcast message from the TP, the peers also have to process the second message from the TP in which they are assigned their index. ``` sig1, msg1 = recv() assert(recv_msg(1, 0, msg1.to, ref_ts, tp_sign_pk, session_id, msg_1, sig_1)) assert(msg1.to <= 128 and msg1.to > 0) peerid = msg.to ``` ------<=[ 3. peers broadcast their keys via TP ]=>------------- If this protocol requires anonymity from each peer all peers broadcast fresh signing and noise keys to all peers via the TP. If no peer-anonymity is required it is ok to either send long-term keys keys here, or skip to the 2nd half or step 5 below. In order to assure the TP that the peer is authentic, this message is additionally signed by the peers long-term signing key - which must be known in advance by the TP. This ensures that the fresh ephemeral keys belong to the peer and not some adversary. ``` peer_sign_sk, peer_sign_pk = sign_genkey() peer_noise_sk, peer_noise_pk = noise_genkey() msg_2, sig_2 = send_msg(2, peerid, 0xff, peer_sign_sk, session_id, {peer_sign_pk, peer_noise_pk}) ltsig = sign(peer_long_term_sig_sk, msg_2|sig_2) broadcast(ltsig | msg_2 | sig_2 ) ``` ------<=[ 4. TP collects and broadcasts all peer keys ]=>------------- The TP first checks if each of the received messages is signed by the expected long-term signing key, if this fails the TP aborts. If all long-term signatures are correct the TP MUST strip those signatures from all the messages. This is to ensure their anonymity from each other. Then the TP acts as a broadcast medium on the long-term signature-stripped messages. This is a recurring pattern where the TP acts in its broadcasting intermediary role: 1. receives the messages from each peer 2. validates the message using recv_msg() 3. extracts all signing pubkeys (or other information depending on the current step) for usage by the TP in the rest of the protocol 4. concatenates all received messages into a new message 5. signs the message of messages 6. adds this the message of messages and its signature to the transcript 7. sends it to all peers ``` peer_sig_pks = [] msgs = [] for i in 1..N ltsig, msg_2, sig_2 = recv() assert(verify(lt_sign_pk[i], msg_2 | sig_2, ltsig)) sig_pk, noise_pk = recv_msg(2, i, 0xff, ref_ts, msg_2.data.peer_sign_pk, session_id, msg_2, sig_2) peer_sig_pks[i] = sig_pk msgs = msgs | { msg_2 , sig_2 } msg_3, sig_3 = send_msg(3, 0, 0xff, tp_sign_sk, session_id, msgs) state = update_ts(state, msg_3, sig_3) broadcast(msg_3|sig_3) ``` ------<=[ 5. each peer get all keys and initiate noise channels with all peers ]=>------- In this phase all peers process the broadcast signing and noise keys received from all peers, and initiate a noise_xk handshake with each of them (including themselves for simplicity and thus security). Note: For performance it MAY be, that each peer only initiates handshakes with peers having a higher index than themselves. But this would create a packet-size and timing side-channel revealing the index of the peer. ``` msg_3, sig_3 = recv() msgs = recv_msg(3, 0, 0xff, ref_ts, tp_sign_pk, session_id, msg_3, sig_3) state = update_ts(state, msg_3, sig_3) peers_sign_pks = [] peers_noise_pks = [] send_session = [] for i in 1..N msg, sig = msgs[i] peers_sign_pks[i], peers_noise_pks[i] = recv_msg(2, i, 0xff, ref_ts, msg.peer_sign_pk, session_id, msg, sig) send_session[i], handshake1 = noisexk_initiator_session(peer_noise_sk, peers_noise_pks[i]) msg, sig = send_msg(4,peerid,i,peer_sign_sk, session_id, handshake1) send(msg | sig) ``` ------<=[ 6. TP routes handshakes from each peer to each peer ]=>------- The TP receives all 1st handshake messages from all peers and routes them correctly to their destination. These messages are not broadcast, each of them is a P2P message. The benefit of the TP forming a star topology here is, that the peers can be on very different physical networks (wifi, lora, uart, nfc, bluetooth, etc) and only the TP needs to be able to connect to all of them. ``` for i in 1..N handshakes = recv(i) for j in 1..N send(j, handshakes[j]) ``` ------<=[ 7. each peer responds to each handshake each peer ]=>------- Peer receives noise handshake1 from each peer and responds with handshake2 answer to each peer. ``` for i in 1..N msg, sig = recv() handshake1 = recv_msg(4, i, peerid, ref_ts, peers_sign_pks[i], session_id, msg, sig) receive_session[i], handshake2 = noisexk_responder_session(peer_noise_sk, handshake1) msg, sig = send_msg(5, peerid, i, peer_sign_sk, session_id, handshake2) send(msg | sig) ``` ------<=[ 8. TP routes handshakes from each peer to each peer ]=>------- TP just routes all P2P messages from all peers to the correct recipients of the messages. ``` for i in 1..N handshakes = recv(i) for j in 1..N send(j, handshakes[j]) ``` ------<=[ 9. each peer completes each handshake with each peer ]=>------- Peers complete the noise handshake. ``` for i in 1..N msg, sig = recv() handshake3 = recv_msg(5, i, peerid, ref_ts, peers_sign_pks[i], session_id, msg, sig) send_session[i] = noisexk_initiator_session_complete(send_session[i], handshake3) ``` ------<=[ 10. Setup complete ]=>------- Each peer has a confidential connection with every peer (including self, for simplicity) The one time this channel is used, when distributing the shares from step 13. The sender uses the initiator interface of the noise session, and the receiver uses the responder interface. ------<=[ 11. each peer executes DKG Round 1 ]=>------- This step is as described by GJKR06 (fig 1. JF-DKG) step 1: Each party P_i (as a dealer) chooses a random polynomial f_i(z) over Z_q of degree t: f_i(z) = a_(i0) + a_(i1)z + ··· + a_(it)z^t P_i broadcasts A_ik = g^(a_ik) mod p for k = 0,... ,t. Each P_i computes the shares s_ij = f_i(j) mod q for j = 1, ... ,n. ``` a = [] A = [] for i in 0..t a[i]=randombytes(32) A[i]=g*a[i] s = [] for i in 1..N for j in 0..t s[i]+=a[j]*i^j msg_6, sig_6 = send_msg(6, peerid, 0xff, peer_sign_sk, session_id, A) send(msg_6 | sig_6) ``` ------<=[ 12. TP collects and broadcasts all A vectors ]=>------- This is another broadcast pattern instance: receive-verify-collect-sign-transcript-broadcast. The TP keeps a copy of all commitments being broadcast. ``` A = [][] msgs = [] for i in 1..N msg_6, sig_6 = recv(i) A[i] = recv_msg(6, i, 0xff, ref_ts, peer_sign_pks[i], session_id, msg_6, sig_6) msgs = msgs | { msg_6 , sig_6 } msg_7, sig_7 = send_msg(7, 0, 0xff, tp_sign_sk, session_id, msgs) state = update_ts(state, msg_7, sig_7) broadcast(msg_7|sig_7) ``` ------<=[ 13. each peer collects all A vectors and distributes their generated shares ]=>------- All peers receive the bundled A commitment messages which have been sent by all peers and re-broadcast by the TP. First the bundle is verified, then each message containing the j-th A commitment vector is also verified. A copy of all A commitment vectors is retained for later usage. Then the share for the j-th peer is sent using the previously established noise channel to the j-th peer. These shares have been already computed in step 11, as per the step 1 of the JF-DKG algorithm from the GJKR06 paper. ``` msg_7, sig_7 = recv() msgs = recv_msg(7, 0, 0xff, ref_ts, tp_sign_pk, session_id, msg_7, sig_7) state = update_ts(state, msg_7, sig_7) A=[][] for i in 1..N msg, sig = msgs[i] A[i] = recv_msg(6, i, 0xff, ref_ts, peer_sign_pks[i], session_id, msg, sig) pkt = noise_send(send_session[i], s[i]) msg, sig = send_msg(8,peerid,i,peer_sign_sk, session_id, pkt) send(msg | sig) ``` ------<=[ 14. TP routes noise protected messages between peers ]=>------- Since all these messages are confidential P2P messages protected by noise, all the TP is doing in this step is routing each packet to its correct destination. For the resolution of complaints and cheater identification, TP keeps a copy of all messages. ``` encrypted_shares = [][] for i in 1..N for j in 1..N msg = recv(i) send(j, msg) encrypted_shares[i][j] = msg ``` ------<=[ 15. each peer executes DKG Round 2 ]=>------- Each peer having received all their shares from all the peers, verifies the messages, and then verifies the shares against the previously broadcast A commitment vectors. For each s_ij, A_i pair that fails, a complaint against the peer producing the conflicting commitment and share is logged in an array, which is broadcast to everyone. This is essentially step 2 from the JF-DKG algorithm described in GJKR06. ``` s=[] for i in 1..N msg, sig = recv() pkt = recv_msg(8, i, peerid, ref_ts, peer_sign_pks[i], session_id, msg, sig) s[i] = noise_recv(receive_session[i], pkt) complaints = [] for i in 1..N v = 0 for k in 0..t v += A[i][k]*peerid*k if (g*s[i] != v) complaints = complaints | i msg, sig = send_msg(9, peerid, 0xff, peer_sign_sk, session_id, len(complaints) | complaints) send(msg | sig) ``` ------<=[ 16. TP collects complaints ]=>------- Another receive-verify-collect-sign-transcribe-broadcast instantiation. The TP keeps a copy of all complaints for the 18th step. If any peer complaints about more than t peers, that complaining peer is a cheater, and must be disqualified. Furthermore if there are in total more than t^2 complaints there are multiple cheaters and the protocol must be aborted and new peers must be chosen in case a rerun is initiated. ``` complaints = [] msgs = [] for i in 1..N msg_9, sig_9 = recv(i) complaints_i = recv_msg(9, i, 0xff, ref_ts, peer_sign_pks[i], session_id, msg_9, sig_9) assert(len(complaints_i) < t) complaints = complaints | complaints_i msgs = msgs | { msg_9 , sig_9 } assert(len(complaints) < t^2) msg_10, sig_10 = send_msg(10, 0, 0xff, tp_sign_sk, session_id, msgs) state = update_ts(state, msg_10, sig_10) broadcast(msg_10|sig_10) ``` The next step of the protocol depends on the number of complaints received, if none then the next step is 21. otherwise 18. If the next TP step is 18 (there are complaints) the next input buffer size depends on the number of complaints against each peer. Each complaint is answered by the symmetric encryption key used to encrypt the share of the accused belonging to the complainer. Each accused packs all answers into one message. ------<=[ 17. Each peer receives all complaints ]=>------- All complaint messages broadcast are received by each peer. If peer_i is being complained about by peer_j, peer_i sends the symmetric encryption key that was used to encrypt s_ij to the TP. This is the first part of step 3. in JF-DKG of GJKR06. There is a slight variation, instead of broadcasting the share, the accused peer reveals the symmetric encryption key that was used to encrypt the share. The TP has a copy of this encrypted message, and with the symmetric encryption key, it can decrypt the originally sent share. This is some kind of poor mans provable encryption. If any complaints have been lodged by any peer the protocol ends here for all the peers. ``` msg_10, sig_10 = recv() msgs = recv_msg(10, 0, 0xff, ref_ts, tp_sign_pk, session_id, msg_10, sig_10) state = update_ts(state, msg_10, sig_10) keys = [] for i in 1..N msg, sig = msgs[i] complaints_len, complaints = recv_msg(9, i, 0xff, ref_ts, peers_sign_pks[i], session_id, msg, sig) for k in 0..complaints_len if complaints[k] == peerid # complaint about current peer, publish key used to encrypt s_ij keys = keys | send_session[i].key if len(keys) > 0 msg_11, sig_11 = send_msg(11, peer, 0x0, peer_sign_sk, session_id, keys) send(msg_11, sig_11) ``` ------<=[ 18. TP collects all s_ij, broadcasts and verifies them ]=>------- In this step TP checks equation 3 from step 2 in JF-DKG of GJKR06. TP also checks if all complaints lodged earlier are answered by the correct s_ij shares. The shares to be verified are decrypted from the previously encrypted messages, using the revealed encryption keys by the accused peers. The protocol ends here, as either the complainer or the accused tried to cheat. ``` for i in 1..N if len(complaints[i]) < 1 continue msg, sig = recv(i) keys = recv_msg(11, i, 0xff, ref_ts, peers_sign_pks[i], session_id, msg, sig) assert(len(keys) == len(complaints[i])) sij=[][] for j, key in keys sij[i][j]=decrypt(key, encrypted_shares[i][j]) for complaint in complaints[i] v = 0 for k in 0..t v += A[i][k]*peerid*k if(g*sij[complaint.from][complaint.data] != v) suspicious = suspicious | identity(i) else suspicious = suspicious | identity(j) ``` ------<=[ 19. Compare all transcripts ]=>------- Each peer calculates the final transcripts and sends it to TP. ``` transcript = final_ts(state) msg_20, sig_20 = send_msg(20, peerid, 0, peer_sign_sk, session_id, transcript) send(msg_20, sig_20) ``` ------<=[ 20. TP receives all and verifies transcripts ]=>------- TP receives all transcripts, and asserts that they all match its own transcript, it aborts if any transcript mismatch is detected. If everything matches tt broadcasts the result either as OK. ``` transcript = final_ts(state) for i in 1..N msg, sig = recv(i) ts = recv_msg(20, i, 0xff, ref_ts, peers_sign_pks[i], session_id, msg, sig) assert( ts == transcript) msg_21, sig_21 = send_msg(21, 0, 0xff, tp_sign_sk, session_id, { "OK" }) ------<=[ 21. SUCCESS, peers set their share and confirm ]=>------- All peers receive the OK acknowledgment from the TP and calculate the final share, this is equivalent with the calculation of x_j in the 4. step in JF-DKG of GJKR06. Finally all peers acknowledge this step with another "OK" message sent to the TP. This is the final step for the peers, each needs to persist the calculated x_j share for usage in later threshold protocol runs (such as tOPRF). ``` msg_21, sig_21 = recv() recv_msg(21, 0, 0xff, ref_ts, tp_sign_pk, session_id, msg_21, sig_21) share = 0 for i in 1..N share += s[i] msg_22, sig_22 = send_msg(22, peerid, 0, peers_sign_sk, session_id, "OK") persist(own_peer_id, share) ``` ------<=[ 22. TP asserts all peers respond with "OK" ]=>------- The TP collects all "OK" messages from all peers. ``` for i in 1..N msg, sig = recv(i) ok = recv_msg(22, i, 0, ref_ts, peers_sign_pks[i], session_id, msg, sig) assert( ok == "OK") ``` This successfully concludes the protocol. liboprf-0.6.1/docs/tp-update.txt000066400000000000000000000037401474121727000165600ustar00rootroot00000000000000Trusted-Party (TP) threshold OPRF key update Protocol This document specifies a proposal for a non-robust threshold OPRF key update protocol that can work for small deployments with a small number of parties and infrequent DKG executions. Non-robust means that the protocol succeeds only if no party aborts. If someone aborts then the protocol needs to run again, possibly after kicking out misbehaving parties. This protocol does support maximum 127 peers. This is probably already too much for a non-robust protocol, but it might work in very special circumstances. Broadcast is implemented by the trusted party (TP) opening a channel to each peer secured by the peers long-term encryption key. Every message is routed through the TP. Peer long-term encryption keys can be either TLS-based, or Noise_XK-based (https://noiseexplorer.com/patterns/XK/). In the latter case the long-term public keys must be known and validated in advance by the TP. The basis for this protocol is the TP-DKG protocol as specified at https://github.com/stef/liboprf/blob/master/docs/tp-dkg.txt, and a Distributed Multiplication protocol which given the sharings of secret a and secret b generates a sharing of the product a·b without learning anything about either secret. The multi-party multiplication is based on Fig. 2 from R. Gennaro, M. O. Rabin, and T. Rabin. "Simplified VSS and fact-track multiparty computations with applications to threshold cryptography" In B. A. Coan and Y. Afek, editors, 17th ACM PODC, pages 101–111. ACM, June / July 1998. 0. TP ensures that n >= 2t+1, otherwise abort. 1. execute TP-DKG for all dealers, if DKG fails, abort 2. dealers (exactly 2t+1 peers) run multiparty multiplication step one, send the results to the corresponding peers 3. TP pre-computes the inverted Van der Monde matrix, and broadcasts the first row. 4. all peers run multiparty multiplication step 2 on inputs from TP and the dealers. 5. all dealers report their shares generated during the DKG, to calculate delta liboprf-0.6.1/misc/000077500000000000000000000000001474121727000141135ustar00rootroot00000000000000liboprf-0.6.1/misc/attack.c000066400000000000000000000074721474121727000155400ustar00rootroot00000000000000// # SPDX-FileCopyrightText: 2024, Marsiske Stefan // # SPDX-License-Identifier: GPL-3.0-or-later // build with // $ gcc -Wall -O3 attack.c -o attack -loprf -lsodium // then run: // $ ./attack test #include // memcmp #include // f?printf #include // uint8_t #include // va_list, va_start, va_end #include #include static const uint8_t k[crypto_core_ristretto255_SCALARBYTES] = {1}; void dump(const uint8_t *p, const size_t len, const char* msg, ...) { va_list args; va_start(args, msg); vfprintf(stderr,msg, args); va_end(args); fprintf(stderr,"\t"); for(size_t i=0;ibeta\n", exec); printf("usage: cat rwd | %s guess password\n", exec); return ret; } static int tamper(const uint8_t alpha[crypto_core_ristretto255_BYTES], uint8_t beta[crypto_core_ristretto255_BYTES]) { puts("tampering"); dump(k, sizeof k, "k"); if(0!=crypto_scalarmult_ristretto255(beta, k, alpha)) { fputs("failed to tamper with k\nabort.\n", stderr); return 1; } return 0; } static int guess(uint8_t rwd[OPRF_BYTES], const uint8_t *pwd, const size_t pwd_len) { //fputs("[1] hashing to group...", stdout); uint8_t h0pwd[crypto_core_ristretto255_BYTES]={0}; if(0!=voprf_hash_to_group(pwd, pwd_len, h0pwd)) { fputs("failed to hash to group\nabort\n", stderr); return 1; } // tamper(h0pwd, h0pwd) uint8_t rwd_[OPRF_BYTES]; if(0!=oprf_Finalize(pwd, pwd_len, h0pwd, rwd_)) { fputs("failed to finalize OPRF\nabort\n", stderr); return 1; } if(memcmp(rwd,rwd_, OPRF_BYTES)!=0) return -1; return 0; } static int test(void) { // regular OPRF flow on the client const uint8_t password[] = "Exploitability of this is low, OPRFs are still cool"; uint8_t alpha[crypto_core_ristretto255_BYTES]={0}; uint8_t r[crypto_core_ristretto255_SCALARBYTES]={0}; if(0!=oprf_Blind(password, sizeof password, r, alpha)) { fputs("failed to blind password\nabort\n", stderr); return 1; } //dump(r, sizeof r, "r"); // we tamper with beta uint8_t beta[crypto_core_ristretto255_BYTES]={0}; dump(alpha, sizeof alpha, "alpha"); tamper(alpha, beta); dump(beta, sizeof beta, "beta"); // regular OPRF flow on the client uint8_t N[crypto_core_ristretto255_BYTES]={0}; int x = oprf_Unblind(r, beta, N); if(0!=x) { fputs("failed to unblind beta\nabort\n", stderr); return 1; } uint8_t rwd[OPRF_BYTES]; if(0!=oprf_Finalize(password, sizeof password, N, rwd)) { fputs("failed to finalize OPRF\nabort\n", stderr); return 1; } // we "intercept" the oprf output and guess candidate inputs fprintf(stderr, "guess(\"%s\") = %d\n", password, guess(rwd, password, sizeof password-1)); fprintf(stderr, "guess(\"%s\") = %d\n", password, guess(rwd, password, sizeof password)); return 0; } int main(const int argc, const char** argv) { if(argc<2) { return usage(argv[0], 0); } if(memcmp(argv[1],"tamper",7)==0) { uint8_t alpha[crypto_core_ristretto255_BYTES]; if(fread(alpha, 1, 32, stdin) != 32) { fputs("failed to read point\nabort.\n", stderr); return 1; } uint8_t beta[crypto_core_ristretto255_BYTES]; if(0!=tamper(alpha, beta)) { return 1; }; fwrite(beta, 1, sizeof beta, stdout); return 0; } if(memcmp(argv[1],"guess",6)==0) { if(argc<3) { return usage(argv[0], 1); } uint8_t rwd[OPRF_BYTES]; if(fread(rwd, 1, OPRF_BYTES, stdin) != OPRF_BYTES) { fputs("failed to read rwd\nabort.\n", stderr); return 1; } return guess(rwd, (uint8_t*) argv[2], strlen(argv[2])); } if(memcmp(argv[1],"test",5)==0) { return test(); } return usage(argv[0], 1); } liboprf-0.6.1/python/000077500000000000000000000000001474121727000145015ustar00rootroot00000000000000liboprf-0.6.1/python/.gitignore000066400000000000000000000000561474121727000164720ustar00rootroot00000000000000pyoprf.egg-info pyoprf/__pycache__ build dist liboprf-0.6.1/python/MANIFEST.in000066400000000000000000000000371474121727000162370ustar00rootroot00000000000000include README.md include *.py liboprf-0.6.1/python/README.md000066400000000000000000000004151474121727000157600ustar00rootroot00000000000000# pyoprf This is the python bindings for liboprf. ## installation you'll need https://github.com/stef/liboprf/ which depends on libsodium. a simple `pip install pyoprf` should suffice to install the bindings. ## usage see the file `test.py` ## License LGPLv3.0+ liboprf-0.6.1/python/examples/000077500000000000000000000000001474121727000163175ustar00rootroot00000000000000liboprf-0.6.1/python/examples/3hashtdh.py000077500000000000000000000014761474121727000204120ustar00rootroot00000000000000#!/usr/bin/env python from pyoprf import keygen, create_shares, blind, evaluate, unblind, thresholdmult from pysodium import randombytes, crypto_core_ristretto255_from_hash, crypto_generichash, crypto_core_ristretto255_add k = keygen() shares = create_shares(k, 5, 3) zero_shares = create_shares(bytes([0]*32), 5, 3) r, alpha = blind(b"test") ssid_S = randombytes(32) betas = [] for ki, zi in zip(shares,zero_shares): h2 = evaluate( zi[1:], crypto_core_ristretto255_from_hash(crypto_generichash(ssid_S + alpha, outlen=64)), ) beta = evaluate(ki[1:], alpha) betas.append(ki[:1]+crypto_core_ristretto255_add(beta, h2)) # normal 2hashdh(k,"test") beta = evaluate(k, alpha) Nt0 = unblind(r, beta) print(Nt0) beta = thresholdmult(betas[:3]) Nt1 = unblind(r, beta) print(Nt1) assert Nt0 == Nt1 liboprf-0.6.1/python/examples/tpdkg_test.py000077500000000000000000000076341474121727000210560ustar00rootroot00000000000000#!/usr/bin/env python """ Test for TP DKG wrapper of pyoprf/liboprf SPDX-FileCopyrightText: 2024, Marsiske Stefan SPDX-License-Identifier: LGPL-3.0-or-later Copyright (c) 2024, Marsiske Stefan. All rights reserved. This file is part of liboprf. liboprf is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liboprf is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with liboprf. If not, see . """ import pyoprf, pysodium, ctypes n = 5 t = 3 ts_epsilon = 5 # enable verbose logging for tp-dkg libc = ctypes.cdll.LoadLibrary('libc.so.6') cstderr = ctypes.c_void_p.in_dll(libc, 'stderr') log_file = ctypes.c_void_p.in_dll(pyoprf.liboprf,'log_file') log_file.value = cstderr.value # create some long-term keypairs peer_lt_pks = [] peer_lt_sks = [] for _ in range(n): pk, sk = pysodium.crypto_sign_keypair() peer_lt_pks.append(pk) peer_lt_sks.append(sk) # initialize the TP and get the first message tp, msg0 = pyoprf.tpdkg_start_tp(n, t, ts_epsilon, "pyoprf tpdkg test", peer_lt_pks) print(f"n: {pyoprf.tpdkg_tpstate_n(tp)}, t: {pyoprf.tpdkg_tpstate_t(tp)}, sid: {bytes(c for c in pyoprf.tpdkg_tpstate_sessionid(tp)).hex()}") # initialize all peers with the 1st message from TP peers=[] for i in range(n): peer = pyoprf.tpdkg_peer_start(ts_epsilon, peer_lt_sks[i], msg0) peers.append(peer) for i in range(n): assert(pyoprf.tpdkg_peerstate_sessionid(peers[i]) == pyoprf.tpdkg_tpstate_sessionid(tp)) assert(peer_lt_sks[i] == pyoprf.tpdkg_peerstate_lt_sk(peers[i])) peer_msgs = [] while pyoprf.tpdkg_tp_not_done(tp): ret, sizes = pyoprf.tpdkg_tp_input_sizes(tp) # peer_msgs = (recv(size) for size in sizes) msgs = b''.join(peer_msgs) cur_step = pyoprf.tpdkg_tpstate_step(tp) try: tp_out = pyoprf.tpdkg_tp_next(tp, msgs) #print(f"tp: msg[{tp[0].step}]: {tp_out.raw.hex()}") except Exception as e: cheaters, cheats = pyoprf.tpdkg_get_cheaters(tp) print(f"Warning during the distributed key generation the peers misbehaved: {sorted(cheaters)}") for k, v in cheats: print(f"\tmisbehaving peer: {k} was caught: {v}") raise ValueError(f"{e} | tp step {cur_step}") peer_msgs = [] while(len(b''.join(peer_msgs))==0 and pyoprf.tpdkg_peer_not_done(peers[0])): for i in range(n): if(len(tp_out)>0): msg = pyoprf.tpdkg_tp_peer_msg(tp, tp_out, i) #print(f"tp -> peer[{i+1}] {msg.hex()}") else: msg = '' out = pyoprf.tpdkg_peer_next(peers[i], msg) if(len(out)>0): peer_msgs.append(out) #print(f"peer[{i+1}] -> tp {peer_msgs[-1].hex()}") tp_out = '' # we are done, let's check the shares shares = [pyoprf.tpdkg_peerstate_share(peers[i]) for i in range(n)] for i, share in enumerate(shares): print(f"share[{i+1}] {share.hex()}") v0 = pyoprf.thresholdmult([bytes([i+1])+pysodium.crypto_scalarmult_ristretto255_base(shares[i][1:]) for i in (0,1,2)]) v1 = pyoprf.thresholdmult([bytes([i+1])+pysodium.crypto_scalarmult_ristretto255_base(shares[i][1:]) for i in (2,0,3)]) assert v0 == v1 v2 = pyoprf.thresholdmult([bytes([i+1])+pysodium.crypto_scalarmult_ristretto255_base(shares[i][1:]) for i in (2,1,4)]) assert v0 == v2 secret = pyoprf.dkg_reconstruct(shares[:t]) #print("secret", secret.hex()) assert v0 == pysodium.crypto_scalarmult_ristretto255_base(secret) # clean up allocated buffers for i in range(n): pyoprf.tpdkg_peer_free(peers[i]) liboprf-0.6.1/python/pyoprf/000077500000000000000000000000001474121727000160205ustar00rootroot00000000000000liboprf-0.6.1/python/pyoprf/__init__.py000077500000000000000000000754641474121727000201540ustar00rootroot00000000000000#!/usr/bin/env python """ Wrapper for liboprf library SPDX-FileCopyrightText: 2023, Marsiske Stefan SPDX-License-Identifier: LGPL-3.0-or-later Copyright (c) 2023, Marsiske Stefan. All rights reserved. This file is part of liboprf. liboprf is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liboprf is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with liboprf. If not, see . """ import ctypes import ctypes.util import pysodium, os import platform from typing import List, Tuple from itertools import zip_longest if "BYZANTINE_DKG" in os.environ: liboprf = ctypes.cdll.LoadLibrary(os.environ['BYZANTINE_DKG']) else: liboprf = ctypes.cdll.LoadLibrary(ctypes.util.find_library('oprf') or ctypes.util.find_library('liboprf')) if not liboprf._name: raise ValueError('Unable to find liboprf') def split_by_n(iterable, n): return list(zip_longest(*[iter(iterable)]*n, fillvalue='')) def __check(code): if code != 0: raise ValueError(f"error: {code}") # (CFRG/IRTF) OPRF section OPRF_BYTES=64 # This function generates an OPRF private key. # # This is almost the KeyGen OPRF function defined in the RFC: since # this lib does not implement V oprf, we don't need a pubkey and so # we don't bother with all that is related. # # @param [out] k - the per-user OPRF private key # void oprf_KeyGen(uint8_t kU[crypto_core_ristretto255_SCALARBYTES]); def keygen() -> bytes: k = ctypes.create_string_buffer(pysodium.crypto_core_ristretto255_SCALARBYTES) liboprf.oprf_KeyGen(k) return k.raw # This function converts input x into an element of the OPRF group, randomizes it # by some scalar r, producing blinded, and outputs (r, blinded). # # This is the Blind OPRF function defined in the RFC. # # @param [in] x - the input value to blind # @param [out] r - an OPRF scalar value used for randomization # @param [out] blinded - a serialized OPRF group element, a byte array of fixed length, # the blinded version of x, an input to oprf_Evaluate # @return The function raises a ValueError if there is something wrong with the inputs. # #int oprf_Blind(const uint8_t *x, const uint16_t x_len, # uint8_t r[crypto_core_ristretto255_SCALARBYTES], # uint8_t blinded[crypto_core_ristretto255_BYTES]); def blind(x: bytes) -> (bytes, bytes): r = ctypes.create_string_buffer(pysodium.crypto_core_ristretto255_SCALARBYTES) blinded = ctypes.create_string_buffer(pysodium.crypto_core_ristretto255_BYTES) __check(liboprf.oprf_Blind(x, ctypes.c_size_t(len(x)), r, blinded)) return r.raw, blinded.raw # This function evaluates input element blinded using private key k, yielding output # element Z. # # This is the Evaluate OPRF function defined in the RFC. # # @param [in] key - a private key - the output of keygen() # @param [in] blinded - a serialized OPRF group element, a byte array # of fixed length, an output of blind() # @param [out] Z - a serialized OPRF group element, a byte array of fixed # length, an input to oprf_Unblind # @return The function raises a ValueError if there is something wrong with the inputs. #int oprf_Evaluate(const uint8_t k[crypto_core_ristretto255_SCALARBYTES], # const uint8_t blinded[crypto_core_ristretto255_BYTES], # uint8_t Z[crypto_core_ristretto255_BYTES]); def evaluate(key: bytes, blinded: bytes) -> bytes: if len(key) != pysodium.crypto_core_ristretto255_SCALARBYTES: raise ValueError("key has incorrect length") if not isinstance(key, bytes): raise ValueError("key is not of type bytes") if len(blinded) != pysodium.crypto_core_ristretto255_BYTES: raise ValueError("blinded param has incorrect length") if not isinstance(blinded, bytes): raise ValueError("blinded is not of type bytes") Z = ctypes.create_string_buffer(pysodium.crypto_core_ristretto255_BYTES) __check(liboprf.oprf_Evaluate(key, blinded, Z)) return Z.raw # This function removes random scalar r from Z, yielding output N. # # This is the Unblind OPRF function defined in the RFC. # # If you do not call finalize() on the result the output is equivalent # to the OPRF protcol we refer to as HashDH - this protocol retains # the algebraic structure of the value, and has weaker security # guarantees, than the full 2HashDH which is equivalent to running # finalize on the output of blind(). The hashDH variant is not # explicitly specified by the CFRG/IRTF specification. This hashDH # variant has one property that makes it interesting: it is an # updateable OPRF - that is if the server updates their key, they can # calculate a public delta value, that can be applied by the client to # the output of blind() and the result will be as if the client and # the server run the OPRF protocol with the original input and the new # key. It is important to note that the delta value is not sensitive, # and can be public. # # @param [in] r - an OPRF scalar value used for randomization in oprf_Blind # @param [in] Z - a serialized OPRF group element, a byte array of fixed length, # an output of oprf_Evaluate # @param [out] N - a serialized OPRF group element with random scalar r removed, # a byte array of fixed length, an input to oprf_Finalize # @return The function raises a ValueError if there is something wrong with the inputs. #int oprf_Unblind(const uint8_t r[crypto_core_ristretto255_SCALARBYTES], # const uint8_t Z[crypto_core_ristretto255_BYTES], # uint8_t N[crypto_core_ristretto255_BYTES]); def unblind(r: bytes, Z: bytes) -> bytes: if len(r) != pysodium.crypto_core_ristretto255_SCALARBYTES: raise ValueError("param r has incorrect length") if not isinstance(r, bytes): raise ValueError("param r is not of type bytes") if len(Z) != pysodium.crypto_core_ristretto255_BYTES: raise ValueError("param Z has incorrect length") if not isinstance(Z, bytes): raise ValueError("param Z is not of type bytes") N = ctypes.create_string_buffer(pysodium.crypto_core_ristretto255_BYTES) __check(liboprf.oprf_Unblind(r, Z, N)) return N.raw # This function computes the OPRF output using input x, N, and domain # separation tag info. # # This is the Finalize OPRF function defined in the RFC. # # @param [in] x - a value used to compute OPRF (the same value that # was used as input to be blinded) # @param [in] N - a serialized OPRF group element, a byte array of fixed length, # an output of oprf_Unblind # @param [out] y - an OPRF output # @return The function raises a ValueError if there is something wrong with the inputs. #int oprf_Finalize(const uint8_t *x, const uint16_t x_len, # const uint8_t N[crypto_core_ristretto255_BYTES], # uint8_t rwdU[OPRF_BYTES]); def finalize(x: bytes, N: bytes) -> bytes: if len(N) != pysodium.crypto_core_ristretto255_BYTES: raise ValueError("param N has incorrect length") if not isinstance(N, bytes): raise ValueError("param N is not of type bytes") y = ctypes.create_string_buffer(OPRF_BYTES) __check(liboprf.oprf_Finalize(x, ctypes.c_size_t(len(x)), N, y)) return y.raw # This function combines unblind() and finalize() as a convenience def unblind_finalize(r: bytes, Z: bytes, x: bytes) -> bytes: return finalize(x, unblind(r,Z)) # TOPRF section TOPRF_Share_BYTES=pysodium.crypto_core_ristretto255_SCALARBYTES+1 TOPRF_Part_BYTES=pysodium.crypto_core_ristretto255_BYTES+1 # This function calculates a lagrange coefficient based on the index # and the indexes of the other contributing shareholders. # # @param [in] index - the index of the shareholder whose lagrange # coefficient we're calculating, must be greater than 0 # # @param [in] peers - list of the shares that contribute to the reconstruction # # @param [out] result - the lagrange coefficient #void coeff(const int index, const int peers_len, const uint8_t peers[peers_len], uint8_t result[crypto_scalarmult_ristretto255_SCALARBYTES]); def coeff(index: int, peers: list) -> bytes: if index < 1: raise ValueError("index must be positive integer") if len(peers) < 2: ValueError("peers must be a list of at least 2 integers") peers_len=ctypes.c_size_t(len(peers)) c = ctypes.create_string_buffer(pysodium.crypto_core_ristretto255_SCALARBYTES) liboprf.coeff(index, peers_len, peers, c) return c.raw # This function creates shares of secret in a (threshold, n) scheme # over the curve ristretto255 # # @param [in] secret - the scalar value to be secretly shared # # @param [in] n - the number of shares created # # @param [in] threshold - the threshold needed to reconstruct the secret # # @param [out] shares - n shares # # @return The function raises a ValueError if there is something wrong with the inputs. #void toprf_create_shares(const uint8_t secret[crypto_core_ristretto255_SCALARBYTES], # const uint8_t n, # const uint8_t threshold, # uint8_t shares[n][TOPRF_Share_BYTES]); bytes_list_t = List[bytes] def create_shares(secret: bytes, n: int, t: int) -> bytes_list_t: if len(secret) != pysodium.crypto_core_ristretto255_SCALARBYTES: raise ValueError("secret has incorrect length") if not isinstance(secret, bytes): raise ValueError("secret is not of type bytes") if n < t: raise ValueError("t cannot be bigger than n") if t < 2: raise ValueError("t must be bigger than 1") shares = ctypes.create_string_buffer(n*TOPRF_Share_BYTES) __check(liboprf.toprf_create_shares(secret, n, t, shares)) return tuple([bytes(s) for s in split_by_n(shares.raw, TOPRF_Share_BYTES)]) # This function recovers the secret in the exponent using lagrange interpolation # over the curve ristretto255 # # The shareholders are not aware if they are contributing to a # threshold or non-threshold oprf evaluation, from their perspective # nothing changes in this approach. # # @param [in] responses - is an array of shares (k_i) multiplied by a # point (P) on the r255 curve # # @param [in] responses_len - the number of elements in the response array # # @param [out] result - the reconstructed value of P multipled by k # # @return The function raises a ValueError if there is something wrong with the inputs. #int toprf_thresholdmult(const size_t response_len, # const uint8_t responses[response_len][TOPRF_Part_BYTES], # uint8_t result[crypto_scalarmult_ristretto255_BYTES]); def thresholdmult(responses: bytes_list_t) -> bytes: if len(responses) < 2: ValueError("responses must be a list of at least 2 integers") if not all(isinstance(r,bytes) for r in responses): raise ValueError("at least one of the responses is not of type bytes") if not all(len(r)==TOPRF_Part_BYTES for r in responses): raise ValueError("at least one of the responses is not of correct size") responses_len=ctypes.c_size_t(len(responses)) responses_buf = ctypes.create_string_buffer(b''.join(responses)) result = ctypes.create_string_buffer(pysodium.crypto_core_ristretto255_BYTES) __check(liboprf.toprf_thresholdmult(responses_len, responses_buf, result)) return result.raw # This function is the efficient threshold version of oprf_Evaluate. # # This function needs to know in advance the indexes of all the # shares that will be combined later in the toprf_thresholdcombine() function. # by doing so this reduces the total costs and distributes them to the shareholders. # # @param [in] k - a private key (for OPAQUE, this is kU, the user's # OPRF private key) # # @param [in] blinded - a serialized OPRF group element, a byte array # of fixed length, an output of oprf_Blind (for OPAQUE, this # is the blinded pwdU, the user's password) # # @param [in] self - the index of the current shareholder # # @param [in] indexes - the indexes of the all the shareholders # contributing to this oprf evaluation, # # @param [in] index_len - the length of the indexes array, # # @param [out] Z - a serialized OPRF group element, a byte array of fixed length, # an input to oprf_Unblind # # @return The function raises a ValueError if there is something wrong with the inputs. #int toprf_Evaluate(const uint8_t k[TOPRF_Share_BYTES], # const uint8_t blinded[crypto_core_ristretto255_BYTES], # const uint8_t self, const uint8_t *indexes, const uint16_t index_len, # uint8_t Z[TOPRF_Part_BYTES]); def threshold_evaluate(k: bytes, blinded: bytes, self: int, indexes: list) -> bytes: if len(k) != TOPRF_Share_BYTES: raise ValueError("param k has incorrect length") if not isinstance(k, bytes): raise ValueError("param k is not of type bytes") if len(blinded) != pysodium.crypto_core_ristretto255_BYTES: raise ValueError("blinded param has incorrect length") if not isinstance(blinded, bytes): raise ValueError("blinded is not of type bytes") if(self>255 or self<1): raise ValueError("self outside valid range") if(not all(i>0 and i<256 for i in indexes)): raise ValueError("index(es) outside valid range") index_len=ctypes.c_uint16(len(indexes)) indexes_buf=ctypes.create_string_buffer(bytes(indexes)) Z = ctypes.create_string_buffer(TOPRF_Part_BYTES) __check(liboprf.toprf_Evaluate(k, blinded, self, indexes_buf, index_len, Z)) return Z.raw # This function is combines the results of the toprf_Evaluate() # function to recover the shared secret in the exponent. # # @param [in] responses - is an array of shares (k_i) multiplied by a point (P) on the r255 curve # # @param [in] responses_len - the number of elements in the response array # # @param [out] result - the reconstructed value of P multipled by k # # @return The function raises a ValueError if there is something wrong with the inputs. #void toprf_thresholdcombine(const size_t response_len, # const uint8_t _responses[response_len][TOPRF_Part_BYTES], # uint8_t result[crypto_scalarmult_ristretto255_BYTES]); def threshold_combine(responses: bytes_list_t) -> bytes: if len(responses) < 2: ValueError("responses must be a list of at least 2 integers") if not all(isinstance(r,bytes) for r in responses): raise ValueError("at least one of the responses is not of type bytes") if not all(len(r)==TOPRF_Part_BYTES for r in responses): raise ValueError("at least one of the responses is not of correct size") responses_len=ctypes.c_size_t(len(responses)) responses_buf = ctypes.create_string_buffer(b''.join(responses)) result = ctypes.create_string_buffer(pysodium.crypto_core_ristretto255_BYTES) __check(liboprf.toprf_thresholdcombine(responses_len, responses_buf, result)) return result.raw #int toprf_3hashtdh(const uint8_t k[TOPRF_Share_BYTES], # const uint8_t z[TOPRF_Share_BYTES], # const uint8_t alpha[crypto_core_ristretto255_BYTES], # const uint8_t *ssid_S, const uint16_t ssid_S_len, # uint8_t beta[TOPRF_Part_BYTES]); def _3hashtdh(k: bytes, z: bytes, alpha: bytes, ssid_S: bytes) -> bytes: if len(k) != TOPRF_Share_BYTES: raise ValueError("param k has incorrect length") if not isinstance(k, bytes): raise ValueError("param k is not of type bytes") if len(z) != TOPRF_Share_BYTES: raise ValueError("param z has incorrect length") if not isinstance(z, bytes): raise ValueError("param z is not of type bytes") if len(alpha) != pysodium.crypto_core_ristretto255_BYTES: raise ValueError("alpha param has incorrect length") if not isinstance(alpha, bytes): raise ValueError("alpha is not of type bytes") if not isinstance(ssid_S, bytes): raise ValueError("ssid_S is not of type bytes") if len(ssid_S) > (1<<16)-1: raise ValueError("ssid_S is too long") ssid_S_len=ctypes.c_uint16(len(ssid_S)) beta = ctypes.create_string_buffer(TOPRF_Part_BYTES) __check(liboprf.toprf_3hashtdh(k, z, alpha, ssid_S, ssid_S_len, beta)) return beta.raw # todo documentation! #int dkg_start(const uint8_t n, # const uint8_t threshold, # uint8_t commitment_hash[dkg_hash_BYTES], # uint8_t commitments[dkg_commitment_BYTES(threshold)], # TOPRF_Share shares[n]); def dkg_start(n : int, t : int) -> (bytes, bytes, bytes_list_t): if n < t: raise ValueError("t cannot be bigger than n") if t < 2: raise ValueError("t must be bigger than 1") shares = ctypes.create_string_buffer(n*TOPRF_Share_BYTES) commitments = ctypes.create_string_buffer(t*pysodium.crypto_core_ristretto255_BYTES) __check(liboprf.dkg_start(n, t, commitments, shares)) shares = tuple([bytes(s) for s in split_by_n(shares.raw, TOPRF_Share_BYTES)]) return commitments.raw, shares #int dkg_verify_commitments(const uint8_t n, # const uint8_t threshold, # const uint8_t self, # const uint8_t commitments[n][threshold*crypto_core_ristretto255_BYTES], # const TOPRF_Share shares[n], # uint8_t fails[n], # uint8_t *fails_len); def dkg_verify_commitments(n: int, t: int, self: int, commitments : bytes_list_t, shares: bytes_list_t) -> bytes: if n < t: raise ValueError("t cannot be bigger than n") if t < 2: raise ValueError("t must be bigger than 1") if self < 1 or self > n: raise ValueError("self must 1 <= self <= n") if len(commitments) != n*t*pysodium.crypto_core_ristretto255_BYTES: raise ValueError(f"signed_commitments must be {n*t*pysodium.crypto_core_ristretto255_BYTES} bytes is instead: {len(commitments)}") shares = b''.join(shares) if len(shares) != n*TOPRF_Share_BYTES: raise ValueError(f"shares must be {TOPRF_Share_BYTES*n} bytes is instead {len(shares)}") shares = ctypes.create_string_buffer(shares) fails = ctypes.create_string_buffer(n) fails_len = ctypes.c_uint8() __check(liboprf.dkg_verify_commitments(n, t, self, commitments, shares, fails, ctypes.byref(fails_len))) return fails[:fails_len.value] #void dkg_finish(const uint8_t n, # const TOPRF_Share shares[n], # const uint8_t self, # TOPRF_Share *xi); def dkg_finish(n: int, shares: List[bytes], self: int, ) -> bytes: if self < 1 or self > n: raise ValueError("self must 1 <= self <= n") shares = b''.join(shares) if len(shares) != n*TOPRF_Share_BYTES: raise ValueError(f"shares must be {TOPRF_Share_BYTES*n} bytes is instead {len(shares)}") shares = ctypes.create_string_buffer(shares) xi = ctypes.create_string_buffer(TOPRF_Share_BYTES) xi[0]=self liboprf.dkg_finish(n, shares, self, xi) return xi.raw #void dkg_reconstruct(const size_t response_len, # const TOPRF_Share responses[response_len][2], # uint8_t result[crypto_scalarmult_ristretto255_BYTES]); def dkg_reconstruct(responses) -> bytes_list_t: rlen = len(responses) responses = ctypes.create_string_buffer(b''.join(responses)) result = ctypes.create_string_buffer(pysodium.crypto_core_ristretto255_BYTES) liboprf.dkg_reconstruct(rlen, responses, result) return result.raw tpdkg_sessionid_SIZE=32 tpdkg_msg0_SIZE = 177 # ( sizeof(TP_DKG_Message) \ # + crypto_generichash_BYTES/*dst*/ \ # + 2 /*n,t*/ \ # + crypto_sign_PUBLICKEYBYTES /* tp_sign_pk */) tpdkg_msg8_SIZE = 256 # (sizeof(TP_DKG_Message) /* header */ \ # + noise_xk_handshake3_SIZE /* 4th&final noise handshake */ \ # + sizeof(TOPRF_Share) /* msg: the noise_xk wrapped share */ \ # + crypto_secretbox_xchacha20poly1305_MACBYTES /* mac of msg */ \ # + crypto_auth_hmacsha256_BYTES /* key-committing mac over msg*/ ) tpdkg_max_err_SIZE = 128 class TP_DKG_Cheater(ctypes.Structure): _fields_ = [('step', ctypes.c_int), ('error', ctypes.c_int), ('peer', ctypes.c_uint8), ('other_peer', ctypes.c_uint8), ('invalid_index', ctypes.c_int), ] #int tpdkg_start_tp(TP_DKG_TPState *ctx, const uint64_t ts_epsilon, # const uint8_t n, const uint8_t t, # const char *proto_name, const size_t proto_name_len, # const size_t msg0_len, TP_DKG_Message *msg0); # # also wraps conveniently: # # void tpdkg_tp_set_bufs(TP_DKG_TPState *ctx, # uint8_t (*commitments)[][crypto_core_ristretto255_BYTES], # uint16_t (*complaints)[], # uint8_t (*suspicious)[], # uint8_t (*tp_peers_sig_pks)[][crypto_sign_PUBLICKEYBYTES], # uint8_t (*peer_lt_pks)[][crypto_sign_PUBLICKEYBYTES], # uint64_t (*last_ts)[]); def tpdkg_start_tp(n, t, ts_epsilon, proto_name, peer_lt_pks): b = ctypes.create_string_buffer(liboprf.tpdkg_tpstate_size()+32) b_addr = ctypes.addressof(b) s_addr = b_addr + (b_addr % 32) state = ctypes.c_void_p(s_addr) if state.value % 32 != 0: raise ValueError("cannot align at 32bytes the TP_DKG_PeerState struct") msg = ctypes.create_string_buffer(tpdkg_msg0_SIZE) __check(liboprf.tpdkg_start_tp(state, ctypes.c_uint64(ts_epsilon), ctypes.c_uint8(n), ctypes.c_uint8(t), proto_name, ctypes.c_size_t(len(proto_name)), ctypes.c_size_t(len(msg.raw)), msg)) peers_sig_pks = ctypes.create_string_buffer(n*pysodium.crypto_sign_PUBLICKEYBYTES) commitments = ctypes.create_string_buffer(n*t*pysodium.crypto_core_ristretto255_BYTES) complaints = ctypes.create_string_buffer(n*n*2) noisy_shares = ctypes.create_string_buffer(n*n*tpdkg_msg8_SIZE) cheaters = (TP_DKG_Cheater * (t*t - 1))() peer_lt_pks = b''.join(peer_lt_pks) last_ts = (ctypes.c_uint64 * n)() liboprf.tpdkg_tp_set_bufs(state, ctypes.byref(commitments), ctypes.byref(complaints), ctypes.byref(noisy_shares), ctypes.byref(cheaters), len(cheaters), ctypes.byref(peers_sig_pks), peer_lt_pks, ctypes.byref(last_ts)) # we need to keep these arrays around, otherwise the gc eats them up. ctx = (state, cheaters, peers_sig_pks, commitments, complaints, noisy_shares, peer_lt_pks, last_ts, b) return ctx, msg.raw #size_t tpdkg_tp_input_size(const TP_DKG_TPState *ctx); def tpdkg_tp_input_size(ctx): return liboprf.tpdkg_tp_input_size(ctx[0]) #int tpdkg_tp_input_sizes(const TP_DKG_TPState *ctx, size_t *sizes); def tpdkg_tp_input_sizes(ctx): sizes = (ctypes.c_size_t * tpdkg_tpstate_n(ctx))() ret = liboprf.tpdkg_tp_input_sizes(ctx[0], ctypes.byref(sizes)) return ret, [x for x in sizes] #size_t tpdkg_tp_output_size(const TP_DKG_TPState *ctx); def tpdkg_tp_output_size(ctx): return liboprf.tpdkg_tp_output_size(ctx[0]) #int tpdkg_tp_next(TP_DKG_TPState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len); def tpdkg_tp_next(ctx, msg): input_len = tpdkg_tp_input_size(ctx) if len(msg) != input_len: raise ValueError(f"input msg is invalid size: {len(msg)}B must be: {input_len}B") output_len = tpdkg_tp_output_size(ctx) output = ctypes.create_string_buffer(output_len) __check(liboprf.tpdkg_tp_next(ctx[0], msg, ctypes.c_size_t(input_len), output, ctypes.c_size_t(output_len))) return output #int tpdkg_tp_peer_msg(const TP_DKG_TPState *ctx, const uint8_t *base, const size_t base_size, const uint8_t peer, const uint8_t **msg, size_t *len); def tpdkg_tp_peer_msg(ctx, base, peer): msg = ctypes.POINTER(ctypes.c_char)() size = ctypes.c_size_t() __check(liboprf.tpdkg_tp_peer_msg(ctx[0], base, len(base.raw), peer, ctypes.byref(msg), ctypes.byref(size))) msg = b''.join([msg[i] for i in range(size.value)]) return msg #int tpdkg_tp_not_done(const TP_DKG_TPState *tp); def tpdkg_tp_not_done(ctx): return liboprf.tpdkg_tp_not_done(ctx[0]) == 1 def tpdkg_get_cheaters(ctx): cheats = [] cheaters = set() for i in range(tpdkg_tpstate_cheater_len(ctx)): err = ctypes.create_string_buffer(tpdkg_max_err_SIZE) p = liboprf.tpdkg_cheater_msg(ctypes.byref(ctx[1][i]), err, tpdkg_max_err_SIZE) if 0 >= p > tpdkg_tpstate_n(ctx): print(f"invalid cheater index: {p}, skipping this entry") continue cheaters.add(p) cheats.append((p, err.raw[:err.raw.find(b'\x00')].decode('utf8'))) return cheaters, cheats liboprf.tpdkg_peerstate_n.restype = ctypes.c_uint8 def tpdkg_peerstate_n(ctx): return liboprf.tpdkg_peerstate_n(ctx[0]) liboprf.tpdkg_peerstate_t.restype = ctypes.c_uint8 def tpdkg_peerstate_t(ctx): return liboprf.tpdkg_peerstate_t(ctx[0]) liboprf.tpdkg_peerstate_sessionid.restype = ctypes.POINTER(ctypes.c_uint8) def tpdkg_peerstate_sessionid(ctx): ptr = liboprf.tpdkg_peerstate_sessionid(ctx[0]) return bytes(ptr[i] for i in range(tpdkg_sessionid_SIZE)) liboprf.tpdkg_peerstate_lt_sk.restype = ctypes.POINTER(ctypes.c_uint8) def tpdkg_peerstate_lt_sk(ctx): ptr = liboprf.tpdkg_peerstate_lt_sk(ctx[0]) return bytes(ptr[i] for i in range(pysodium.crypto_sign_SECRETKEYBYTES)) liboprf.tpdkg_peerstate_share.restype = ctypes.POINTER(ctypes.c_uint8) def tpdkg_peerstate_share(ctx): ptr = liboprf.tpdkg_peerstate_share(ctx[0]) return bytes(ptr[i] for i in range(TOPRF_Share_BYTES)) def tpdkg_peerstate_step(ctx): return liboprf.tpdkg_peerstate_step(ctx[0]) liboprf.tpdkg_tpstate_n.restype = ctypes.c_uint8 def tpdkg_tpstate_n(ctx): return liboprf.tpdkg_tpstate_n(ctx[0]) liboprf.tpdkg_tpstate_t.restype = ctypes.c_uint8 def tpdkg_tpstate_t(ctx): return liboprf.tpdkg_tpstate_t(ctx[0]) liboprf.tpdkg_tpstate_cheater_len.restype = ctypes.c_size_t def tpdkg_tpstate_cheater_len(ctx): return liboprf.tpdkg_tpstate_cheater_len(ctx[0]) liboprf.tpdkg_tpstate_sessionid.restype = ctypes.POINTER(ctypes.c_uint8) def tpdkg_tpstate_sessionid(ctx): ptr = liboprf.tpdkg_tpstate_sessionid(ctx[0]) return bytes(ptr[i] for i in range(tpdkg_sessionid_SIZE)) def tpdkg_tpstate_step(ctx): return liboprf.tpdkg_tpstate_step(ctx[0]) #int tpdkg_start_peer(TP_DKG_PeerState *ctx, const uint64_t ts_epsilon, # const uint8_t peer_lt_sk[crypto_sign_SECRETKEYBYTES], # const TP_DKG_Message *msg0); # # also wraps conveniently # #void tpdkg_peer_set_bufs(TP_DKG_PeerState *ctx, # uint8_t (*peers_sig_pks)[][crypto_sign_PUBLICKEYBYTES], # uint8_t (*peers_noise_pks)[][crypto_scalarmult_BYTES], # Noise_XK_session_t *(*noise_outs)[], # Noise_XK_session_t *(*noise_ins)[], # TOPRF_Share (*shares)[], # TOPRF_Share (*xshares)[], # uint8_t (*commitments)[][crypto_core_ristretto255_BYTES], # uint16_t (*complaints)[], # uint8_t (*my_complaints)[]); def tpdkg_peer_start(ts_epsilon, peer_lt_sk, msg0): b = ctypes.create_string_buffer(liboprf.tpdkg_peerstate_size()+32) b_addr = ctypes.addressof(b) s_addr = b_addr + (b_addr % 32) state = ctypes.c_void_p(s_addr) if state.value % 32 != 0: raise ValueError("cannot align at 32bytes the TP_DKG_PeerState struct") __check(liboprf.tpdkg_start_peer(state, ctypes.c_uint64(ts_epsilon), peer_lt_sk, msg0)) n = tpdkg_peerstate_n([state]) t = tpdkg_peerstate_t([state]) peers_sig_pks = ctypes.create_string_buffer(b"peer_sig_pks", n * pysodium.crypto_sign_PUBLICKEYBYTES) peers_noise_pks = ctypes.create_string_buffer(b"peer_noise_pks", n * pysodium.crypto_scalarmult_BYTES) noise_outs = (ctypes.c_void_p * n)() noise_ins = (ctypes.c_void_p * n)() shares = ctypes.create_string_buffer(n * TOPRF_Share_BYTES) xshares = ctypes.create_string_buffer(n * TOPRF_Share_BYTES) commitments = ctypes.create_string_buffer(n * t * pysodium.crypto_core_ristretto255_BYTES) complaints = ctypes.create_string_buffer(n * n * 2) my_complaints = ctypes.create_string_buffer(n) last_ts = (ctypes.c_uint64 * n)() liboprf.tpdkg_peer_set_bufs(state, ctypes.byref(peers_sig_pks), ctypes.byref(peers_noise_pks), noise_outs, noise_ins, ctypes.byref(shares), ctypes.byref(xshares), ctypes.byref(commitments), ctypes.byref(complaints), ctypes.byref(my_complaints), ctypes.byref(last_ts)) # we need to keep these arrays around, otherwise the gc eats them up. ctx = (state, peers_sig_pks, peers_noise_pks, noise_outs, noise_ins, shares, xshares, commitments, complaints, my_complaints, b, last_ts) return ctx #size_t tpdkg_peer_input_size(const TP_DKG_PeerState *ctx); def tpdkg_peer_input_size(ctx): return liboprf.tpdkg_peer_input_size(ctx[0]) #size_t tpdkg_peer_output_size(const TP_DKG_PeerState *ctx); def tpdkg_peer_output_size(ctx): return liboprf.tpdkg_peer_output_size(ctx[0]) #int tpdkg_peer_next(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len); def tpdkg_peer_next(ctx, msg): input_len = tpdkg_peer_input_size(ctx) if len(msg) != input_len: raise ValueError(f"input msg is invalid size: {len(msg)}B must be: {input_len}B") output_len = tpdkg_peer_output_size(ctx) output = ctypes.create_string_buffer(output_len) __check(liboprf.tpdkg_peer_next(ctx[0], msg, ctypes.c_size_t(input_len), output, ctypes.c_size_t(output_len))) return output.raw #int tpdkg_peer_not_done(const TP_DKG_PeerState *peer); def tpdkg_peer_not_done(ctx): return liboprf.tpdkg_peer_not_done(ctx[0]) == 1 #void tpdkg_peer_free(TP_DKG_PeerState *ctx); def tpdkg_peer_free(ctx): liboprf.tpdkg_peer_free(ctx[0]) liboprf-0.6.1/python/pyoprf/multiplexer.py000077500000000000000000000133311474121727000207500ustar00rootroot00000000000000#!/usr/bin/env python import ssl, socket, select from binascii import a2b_base64 class Peer: def __init__(self, name, addr, type = "SSL", ssl_cert=None, timeout=5): self.name = name self.type = type # currently only TCP or SSL over TCP, but # could be others like dedicated NOISE_XK, # or hybrid mceliece+x25519 over USB or # even UART self.address = addr # Currently only TCP host:port as a tuple self.ssl_cert = ssl_cert self.timeout = timeout self.state = "new" self.fd = None def connect(self): if self.state == "connected": raise ValueError(f"{self.name} is already connected") if self.type not in {"SSL", "TCP"}: raise ValueError(f"Unsupported peer type: {self.type}") if self.type == "SSL": ctx = ssl.create_default_context() ctx.minimum_version = ssl.TLSVersion.TLSv1_2 if(self.ssl_cert): ctx.load_verify_locations(self.ssl_cert) # only for dev, production system should use proper certs! ctx.check_hostname=False # only for dev, production system should use proper certs! ctx.verify_mode=ssl.CERT_NONE # only for dev, production system should use proper certs! else: ctx.load_default_certs() ctx.verify_mode = ssl.CERT_REQUIRED ctx.check_hostname = True s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(self.timeout) if self.type == "SSL": self.fd = ctx.wrap_socket(s, server_hostname=self.address[0]) self.fd.connect(self.address) self.state="connected" def read(self,size): if self.state != "connected": raise ValueError(f"{self.name} cannot read, is not connected") res = [] read = 0 while read= 0} if not fds: raise ValueError("not enough peers left to get enough results") #print("select") r, _,_ =select.select(fds.keys(),[],[],2) #print("select done") if not r: continue #print("got r") for fd in r: idx = fds[fd][0] if idx in responses: continue #print(f"gathering {idx}") pkt = fds[fd][1].read(expectedmsglen) if pkt == b'\x00\x04fail': responses[idx]=None continue if debug: print(f"{idx} got response of {len(pkt)}") tmp = pkt if not proc else proc(pkt) if tmp is None: continue responses[idx]=tmp if set((tuple(e) if isinstance(e,list) else e) for e in responses.values())=={None}: raise ValueError("oracles failed") if None in responses.values(): if debug: print(f"some reponses failed") #return {k:v for k,v in responses.items() if v is not None} return [responses.get(i,None) for i in range(len(self.peers))] #return responses def close(self): for p in self.peers: p.close() liboprf-0.6.1/python/pyoprf/noisexk.py000077500000000000000000000234731474121727000200660ustar00rootroot00000000000000#!/usr/bin/env python """ Wrapper for hacl-star XK_Noise SPDX-FileCopyrightText: 2024, Marsiske Stefan SPDX-License-Identifier: LGPL-3.0-or-later Copyright (c) 2024, Marsiske Stefan. All rights reserved. This file is part of liboprf. liboprf is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liboprf is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with liboprf. If not, see . """ import ctypes import ctypes.util from ctypes import c_void_p, c_ubyte, c_uint32, c_char, c_size_t, POINTER, byref lib = ctypes.cdll.LoadLibrary(ctypes.util.find_library('oprf-noiseXK') or ctypes.util.find_library('liboprf-noiseXK')) if not lib._name: raise ValueError('Unable to find liboprf-noiseXK') libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c') or ctypes.util.find_library('libc')) if not libc._name: raise ValueError('Unable to find libc') KEYSIZE = 32 NOISE_XK_CONF_ZERO = 0 NOISE_XK_AUTH_KNOWN_SENDER_NO_KCI = 2 NOISE_XK_CONF_STRONG_FORWARD_SECRECY = 5 def __check(code): if code != 0: raise ValueError lib.Noise_XK_device_add_peer.restype = c_void_p lib.Noise_XK_device_add_peer.argtypes = [c_void_p, c_void_p, ctypes.c_char_p] def add_peer(device, name, key): return lib.Noise_XK_device_add_peer(device, name, key) def pubkey(privkey): pubkey = ctypes.create_string_buffer(KEYSIZE) lib.Noise_XK_dh_secret_to_public(pubkey, privkey) return pubkey.raw lib.Noise_XK_device_create.restype = c_void_p def create_device(prologue, name, privkey): srlz_key = b'\x00'*KEYSIZE return lib.Noise_XK_device_create(len(prologue), prologue, name, srlz_key, privkey) lib.Noise_XK_peer_get_id.restype = c_void_p lib.Noise_XK_peer_get_id.argtypes = [c_void_p] def get_peerid(peer): return lib.Noise_XK_peer_get_id(peer) lib.Noise_XK_session_create_initiator.restype = c_void_p lib.Noise_XK_session_create_initiator.argtypes = [c_void_p, c_void_p] def create_session_initiator(device, peerid): return lib.Noise_XK_session_create_initiator(device, peerid) lib.Noise_XK_session_create_initiator.restype = c_void_p lib.Noise_XK_session_create_initiator.argtypes = [c_void_p, c_void_p] def create_session_initiator(device, peerid): res = lib.Noise_XK_session_create_initiator(device, peerid) if res == 0: raise ValueError return res lib.Noise_XK_session_create_responder.restype = c_void_p lib.Noise_XK_session_create_responder.argtypes = [c_void_p] def create_session_responder(device): res = lib.Noise_XK_session_create_responder(device) if res == 0: raise ValueError return res lib.Noise_XK_pack_message_with_conf_level.restype = c_void_p lib.Noise_XK_session_write.argtypes = [c_void_p, c_void_p, POINTER(c_uint32), POINTER(POINTER(c_ubyte))] lib.Noise_XK_encap_message_p_free.argtypes = [c_void_p] def initiator_1st_msg(session): encap_msg = lib.Noise_XK_pack_message_with_conf_level(0, 0, 0); msg_len = c_uint32() msg = POINTER(c_ubyte)() if 0!=lib.Noise_XK_session_write(encap_msg, session, byref(msg_len), byref(msg)): raise ValueError lib.Noise_XK_encap_message_p_free(encap_msg) res = bytes(msg[i] for i in range(msg_len.value)) if msg_len.value > 0: libc.free(msg) return res # Noise_XK_session_read(&encap_msg, bob_session, cipher_msg_len, cipher_msg); lib.Noise_XK_session_read.argtypes = [POINTER(c_void_p), c_void_p, c_uint32, POINTER(c_ubyte)] # Noise_XK_unpack_message_with_auth_level(&plain_msg_len, &plain_msg, NOISE_XK_AUTH_ZERO, encap_msg), def responder_1st_msg(session, msg): encap_msg = c_void_p() msg = (c_ubyte * len(msg)).from_buffer(bytearray(msg)) msg_len = c_uint32(len(msg)) if 0 != lib.Noise_XK_session_read(byref(encap_msg), session, msg_len, msg): raise ValueError plain_msg_len = c_uint32() plain_msg = POINTER(c_ubyte)() if not lib.Noise_XK_unpack_message_with_auth_level(byref(plain_msg_len), byref(plain_msg), 0, encap_msg): raise ValueError lib.Noise_XK_encap_message_p_free(encap_msg) if plain_msg_len.value > 0: libc.free(plain_msg) return initiator_1st_msg(session) def initiator_handshake_finish(session, msg): encap_msg = c_void_p() msg = (c_ubyte * len(msg)).from_buffer(bytearray(msg)) msg_len = c_uint32(len(msg)) if 0 != lib.Noise_XK_session_read(byref(encap_msg), session, msg_len, msg): raise ValueError plain_msg_len = c_uint32() plain_msg = POINTER(c_ubyte)() if not lib.Noise_XK_unpack_message_with_auth_level(byref(plain_msg_len), byref(plain_msg), 0, encap_msg): raise ValueError lib.Noise_XK_encap_message_p_free(encap_msg) if plain_msg_len.value > 0: libc.free(plain_msg) def send_msg(session, msg): if isinstance(msg, str): msg = msg.encode('utf8') encap_msg = lib.Noise_XK_pack_message_with_conf_level(NOISE_XK_CONF_STRONG_FORWARD_SECRECY, len(msg), msg); ct_len = c_uint32() ct = POINTER(c_ubyte)() if 0!=lib.Noise_XK_session_write(encap_msg, session, byref(ct_len), byref(ct)): raise ValueError lib.Noise_XK_encap_message_p_free(encap_msg) res = bytes(ct[:ct_len.value]) if ct_len.value > 0: libc.free(ct) return res def read_msg(session, msg): encap_msg = c_void_p() u_bytes = (c_ubyte * (len(msg)))() u_bytes[:] = msg if 0 != lib.Noise_XK_session_read(byref(encap_msg), session, len(msg), u_bytes): raise ValueError plain_msg_len = c_uint32() plain_msg = POINTER(c_ubyte)() if not lib.Noise_XK_unpack_message_with_auth_level(byref(plain_msg_len), byref(plain_msg), NOISE_XK_AUTH_KNOWN_SENDER_NO_KCI, encap_msg): raise ValueError lib.Noise_XK_encap_message_p_free(encap_msg) res = bytes(plain_msg[i] for i in range(plain_msg_len.value)) if plain_msg_len.value > 0: libc.free(plain_msg) return res lib.Noise_XK_session_get_peer_id.restype = c_uint32 lib.Noise_XK_session_get_peer_id.argtypes = [c_void_p] lib.Noise_XK_device_lookup_peer_by_id.restype = c_void_p lib.Noise_XK_device_lookup_peer_by_id.argtypes = [c_void_p, c_uint32] lib.Noise_XK_peer_get_static.argtypes = [(c_char * 32), c_void_p] def get_pubkey(session, device): peerid = lib.Noise_XK_session_get_peer_id(session) peer = lib.Noise_XK_device_lookup_peer_by_id(device, peerid); pubkey = ctypes.create_string_buffer(KEYSIZE) lib.Noise_XK_peer_get_static(pubkey, peer); return pubkey.raw def initiator_session(initiator_privkey, responder_pubkey, iname=None, rname=None, dst=None): if dst is None: dst = b"liboprf-noiseXK" if iname is None: iname = b"initiator" if rname is None: rname = b"responder" initiator_pubkey = pubkey(initiator_privkey) dev = create_device(dst, iname, initiator_privkey) peer = add_peer(dev, rname, responder_pubkey) peerid = get_peerid(peer) session = create_session_initiator(dev, peerid) msg = initiator_1st_msg(session) return session, msg libc.malloc.restype = POINTER(c_ubyte) def responder_session(responder_privkey, auth_keys, msg, dst=None, name=None): if dst is None: dst = b"liboprf-noiseXK" if name is None: name = b"responder" responder_pubkey = pubkey(responder_privkey) dev = create_device(dst, name, responder_privkey) for key, peer in auth_keys: add_peer(dev,peer,key) session = create_session_responder(dev) msg = responder_1st_msg(session, msg) return session, msg def initiator_session_complete(session, msg): return initiator_handshake_finish(session, msg) def test(): from binascii import unhexlify, hexlify # low level alice_privkey = unhexlify("c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552") alice_pubkey = pubkey(alice_privkey) bob_privkey = unhexlify("c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552") bob_pubkey = pubkey(bob_privkey) adev = create_device("liboprf-noiseXK test", "Alice", alice_privkey) bpeer = add_peer(adev, "Bob", bob_pubkey) bobid = get_peerid(bpeer) bdev = create_device("liboprf-noiseXK test", "Bob", bob_privkey) add_peer(bdev, "Alice", alice_pubkey) asession = create_session_initiator(adev, bobid) bsession = create_session_responder(bdev) msg = initiator_1st_msg(asession) msg = responder_1st_msg(bsession, msg) initiator_handshake_finish(asession, msg) ct = send_msg(asession, "hello bob!") pt = read_msg(bsession, ct) peer_pk = get_pubkey(bsession, bdev) print(hexlify(peer_pk)) print(pt) ct = send_msg(bsession, "hello alice!") pt = read_msg(asession, ct) print(pt) # high-level a2session, msg = initiator_session(alice_privkey, bob_pubkey) b2session, msg = responder_session(bob_privkey, [(alice_pubkey, "Alice")], msg) initiator_session_complete(a2session, msg) ct = send_msg(a2session, "hello bob!") pt = read_msg(b2session, ct) print(pt) ct = send_msg(b2session, "hello alice!") pt = read_msg(a2session, ct) print(pt) for _ in range(1000): if ct[0] % 2 == 0: sender = a2session receiver = b2session else: sender = b2session receiver = a2session message = ct[:16+(ct[1]>>4)] * (ct[1] & 0xf) ct = send_msg(sender, message) pt = read_msg(receiver, ct) assert(pt == message) if __name__ == '__main__': test() liboprf-0.6.1/python/setup.py000077500000000000000000000023461474121727000162230ustar00rootroot00000000000000#!/usr/bin/env python # SPDX-FileCopyrightText: 2023, Marsiske Stefan # SPDX-License-Identifier: LGPL-3.0-or-later import os from setuptools import setup, find_packages # Utility function to read the README file. # Used for the long_description. It's nice, because now 1) we have a top level # README file and 2) it's easier to type in the README file than to put a raw # string in below ... def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() setup(name = 'pyoprf', version = '0.6.1', description = 'python bindings for liboprf', license = "LGPLv3", author = 'Stefan Marsiske', author_email = 'toprf@ctrlc.hu', url = 'https://github.com/stef/liboprf/python', long_description=read('README.md'), long_description_content_type="text/markdown", packages=find_packages(), install_requires = ("pysodium", "SecureString"), classifiers = ["Development Status :: 4 - Beta", "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)", "Topic :: Security :: Cryptography", "Topic :: Security", ], #ext_modules = [liboprf], ) liboprf-0.6.1/python/tests/000077500000000000000000000000001474121727000156435ustar00rootroot00000000000000liboprf-0.6.1/python/tests/test.py000077500000000000000000000243741474121727000172110ustar00rootroot00000000000000#!/usr/bin/env python3 import unittest import pyoprf, pysodium, ctypes from binascii import unhexlify from itertools import combinations class TestEndToEnd(unittest.TestCase): def test_cfrg_irtf(self): """CFRG/IRTF spec compliant run""" # Alice blinds the input "test" r, alpha = pyoprf.blind(b"test") # Bob generates a "secret" key k = pyoprf.keygen() # Bob evaluates Alices blinded value with it's key beta = pyoprf.evaluate(k, alpha) # Alice unblinds Bobs evaluation N = pyoprf.unblind(r, beta) # Alice finalizes the calculation y = pyoprf.finalize(b"test", N) # rerun and assert that oprf(k,"test") equals all runs r, alpha = pyoprf.blind(b"test") beta = pyoprf.evaluate(k, alpha) N = pyoprf.unblind(r, beta) y2 = pyoprf.finalize(b"test", N) self.assertEqual(y, y2) def test_cfrg_irtf_testvec1(self): """IRTF/CFRG testvector 1""" x = unhexlify("00") k = unhexlify("5ebcea5ee37023ccb9fc2d2019f9d7737be85591ae8652ffa9ef0f4d37063b0e") out=unhexlify("527759c3d9366f277d8c6020418d96bb393ba2afb20ff90df23fb7708264e2f3ab9135e3bd69955851de4b1f9fe8a0973396719b7912ba9ee8aa7d0b5e24bcf6") r, alpha = pyoprf.blind(x) beta = pyoprf.evaluate(k, alpha) N = pyoprf.unblind(r, beta) y = pyoprf.finalize(x, N) self.assertEqual(y,out) def test_cfrg_irtf_testvec2(self): """IRTF/CFRG testvector 2""" x=unhexlify("5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a") k = unhexlify("5ebcea5ee37023ccb9fc2d2019f9d7737be85591ae8652ffa9ef0f4d37063b0e") out=unhexlify("f4a74c9c592497375e796aa837e907b1a045d34306a749db9f34221f7e750cb4f2a6413a6bf6fa5e19ba6348eb673934a722a7ede2e7621306d18951e7cf2c73") r, alpha = pyoprf.blind(x) beta = pyoprf.evaluate(k, alpha) N = pyoprf.unblind(r, beta) y = pyoprf.finalize(x, N) self.assertEqual(y, out) def test_hashDH_update(self): """HashDH with update example""" # Alice blinds the input "test" r, alpha = pyoprf.blind(b"test") # Bob generates a "secret" key k = pyoprf.keygen() # Bob evaluates Alices blinded value with it's key beta = pyoprf.evaluate(k, alpha) # Alice unblinds Bobs evaluation N = pyoprf.unblind(r, beta) # Bob updates his key, by generating delta delta = pysodium.crypto_core_ristretto255_scalar_random() k2 = pysodium.crypto_core_ristretto255_scalar_mul(k, delta) # Alice updates her previous calculation of N with delta N2 = pysodium.crypto_scalarmult_ristretto255(delta, N) # rerun hashDH to verify if N2 is equal with a full run r, alpha = pyoprf.blind(b"test") beta = pyoprf.evaluate(k2, alpha) N2_ = pyoprf.unblind(r, beta) self.assertEqual(N2, N2_) def test_toprf_sss(self): """tOPRF (hashDH), (3,5), with centrally shared key interpolation at client""" k2 = pyoprf.keygen() shares = pyoprf.create_shares(k2, 5, 3) r, alpha = pyoprf.blind(b"test") #print(' '.join(s.hex() for s in shares)) # we reuse values from te previous test betas = tuple(s[:1]+pyoprf.evaluate(s[1:], alpha) for s in shares) #print(''.join(b.hex() for b in betas)) beta = pyoprf.thresholdmult(betas) Nt = pyoprf.unblind(r, beta) beta = pyoprf.evaluate(k2, alpha) N2 = pyoprf.unblind(r, beta) self.assertEqual(N2, Nt) def test_toprf_tcombine(self): """tOPRF (hashDH), (3,5), with centrally shared key interpolation at servers""" k2 = pyoprf.keygen() shares = pyoprf.create_shares(k2, 5, 3) r, alpha = pyoprf.blind(b"test") indexes=(4,2,1) betas = tuple(pyoprf.threshold_evaluate(shares[i-1], alpha, i, indexes) for i in indexes) beta = pyoprf.threshold_combine(betas) beta = pyoprf.evaluate(k2, alpha) Nt = pyoprf.unblind(r, beta) Nt2 = pyoprf.unblind(r, beta) self.assertEqual(Nt, Nt2) def test_raw_dkg(self): """naked Distributed KeyGen (3,5)""" n = 5 t = 3 mailboxes=[[] for _ in range(n)] commitments=[] for _ in range(n): coms, shares = pyoprf.dkg_start(n,t) commitments.append(coms) for i,s in enumerate(shares): mailboxes[i].append(s) commitments=b''.join(commitments) shares = [] for i in range(n): fails = pyoprf.dkg_verify_commitments(n,t,i+1, commitments, mailboxes[i]) if len(fails) > 0: for fail in fails: print(f"fail: peer {fail}") raise ValueError("failed to verify contributions, aborting") xi = pyoprf.dkg_finish(n, mailboxes[i], i+1) #print(i, xi.hex(), x_i.hex()) shares.append(xi) # test if the final shares all reproduce the same shared `secret` v0 = pyoprf.thresholdmult([bytes([i+1])+pysodium.crypto_scalarmult_ristretto255_base(shares[i][1:]) for i in (0,1,2)]) for peers in combinations(range(1,5), 3): v1 = pyoprf.thresholdmult([bytes([i+1])+pysodium.crypto_scalarmult_ristretto255_base(shares[i][1:]) for i in peers]) self.assertEqual(v0, v1) secret = pyoprf.dkg_reconstruct(shares[:t]) #print("secret", secret.hex()) self.assertEqual(v0, pysodium.crypto_scalarmult_ristretto255_base(secret)) def test_explicit_3hashtdh(self): """toprf based on 2024/1455 [JSPPJ24] https://eprint.iacr.org/2024/1455 using explicit implementation of 3hashtdh""" print("tOPRF (3hashTDH), (3,5), with centrally shared key interpolation at client") k2 = pyoprf.keygen() shares = pyoprf.create_shares(k2, 5, 3) zero_shares = pyoprf.create_shares(bytes([0]*32), 5, 3) r, alpha = pyoprf.blind(b"test") ssid_S = pysodium.randombytes(32) betas = [] for k, z in zip(shares,zero_shares): h2 = pyoprf.evaluate( z[1:], pysodium.crypto_core_ristretto255_from_hash(pysodium.crypto_generichash(ssid_S + alpha, outlen=64)), ) beta = pyoprf.evaluate(k[1:], alpha) betas.append(k[:1]+pysodium.crypto_core_ristretto255_add(beta, h2)) # normal 2hashdh(k2,"test") beta = pyoprf.evaluate(k2, alpha) Nt0 = pyoprf.unblind(r, beta) for peers in combinations(betas, 3): beta = pyoprf.thresholdmult(betas[:3]) Nt1 = pyoprf.unblind(r, beta) self.assertEqual(Nt0, Nt1) def test_native_3hashtdh(self): """toprf based on 2024/1455 [JSPPJ24] https://eprint.iacr.org/2024/1455 using libopr native implementation of 3hashtdh tOPRF (3hashTDH), (3,5), with centrally shared key interpolation at client""" k2 = pyoprf.keygen() shares = pyoprf.create_shares(k2, 5, 3) zero_shares = pyoprf.create_shares(bytes([0]*32), 5, 3) r, alpha = pyoprf.blind(b"test") ssid_S = pysodium.randombytes(32) betas = [] for k, z in zip(shares,zero_shares): betas.append(pyoprf._3hashtdh(k, z, alpha, ssid_S)) beta = pyoprf.evaluate(k2, alpha) Nt0 = pyoprf.unblind(r, beta) for peers in combinations(betas, 3): beta = pyoprf.thresholdmult(betas[:3]) Nt1 = pyoprf.unblind(r, beta) self.assertEqual(Nt0, Nt1) def test_tp_dkg(self): """Trusted Party Distributed KeyGeneration""" n = 5 t = 3 ts_epsilon = 5 # enable verbose logging for tp-dkg #libc = ctypes.cdll.LoadLibrary('libc.so.6') #cstderr = ctypes.c_void_p.in_dll(libc, 'stderr') #log_file = ctypes.c_void_p.in_dll(pyoprf.liboprf,'log_file') #log_file.value = cstderr.value # create some long-term keypairs peer_lt_pks = [] peer_lt_sks = [] for _ in range(n): pk, sk = pysodium.crypto_sign_keypair() peer_lt_pks.append(pk) peer_lt_sks.append(sk) # initialize the TP and get the first message tp, msg0 = pyoprf.tpdkg_start_tp(n, t, ts_epsilon, "pyoprf tpdkg test", peer_lt_pks) print(f"n: {pyoprf.tpdkg_tpstate_n(tp)}, t: {pyoprf.tpdkg_tpstate_t(tp)}, sid: {bytes(c for c in pyoprf.tpdkg_tpstate_sessionid(tp)).hex()}") # initialize all peers with the 1st message from TP peers=[] for i in range(n): peer = pyoprf.tpdkg_peer_start(ts_epsilon, peer_lt_sks[i], msg0) peers.append(peer) for i in range(n): self.assertEqual(pyoprf.tpdkg_peerstate_sessionid(peers[i]), pyoprf.tpdkg_tpstate_sessionid(tp)) self.assertEqual(peer_lt_sks[i], pyoprf.tpdkg_peerstate_lt_sk(peers[i])) peer_msgs = [] while pyoprf.tpdkg_tp_not_done(tp): ret, sizes = pyoprf.tpdkg_tp_input_sizes(tp) # peer_msgs = (recv(size) for size in sizes) msgs = b''.join(peer_msgs) cur_step = pyoprf.tpdkg_tpstate_step(tp) try: tp_out = pyoprf.tpdkg_tp_next(tp, msgs) #print(f"tp: msg[{tp[0].step}]: {tp_out.raw.hex()}") except Exception as e: cheaters, cheats = pyoprf.tpdkg_get_cheaters(tp) print(f"Warning during the distributed key generation the peers misbehaved: {sorted(cheaters)}") for k, v in cheats: print(f"\tmisbehaving peer: {k} was caught: {v}") raise ValueError(f"{e} | tp step {cur_step}") peer_msgs = [] while(len(b''.join(peer_msgs))==0 and pyoprf.tpdkg_peer_not_done(peers[0])): for i in range(n): if(len(tp_out)>0): msg = pyoprf.tpdkg_tp_peer_msg(tp, tp_out, i) #print(f"tp -> peer[{i+1}] {msg.hex()}") else: msg = '' out = pyoprf.tpdkg_peer_next(peers[i], msg) if(len(out)>0): peer_msgs.append(out) #print(f"peer[{i+1}] -> tp {peer_msgs[-1].hex()}") tp_out = '' # we are done, let's check the shares shares = [pyoprf.tpdkg_peerstate_share(peers[i]) for i in range(n)] for i, share in enumerate(shares): print(f"share[{i+1}] {share.hex()}") v0 = pyoprf.thresholdmult([bytes([i+1])+pysodium.crypto_scalarmult_ristretto255_base(shares[i][1:]) for i in (0,1,2)]) for peers_idxs in combinations(range(1,5), 3): v1 = pyoprf.thresholdmult([bytes([i+1])+pysodium.crypto_scalarmult_ristretto255_base(shares[i][1:]) for i in peers_idxs]) self.assertEqual(v0, v1) secret = pyoprf.dkg_reconstruct(shares[:t]) #print("secret", secret.hex()) self.assertEqual(v0, pysodium.crypto_scalarmult_ristretto255_base(secret)) # clean up allocated buffers for i in range(n): pyoprf.tpdkg_peer_free(peers[i]) liboprf-0.6.1/src/000077500000000000000000000000001474121727000137475ustar00rootroot00000000000000liboprf-0.6.1/src/dkg.c000066400000000000000000000147341474121727000146710ustar00rootroot00000000000000#include #include #include #include "toprf.h" #include "utils.h" #include "dkg.h" /* @copyright 2023-24, Stefan Marsiske toprf@ctrlc.hu This file is part of liboprf. liboprf is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liboprf is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the License along with liboprf. If not, see . */ /* warning this is a low-level interface. Do not use directly unless you use it to implement DKG protocols which have proper sessionids and other protections against replay and confused deputy attacks. for an example of a high-level DKG protocol see tp-dkg.[ch] */ // calculates polynomial f(j) given the polynomials threshold coefficients in // array a static void polynom(const uint8_t j, const uint8_t threshold, const uint8_t a[threshold][crypto_core_ristretto255_SCALARBYTES], TOPRF_Share *result) { //f(z) = a_0 + a_1*z + a_2*z^2 + a_3*z^3 + ⋯ + (a_t)*(z^t) result->index=j; // f(z) = result = a[0] +..... memcpy(result->value, a[0], crypto_core_ristretto255_SCALARBYTES); // z = j uint8_t z[crypto_core_ristretto255_SCALARBYTES]={j}; // z^t -> for(int t=1;tvalue, result->value, tmp); } } int dkg_start(const uint8_t n, const uint8_t threshold, uint8_t commitments[threshold][crypto_core_ristretto255_BYTES], TOPRF_Share shares[n]) { uint8_t a[threshold][crypto_core_ristretto255_SCALARBYTES]; if(0!=sodium_mlock(a,sizeof a)) { return -1; } for(int k=0;kvalue, 0, crypto_core_ristretto255_SCALARBYTES); for(int i=0;ivalue, xi->value, shares[i].value); //dump((uint8_t*)&shares[i][0], sizeof(TOPRF_Share), "s[%d,%d] ", qual[i], self); } //dump(xi->value, crypto_core_ristretto255_SCALARBYTES, "x[%d] ", self); } void dkg_reconstruct(const size_t response_len, const TOPRF_Share responses[response_len], uint8_t result[crypto_scalarmult_ristretto255_BYTES]) { uint8_t lpoly[crypto_scalarmult_ristretto255_SCALARBYTES]; uint8_t tmp[crypto_scalarmult_ristretto255_SCALARBYTES]; memset(result,0,crypto_scalarmult_ristretto255_BYTES); uint8_t indexes[response_len]; for(size_t i=0;i #include #define dkg_hash_BYTES crypto_generichash_BYTES #define dkg_commitment_BYTES(threshold) (threshold*crypto_core_ristretto255_BYTES) typedef struct { uint8_t index; uint8_t value[crypto_core_ristretto255_SCALARBYTES]; } __attribute((packed)) TOPRF_Share; #define HASH ((uint8_t) 1) #define COMMITMENT ((uint8_t) 2) typedef struct { uint8_t type; uint8_t index; } __attribute((packed)) DKG_Fail; /** * 1st step in the DKG protocol to be executed by all peers participating. * * @param [in] n - the number of peers participating in the DKG * @param [in] threshold - the threshold (must be greater 1 and less than n) * @param [out] commitments[dkg_signed_commitment_BYTES] - to * be broadcast after receiving all hashes * broadcasts * @param [out] shares[n] - one share for each peer, to be sent * privately to each peer after receving all of the * commitment_hash broadcasts * @return The function returns 0 if everything is correct. */ int dkg_start(const uint8_t n, const uint8_t threshold, uint8_t commitments[threshold][crypto_core_ristretto255_BYTES], TOPRF_Share shares[n]); int dkg_verify_commitment(const uint8_t n, const uint8_t threshold, const uint8_t self, const uint8_t i, const uint8_t commitments[threshold][crypto_core_ristretto255_BYTES], const TOPRF_Share share); int dkg_verify_commitments(const uint8_t n, const uint8_t threshold, const uint8_t self, const uint8_t commitments[n][threshold][crypto_core_ristretto255_BYTES], const TOPRF_Share shares[n], uint8_t fails[n], uint8_t *fails_len); void dkg_finish(const uint8_t n, const TOPRF_Share shares[n], const uint8_t self, TOPRF_Share *xi); void dkg_reconstruct(const size_t response_len, const TOPRF_Share responses[response_len], uint8_t result[crypto_scalarmult_ristretto255_BYTES]); #endif // DKG_H liboprf-0.6.1/src/makefile000066400000000000000000000074651474121727000154630ustar00rootroot00000000000000PREFIX?=/usr/local INCLUDES=-Inoise_xk/include -Inoise_xk/include/karmel -Inoise_xk/include/karmel/minimal CFLAGS?=-march=native -Wall -O2 -g \ -Werror=format-security -Werror=implicit-function-declaration \ -Wformat=2 -Wconversion -Wimplicit-fallthrough \ -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \ -fstack-protector-strong -fasynchronous-unwind-tables -fpic \ -ftrapv -D_GLIBCXX_ASSERTIONS $(DEFINES) LDFLAGS?=-lsodium -loprf-noiseXK -Lnoise_xk CC?=gcc SOEXT?=so STATICEXT?=a SOVER=0 UNAME := $(shell uname -s) ARCH := $(shell uname -m) ifeq ($(UNAME),Darwin) SOEXT=dylib SOFLAGS=-Wl,-install_name,$(DESTDIR)$(PREFIX)/lib/liboprf.$(SOEXT) else CFLAGS+=-Wl,-z,defs -Wl,-z,relro -Wl,-z,noexecstack -Wl,-z,now -Wtrampolines \ -fsanitize=signed-integer-overflow -fsanitize-undefined-trap-on-error #-fstrict-flex-arrays=3 -mbranch-protection=standard SOEXT=so SOFLAGS=-Wl,-soname,liboprf.$(SOEXT).$(SOVER) ifeq ($(ARCH),x86_64) CFLAGS+=-fcf-protection=full endif ifeq ($(ARCH),parisc64) else ifeq ($(ARCH),parisc64) else CFLAGS+=-fstack-clash-protection endif endif CFLAGS+=$(INCLUDES) SOURCES=oprf.c toprf.c dkg.c utils.c tp-dkg.c mpmult.c $(EXTRA_SOURCES) OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) all: liboprf.$(SOEXT) liboprf.$(STATICEXT) noise_xk/liboprf-noiseXK.$(SOEXT) debug: DEFINES=-DTRACE debug: all asan: CFLAGS=-fsanitize=address -static-libasan -g -march=native -Wall -O2 -g -fstack-protector-strong -fpic -Werror=format-security -Werror=implicit-function-declaration -Wl, -z,noexecstack ifeq ($(ARCH),x86_64) CFLAGS+=-fcf-protection=full endif ifeq ($(ARCH),parisc64) else ifeq ($(ARCH),parisc64) else CFLAGS+=-fstack-clash-protection endif asan: LDFLAGS+= -fsanitize=address -static-libasan asan: all AR ?= ar liboprf.$(SOEXT): $(SOURCES) noise_xk/liboprf-noiseXK.$(SOEXT) $(CC) $(CFLAGS) -fPIC -shared $(SOFLAGS) -o $@ $^ $(LDFLAGS) liboprf-corrupt-dkg.$(SOEXT): $(SOURCES) noise_xk/liboprf-noiseXK.$(SOEXT) $(CC) $(CFLAGS) -DUNITTEST -DUNITTEST_CORRUPT -fPIC -shared $(SOFLAGS) -o $@ $^ $(LDFLAGS) liboprf.$(STATICEXT): $(OBJECTS) $(AR) rcs $@ $^ noise_xk/liboprf-noiseXK.$(SOEXT): make -C noise_xk all noise_xk/liboprf-noiseXK.$(STATICEXT): make -C noise_xk all clean: rm -f *.o liboprf.$(SOEXT) liboprf.$(STATICEXT) liboprf-corrupt-dkg.$(SOEXT) make -C tests clean make -C noise_xk clean install: install-oprf install-noiseXK install-oprf: $(DESTDIR)$(PREFIX)/lib/liboprf.$(SOEXT) $(DESTDIR)$(PREFIX)/lib/liboprf.$(STATICEXT) $(DESTDIR)$(PREFIX)/include/oprf/oprf.h $(DESTDIR)$(PREFIX)/include/oprf/toprf.h $(DESTDIR)$(PREFIX)/include/oprf/dkg.h $(DESTDIR)$(PREFIX)/include/oprf/tp-dkg.h install-noiseXK: make -C noise_xk install uninstall: uninstall-oprf uninstall-noiseXK uninstall-oprf: $(DESTDIR)$(PREFIX)/lib/liboprf.$(SOEXT) $(DESTDIR)$(PREFIX)/lib/liboprf.$(STATICEXT) $(DESTDIR)$(PREFIX)/include/oprf/oprf.h $(DESTDIR)$(PREFIX)/include/oprf/toprf.h $(PREFIX)/include/oprf/dkg.h rm $^ rmdir $(PREFIX)/include/oprf/ uninstall-noiseXK: make -C noise_xk uninstall $(DESTDIR)$(PREFIX)/lib/liboprf.$(SOEXT): liboprf.$(SOEXT) mkdir -p $(DESTDIR)$(PREFIX)/lib cp $< $@.$(SOVER) ln -sf $@.$(SOVER) $@ $(DESTDIR)$(PREFIX)/lib/liboprf.$(STATICEXT): liboprf.$(STATICEXT) mkdir -p $(DESTDIR)$(PREFIX)/lib cp $< $@ $(DESTDIR)$(PREFIX)/include/oprf/oprf.h: oprf.h mkdir -p $(DESTDIR)$(PREFIX)/include/oprf cp $< $@ $(DESTDIR)$(PREFIX)/include/oprf/toprf.h: toprf.h mkdir -p $(DESTDIR)$(PREFIX)/include/oprf cp $< $@ $(DESTDIR)$(PREFIX)/include/oprf/dkg.h: dkg.h mkdir -p $(DESTDIR)$(PREFIX)/include/oprf cp $< $@ $(DESTDIR)$(PREFIX)/include/oprf/tp-dkg.h: tp-dkg.h mkdir -p $(DESTDIR)$(PREFIX)/include/oprf cp $< $@ test: liboprf-corrupt-dkg.$(SOEXT) liboprf.$(STATICEXT) noise_xk/liboprf-noiseXK.$(STATICEXT) make -C tests tests make -C noise_xk test PHONY: clean liboprf-0.6.1/src/mpmult.c000066400000000000000000000246721474121727000154440ustar00rootroot00000000000000#include #include #include #include "toprf.h" #ifdef UNIT_TEST #include "utils.h" #endif /** Implements the Simple-Mult algorithm from page 5 fig. 2 of "Simplified VSS and Fast-track Multiparty Computations with Applications to Threshold Cryptography" by Gennaro, Rabin, Rabin, 1998. */ typedef struct { uint8_t index; uint8_t value[crypto_core_ristretto255_SCALARBYTES]; } __attribute((packed)) TOPRF_Share; static int cmp(uint8_t a[crypto_core_ristretto255_SCALARBYTES], uint8_t b[crypto_core_ristretto255_SCALARBYTES]) { // non-const time! but its ok, this operates on the vandermonde matrix, no secrets involved for(int i=crypto_core_ristretto255_SCALARBYTES-1;i>=0;i--) { if(a[i]>b[i]) return 1; if(a[i]0) {// a[i][j] > c1 memcpy(c1,&a[i][j],crypto_core_ristretto255_SCALARBYTES); } } memcpy(&c[i],c1,crypto_core_ristretto255_SCALARBYTES); } uint8_t k=0; for(uint8_t j=0;j pi1? if(cmp(pi0,pi1)>0) {// pi0 > pi1 memcpy(pi1,pi0,crypto_core_ristretto255_SCALARBYTES); k=i; } } // swap index[j] and index[k] uint8_t prev_index_j=index[j]; index[j] = index[k]; index[k] = prev_index_j; for(uint8_t i=j+1; i=0; j--) { memcpy(&x[j][i], &b[index[j]][i], crypto_core_ristretto255_SCALARBYTES); for(int k = j+1; kindex!=b->index || peersvalue, b->value); //dump(ab, sizeof ab, "ab"); toprf_create_shares(ab, peers, threshold, shares); //for(unsigned j=0;jindex=peer; uint8_t tmp[crypto_core_ristretto255_SCALARBYTES]; for(unsigned i=0;ivalue, share->value, tmp); } //dump(share->value, sizeof share->value, "share"); } static int vsps_check(const uint8_t t, const uint8_t A[t][crypto_core_ristretto255_BYTES], const uint8_t λ[t+1][t+1][crypto_core_ristretto255_SCALARBYTES], const uint8_t δ_exp[t+1][crypto_core_ristretto255_SCALARBYTES], uint8_t v[crypto_core_ristretto255_BYTES]) { // calculates Π(A_i ^ Δ_i), where i=1..t+1, Δ_i = Σ(λ_ji * δ^j, j= 0..t // v = 0 memset(v, 0,crypto_core_ristretto255_BYTES); for(int i=0;i<=t;i++) { uint8_t Δi[crypto_core_ristretto255_SCALARBYTES]={0}; for(int j=0;j<=t;j++) { // calculate λ_ji * δ^j uint8_t tmp[crypto_core_ristretto255_SCALARBYTES]; #ifdef UNIT_TEST dump(λ[j][i], crypto_core_ristretto255_SCALARBYTES, "vdm[%d,%d]", j, i); dump(δ_exp[j], crypto_core_ristretto255_SCALARBYTES, "d^%d", j); #endif crypto_core_ristretto255_scalar_mul(tmp, λ[j][i], δ_exp[j]); // Δ_i = sum_(j=0..t) (λ_ji * δ^j) crypto_core_ristretto255_scalar_add(Δi, Δi, tmp); } #ifdef UNIT_TEST dump(Δi,sizeof Δi, "Δ%d", i); #endif uint8_t tmp[crypto_core_ristretto255_BYTES]; // A_i ^ Δ_i if(0!=crypto_scalarmult_ristretto255(tmp, Δi, A[i])) return 1; #ifdef UNIT_TEST dump(tmp, crypto_scalarmult_ristretto255_BYTES, "A%d^Δ%d", i, i); #endif // Π, but we are in an additive group crypto_core_ristretto255_add(v, v, tmp); } return 0; } int toprf_mpc_vsps_check(const uint8_t t, const uint8_t A[t*2][crypto_core_ristretto255_BYTES]) { uint8_t indexes[t+1]; // p8para3L2: A0..At & At+1..A2t+1 // left-hand side of the equation (1) for(int i=0;i<=t;i++) indexes[i]=i; // left side of equation Π i:=1..t, which is a typo? should be 0..t uint8_t λ[t+1][t+1][crypto_core_ristretto255_SCALARBYTES]; invertedVDMmatrix(t+1,indexes,λ); #ifdef UNIT_TEST fprintf(stderr,"vdm1\n"); for(int i=0;i #include #include "toprf.h" /** generates an inverted Van der Monde matrix */ void invertedVDMmatrix(const uint8_t dealers, const uint8_t indexes[dealers], uint8_t inverted[dealers][dealers][crypto_core_ristretto255_SCALARBYTES]); /** * This function is the first phase of a multiparty threshold * multiplication * * This function is called by each shareholder contributing to the * calculation. * * @param [in] a - One of the shares held by the shareholder * contributing to the multiplication. * * @param [in] b - The other one of the shares held by the shareholder * contributing to the multiplication. * * @param [in] peers - the number of shareholders cooperating in this * computation, should be equal to the number of shareholders holding * shares of a and b. * * @param [in] threshold - the number of shareholders minimum * necessary to parcipate in this computation. Should be the same as * the threshold for the a and b values. * * @param [out] Z - The output shares containing a sharing of * a*b. Each of those shares should be distributed to the shareholder * indicated in the index of the share. * * @return The function returns 0 if everything is correct. */ int toprf_mpc_mul_start(const uint8_t _a[TOPRF_Share_BYTES], const uint8_t _b[TOPRF_Share_BYTES], const uint8_t peers, const uint8_t threshold, uint8_t shares[peers][TOPRF_Share_BYTES]); /** * This function is the second phase of a multiparty threshold * multiplication * * This function is called by each shareholder contributing to the * calculation. At the end of this function a share is returned that * contributes to the value a*b from the first phase. * * @param [in] peers - the number of shareholders cooperating in this * computation, should be equal to the number of shareholders holding * shares of a and b. * * @param [in] indexes of the sender of each share in shares * * @param [in] peer the index of the shareholder executing the * computation. * * @param [in] shares - all the shares from phase 1 for this * shareholder. * * @param [out] shre - The output share, which can reconstruct the * value of a*b. * * @return The function returns 0 if everything is correct. */ void toprf_mpc_mul_finish(const uint8_t dealers, const uint8_t indexes[dealers], const uint8_t peer, const uint8_t shares[dealers][TOPRF_Share_BYTES], uint8_t _share[TOPRF_Share_BYTES]); // todo document API int toprf_mpc_vsps_check(const uint8_t t, const uint8_t A[t*2][crypto_core_ristretto255_BYTES]); #endif // THMULT_H liboprf-0.6.1/src/noise_xk/000077500000000000000000000000001474121727000155665ustar00rootroot00000000000000liboprf-0.6.1/src/noise_xk/.gitignore000066400000000000000000000001041474121727000175510ustar00rootroot00000000000000liboprf-noiseXK.a liboprf-noiseXK.so liboprf-noiseXK.so.0 xk-ex *.o liboprf-0.6.1/src/noise_xk/README.md000066400000000000000000000005471474121727000170530ustar00rootroot00000000000000libsodiumized version of `XK_25519_ChaChaPoly_BLAKE2b` extracted from https://github.com/Inria-Prosecco/noise-star git revision `38ad46c4e1adc048f8b9002c2265a96b961eb702` karmel directory contains the necessary includes https://github.com/project-everest/hacl-star git version `e5620ceb7c8a4996520d693f597872806dc0a1d3` see noise-star.patch for all changes liboprf-0.6.1/src/noise_xk/example/000077500000000000000000000000001474121727000172215ustar00rootroot00000000000000liboprf-0.6.1/src/noise_xk/example/authorized_keys000066400000000000000000000005441474121727000223600ustar00rootroot00000000000000cWGtl4rxhY8S1uFh2Gfyi4d4B1BBoxKXpX5oAqsn3SQ= stf wLjHJ6njZIpaAuxQ2mK1OjLhYkHu0GGjm/HFfSi5iyM= alice auL719iakN0Uh9X1XSjsNgmMSYrbLUQHRJmjKuuqRHc= robert LvujMt01+k/1YQ19tIyLXdnqZlabtyPQv8+EZLKeBVA= rob kQH8j5UPJLcQfDEDGYS3NavVobgiov9dHVZ2v5JMGgo= robby NHBPri2k+EhTY+RKaKAlTXpxuQ7mKSxeRZ1stVeDLy0= robbie pN7KA3MPHU4Y9tmMcgsWjhYUuz1Kalk6KtAasr17+2w= bobbie liboprf-0.6.1/src/noise_xk/example/makefile000066400000000000000000000017011474121727000207200ustar00rootroot00000000000000LDFLAGS=-lsodium -loprf-noiseXK SOURCES=xk-ex.c ../../utils.c CFLAGS ?= -I../.. -I../include -I ../include/karmel -I ../include/karmel/minimal \ -Wall -Wextra -Werror -std=c11 -Wno-unused-variable \ -Wno-unknown-warning-option -Wno-unused-but-set-variable \ -Wno-unused-parameter -Wno-infinite-recursion -fPIC \ -g -fwrapv -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM \ -O2 -fstack-protector-strong -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \ -fasynchronous-unwind-tables -fpic -Werror=format-security \ -Werror=implicit-function-declaration -Wl,-z,defs -Wl,-z,relro \ -ftrapv -Wl,-z,noexecstack ARCH := $(shell uname -m) ifeq ($(ARCH),x86_64) CFLAGS+=-fcf-protection=full endif ifeq ($(ARCH),parisc64) else ifeq ($(ARCH),parisc64) else CFLAGS+=-fstack-clash-protection endif all: xk-ex xk-ex: $(SOURCES) $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) -L.. AR ?= ar test: xk-ex LD_LIBRARY_PATH=.. ./xk-ex clean: rm -rf *.o xk-ex liboprf-0.6.1/src/noise_xk/example/xk-ex.c000066400000000000000000000256431474121727000204330ustar00rootroot00000000000000#include #include #include #include #include "XK.h" #include "utils.h" #include #include typedef Noise_XK_device_t device; typedef Noise_XK_session_t session; typedef Noise_XK_peer_t peer; typedef Noise_XK_encap_message_t encap_message; typedef Noise_XK_rcode rcode; typedef uint32_t peer_id; // Using XK with: // - DH: Curve25519 // - AEAD: ChaChaPoly // - Hash: SHA256 #define AEAD_KEY_SIZE 32 #define DH_KEY_SIZE 32 #define HASH_SIZE 32 #define PSK_SIZE 32 #define RETURN_IF_ERROR(e, msg) if (!(e)) { printf("Error: %s\n", msg); return 1; } // Symmetric key used by Alice for serialization/deserialization uint8_t alice_srlz_key[AEAD_KEY_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; // Alice's DH keys uint8_t alice_spriv[DH_KEY_SIZE] = { 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 }; uint8_t alice_spub[DH_KEY_SIZE] = { 0 }; // Symmetric key used by Bob for serialization/deserialization uint8_t bob_srlz_key[AEAD_KEY_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; // Bob's DH keys uint8_t bob_spriv[DH_KEY_SIZE] = { 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 }; uint8_t bob_spub[DH_KEY_SIZE] = { 0 }; extern int debug; static int load_authkeys(const char *path, device *dev) { FILE *stream; char *line = NULL; size_t len = 0; ssize_t nread; int ret = 0; stream = fopen(path, "r"); if (stream == NULL) { perror("fopen authorized_keys file"); return 1; } while ((nread = getline(&line, &len, stream)) != -1) { int i; for(i=0;i 0) free(cipher_msg); if (plain_msg_len > 0) free(plain_msg); // # Step 2: Send an empty message from Bob to Alice. // Very similar to step 1. // ## Bob: generate the message encap_msg = Noise_XK_pack_message_with_conf_level(NOISE_XK_CONF_ZERO, 0, NULL); res = Noise_XK_session_write(encap_msg, bob_session, &cipher_msg_len, &cipher_msg); RETURN_IF_ERROR(Noise_XK_rcode_is_success(res), "Send message 1"); Noise_XK_encap_message_p_free(encap_msg); // ## Alice: read the message fprintf(stderr, "len of msg2: %d\n", cipher_msg_len); res = Noise_XK_session_read(&encap_msg, alice_session, cipher_msg_len, cipher_msg); RETURN_IF_ERROR(Noise_XK_rcode_is_success(res), "Receive message 1"); RETURN_IF_ERROR( Noise_XK_unpack_message_with_auth_level(&plain_msg_len, &plain_msg, NOISE_XK_AUTH_ZERO, encap_msg), "Unpack message 1"); Noise_XK_encap_message_p_free(encap_msg); if (cipher_msg_len > 0) free(cipher_msg); if (plain_msg_len > 0) free(plain_msg); // # Step 3 : Send a confidential message from Alice to Bob // By now, Alice should have reached the best security level. // Send a secret message, and request the highest confidentiality // guarantees. // ## Alice: generate the message // We request strong forward secrecy encap_msg = Noise_XK_pack_message_with_conf_level(NOISE_XK_CONF_STRONG_FORWARD_SECRECY, 11, (uint8_t*) "Hello Bob!"); //encap_msg = Noise_XK_pack_message_with_conf_level(NOISE_XK_CONF_STRONG_FORWARD_SECRECY, 0, NULL); res = Noise_XK_session_write(encap_msg, alice_session, &cipher_msg_len, &cipher_msg); RETURN_IF_ERROR(Noise_XK_rcode_is_success(res), "Send message 2"); Noise_XK_encap_message_p_free(encap_msg); // ## Bob: read the message // We request the highest authentication guarantees (known sender, no KCI). fprintf(stderr, "len of msg3: %d\n", cipher_msg_len); res = Noise_XK_session_read(&encap_msg, bob_session, cipher_msg_len, cipher_msg); RETURN_IF_ERROR(Noise_XK_rcode_is_success(res), "Receive message 2"); // digging out alices spub: peer_id peer_id = Noise_XK_session_get_peer_id(bob_session); Noise_XK_peer_t *peer = Noise_XK_device_lookup_peer_by_id(bob_device, peer_id); uint8_t pubkey[32]; Noise_XK_peer_get_static(pubkey, peer); dump(pubkey, sizeof pubkey, "peers spub: "); RETURN_IF_ERROR( Noise_XK_unpack_message_with_auth_level(&plain_msg_len, &plain_msg, NOISE_XK_AUTH_KNOWN_SENDER_NO_KCI, encap_msg), "Unpack message 2"); Noise_XK_encap_message_p_free(encap_msg); if (cipher_msg_len > 0) free(cipher_msg); printf("%s\n",plain_msg); if (plain_msg_len > 0) free(plain_msg); // # Step 4: Send a confidential message from Bob to Alice. // Same for Bob: we can now send messages with the highest confidentiality level. // ## Bob: generate the message (request max confidentiality) encap_msg = Noise_XK_pack_message_with_conf_level(NOISE_XK_CONF_STRONG_FORWARD_SECRECY, 11, (uint8_t*) "Hello Alice!"); res = Noise_XK_session_write(encap_msg, bob_session, &cipher_msg_len, &cipher_msg); RETURN_IF_ERROR(Noise_XK_rcode_is_success(res), "Send message 3"); Noise_XK_encap_message_p_free(encap_msg); // ## Alice: read the message (request max authentication) res = Noise_XK_session_read(&encap_msg, alice_session, cipher_msg_len, cipher_msg); RETURN_IF_ERROR(Noise_XK_rcode_is_success(res), "Receive message 3"); RETURN_IF_ERROR( Noise_XK_unpack_message_with_auth_level(&plain_msg_len, &plain_msg, NOISE_XK_AUTH_KNOWN_SENDER_NO_KCI, encap_msg), "Unpack message 3"); Noise_XK_encap_message_p_free(encap_msg); if (cipher_msg_len > 0) free(cipher_msg); if (plain_msg_len > 0) free(plain_msg); /* * Cleanup */ // Free the sessions, then the devices Noise_XK_session_free(alice_session); Noise_XK_session_free(bob_session); Noise_XK_device_free(alice_device); Noise_XK_device_free(bob_device); printf("Success!\n"); return 0; } liboprf-0.6.1/src/noise_xk/include/000077500000000000000000000000001474121727000172115ustar00rootroot00000000000000liboprf-0.6.1/src/noise_xk/include/Noise_XK.h000066400000000000000000000052261474121727000210460ustar00rootroot00000000000000/** This file was automatically generated */ #ifndef __Noise_XK_H #define __Noise_XK_H #include #include "krml/internal/target.h" #include "krml/internal/types.h" #ifndef WITH_HACL #include #else // WITH_SODIUM #include "Hacl.h" #endif // WITH_SODIUM #define Noise_XK_CSuccess 0 #define Noise_XK_CIncorrect_transition 1 #define Noise_XK_CPremessage 2 #define Noise_XK_CNo_key 3 #define Noise_XK_CAlready_key 4 #define Noise_XK_CRs_rejected_by_policy 5 #define Noise_XK_CRs_not_certified 6 #define Noise_XK_CAlready_peer 7 #define Noise_XK_CPeer_conflict 8 #define Noise_XK_CUnknown_peer_id 9 #define Noise_XK_CInput_size 10 #define Noise_XK_CDH_error 11 #define Noise_XK_CDecrypt_error 12 #define Noise_XK_CSaturated_nonce 13 #define Noise_XK_CEphemeral_generation 14 #define Noise_XK_CSecurity_level 15 typedef uint8_t Noise_XK_error_code; bool Noise_XK_lbytes_eq(uint32_t len, uint8_t *b1, uint8_t *b2); typedef struct Noise_XK_sized_buffer_s { uint32_t size; uint8_t *buffer; } Noise_XK_sized_buffer; uint64_t Noise_XK_bytes_to_nonce(uint8_t *n8); #define Noise_XK_Handshake_read 0 #define Noise_XK_Handshake_write 1 #define Noise_XK_Transport 2 typedef uint8_t Noise_XK_status; typedef uint8_t *Noise_XK_noise_string; typedef Noise_XK_noise_string *Noise_XK_hstring; Noise_XK_error_code Noise_XK_dh_secret_to_public(uint8_t *dest, uint8_t *priv); Noise_XK_error_code Noise_XK_dh(uint8_t *dest, uint8_t *priv, uint8_t *pub); void Noise_XK_aead_encrypt( uint8_t *key, uint64_t nonce, uint32_t aad_len, uint8_t *aad, uint32_t plen, uint8_t *plain, uint8_t *cipher ); Noise_XK_error_code Noise_XK_aead_decrypt( uint8_t *key, uint64_t nonce, uint32_t aad_len, uint8_t *aad, uint32_t plen, uint8_t *plain, uint8_t *cipher ); void Noise_XK_hash(uint8_t *output, uint32_t inlen, uint8_t *input); void Noise_XK_mix_hash(uint8_t *hash1, uint32_t inlen, uint8_t *input); void Noise_XK_hmac(uint8_t *output, uint32_t keylen, uint8_t *key, uint32_t datalen, uint8_t *data); void Noise_XK_kdf( uint8_t *hash1, uint32_t keylen, uint8_t *key, uint8_t *dst1, uint8_t *dst2, uint8_t *dst3 ); void Noise_XK_mix_psk(uint8_t *psk, uint8_t *st_cs_k, uint8_t *st_ck, uint8_t *st_h); void Noise_XK_encrypt_and_hash( uint32_t msg_len, uint8_t *msg, uint8_t *cipher, uint8_t *st_cs_k, uint8_t *st_h, uint64_t nonce ); Noise_XK_error_code Noise_XK_decrypt_and_hash( uint32_t msg_len, uint8_t *msg, uint8_t *cipher, uint8_t *st_cs_k, uint8_t *st_h, uint64_t nonce ); Noise_XK_error_code Noise_XK_mix_dh(uint8_t *sec, uint8_t *pub, uint8_t *cipher_key, uint8_t *ck, uint8_t *hash1); #define __Noise_XK_H_DEFINED #endif liboprf-0.6.1/src/noise_xk/include/XK.h000066400000000000000000000345471474121727000177210ustar00rootroot00000000000000/** This file was automatically generated */ #ifndef __XK_H #define __XK_H #include #include "krml/internal/target.h" #include "krml/internal/types.h" #ifdef WITH_HACL #include "Hacl.h" #endif // WITH_SODIUM #include "Noise_XK.h" #define Noise_XK_Success 0 #define Noise_XK_Error 1 #define Noise_XK_Stuck 2 typedef uint8_t Noise_XK_rcode_tags; typedef struct Noise_XK_rcode_s { Noise_XK_rcode_tags tag; union { Noise_XK_error_code case_Error; Noise_XK_error_code case_Stuck; } val; } Noise_XK_rcode; bool Noise_XK_uu___is_Success(Noise_XK_rcode projectee); bool Noise_XK_uu___is_Error(Noise_XK_rcode projectee); Noise_XK_error_code Noise_XK___proj__Error__item___0(Noise_XK_rcode projectee); bool Noise_XK_uu___is_Stuck(Noise_XK_rcode projectee); Noise_XK_error_code Noise_XK___proj__Stuck__item___0(Noise_XK_rcode projectee); typedef uint8_t Noise_XK_conf_level_t; typedef uint8_t Noise_XK_auth_level_t; #define NOISE_XK_AUTH_ZERO ((uint8_t)0U) #define NOISE_XK_AUTH_KNOWN_SENDER ((uint8_t)1U) #define NOISE_XK_AUTH_KNOWN_SENDER_NO_KCI ((uint8_t)2U) #define NOISE_XK_MAX_AUTH_LEVEL ((uint8_t)2U) #define NOISE_XK_CONF_ZERO ((uint8_t)0U) #define NOISE_XK_CONF_KNOWN_RECEIVER ((uint8_t)2U) #define NOISE_XK_CONF_KNOWN_RECEIVER_NON_REPLAYABLE ((uint8_t)3U) #define NOISE_XK_CONF_STRONG_FORWARD_SECRECY ((uint8_t)5U) #define NOISE_XK_MAX_CONF_LEVEL ((uint8_t)5U) #define Noise_XK_Auth_level 0 #define Noise_XK_Conf_level 1 #define Noise_XK_No_level 2 typedef uint8_t Noise_XK_ac_level_t_tags; typedef struct Noise_XK_ac_level_t_s { Noise_XK_ac_level_t_tags tag; union { uint8_t case_Auth_level; uint8_t case_Conf_level; } val; } Noise_XK_ac_level_t; bool Noise_XK_uu___is_Auth_level(Noise_XK_ac_level_t projectee); uint8_t Noise_XK___proj__Auth_level__item__l(Noise_XK_ac_level_t projectee); bool Noise_XK_uu___is_Conf_level(Noise_XK_ac_level_t projectee); uint8_t Noise_XK___proj__Conf_level__item__l(Noise_XK_ac_level_t projectee); bool Noise_XK_uu___is_No_level(Noise_XK_ac_level_t projectee); typedef struct Noise_XK_encap_message_t_s Noise_XK_encap_message_t; typedef Noise_XK_encap_message_t *Noise_XK_encap_message_p_or_null; Noise_XK_encap_message_t *Noise_XK___proj__Mkencap_message_p_or_null__item__emp(Noise_XK_encap_message_t *projectee); bool Noise_XK_encap_message_p_is_null(Noise_XK_encap_message_t *emp); typedef Noise_XK_encap_message_t *Noise_XK_encap_message_p; void Noise_XK_encap_message_p_free(Noise_XK_encap_message_t *emp); Noise_XK_encap_message_t *Noise_XK_pack_message_with_conf_level( uint8_t requested_conf_level, uint32_t msg_len, uint8_t *msg ); Noise_XK_encap_message_t *Noise_XK_pack_message(uint32_t msg_len, uint8_t *msg); bool Noise_XK_unpack_message_with_auth_level( uint32_t *out_msg_len, uint8_t **out_msg, uint8_t requested_auth_level, Noise_XK_encap_message_t *emp ); bool Noise_XK_unpack_message( uint32_t *out_msg_len, uint8_t **out_msg, Noise_XK_encap_message_t *emp ); void Noise_XK_unsafe_unpack_message( Noise_XK_ac_level_t *out_ac_level, uint32_t *out_msg_len, uint8_t **out_msg, Noise_XK_encap_message_t *emp ); extern Prims_int Noise_XK_num_pattern_messages; bool Noise_XK_rcode_is_success(Noise_XK_rcode c); bool Noise_XK_rcode_is_error(Noise_XK_rcode c); bool Noise_XK_rcode_is_stuck(Noise_XK_rcode c); /******************************************************************************* An instanciation of the NoiseAPI for the XK pattern. This instanciation uses the following features: * uint32 for the sessions and peers counters/unique identifiers * we don't accept unknown remote static keys: all remote keys should have been registered in the device by adding the proper peers. * device/session/peer names are null-terminated strings of ANSI char *******************************************************************************/ typedef Noise_XK_status Noise_XK_status0; #define Noise_XK_IMS_Handshake 0 #define Noise_XK_IMS_Transport 1 typedef uint8_t Noise_XK_init_state_t_tags; typedef struct Noise_XK_init_state_t_s Noise_XK_init_state_t; typedef struct Noise_XK_peer_t_s Noise_XK_peer_t; typedef struct Noise_XK_cell_s Noise_XK_cell; typedef struct Noise_XK_cell_s { Noise_XK_cell *next; Noise_XK_peer_t *data; } Noise_XK_cell; typedef struct Noise_XK_device_t_s Noise_XK_device_t; typedef struct Noise_XK_resp_state_t_s Noise_XK_resp_state_t; #define Noise_XK_DS_Initiator 0 #define Noise_XK_DS_Responder 1 typedef uint8_t Noise_XK_session_t_tags; typedef struct Noise_XK_session_t_s Noise_XK_session_t; typedef Noise_XK_session_t Noise_XK_session_t0; typedef Noise_XK_session_t *Noise_XK_session_p; typedef Noise_XK_device_t Noise_XK_device_t0; typedef Noise_XK_device_t *Noise_XK_device_p; typedef Noise_XK_peer_t Noise_XK_peer_t0; typedef Noise_XK_peer_t *Noise_XK_peer_p; /* Create a device. Parameters: * `prlg`: Prologue for session initialization * `info`: Device name * `sk`: (if present) symmetric key used to serialize/deserialize private data * `spriv`: (if present) static private key May fail and return NULL if provided unvalid keys. */ Noise_XK_device_t *Noise_XK_device_create( uint32_t prlg_len, uint8_t *prlg, uint8_t *info, uint8_t *sk, uint8_t *spriv ); /* Create a device. Takes as arguments a symmetric key `sk` for secret data serialization/ deserialization, and an encrypted static private key `spriv`. The device name `info` is used as authentication data to encrypt/decrypt the device private key. May fail and return NULL if provided unvalid keys. */ Noise_XK_device_t *Noise_XK_device_create_from_secret( uint32_t prlg_len, uint8_t *prlg, uint8_t *info, uint8_t *sk, uint8_t *spriv ); /* Free a device. Take care to free the device **AFTER** having freed all the sessions created from this device. */ void Noise_XK_device_free(Noise_XK_device_t *dvp); /* Encrypt and derialize a device's secret. Uses the device symmetric key to encrypt the device's secret key. Uses a randomly generated nonce together with the device name as authentication data. */ void Noise_XK_serialize_device_secret(uint32_t *outlen, uint8_t **out, Noise_XK_device_t *dvp); /* Add a peer to the device and return a pointer to the newly created peer. May fail and return NULL if the device already contains a peer with the same public static key. Note that the peer is owned by the device: we don't provide any way of freeing it on the user side, and it might be invalidated after a removal operation. For this reason, we advise to immediately use the returned pointer (to retrieve the peer id for instance), then forget it. */ Noise_XK_peer_t *Noise_XK_device_add_peer(Noise_XK_device_t *dvp, uint8_t *pinfo, uint8_t *rs); /* Remove a peer designated by its unique identifier. */ void Noise_XK_device_remove_peer(Noise_XK_device_t *dvp, uint32_t pid); /* Encrypt and serialize a peer's key(s). Uses the device symmetric key to encrypt the peer's key(s). Uses a randomly generated nonce together with the peer name as authentication data. */ void Noise_XK_serialize_peer_secret( uint32_t *outlen, uint8_t **out, Noise_XK_device_t *dvp, Noise_XK_peer_t *peer ); /* Decrypt and deserialize a peer's secret data and add it to the device. */ Noise_XK_peer_t *Noise_XK_deserialize_peer_secret( Noise_XK_device_t *dvp, uint8_t *peer_name, uint32_t inlen, uint8_t *enc_keys ); /* Lookup a peer by using its unique identifier. Return NULL is no peer was found. Note that the peer is owned by the device: we don't provide any way of freeing it on the user side, and it might be invalidated after a removal operation. For this reason, we advise to immediately use the returned pointer (to retrieve the peer name, etc.), then forget it. */ Noise_XK_peer_t *Noise_XK_device_lookup_peer_by_id(Noise_XK_device_t *dvp, uint32_t id); /* Lookup a peer by using its static public key. Return NULL is no peer was found. Note that the peer is owned by the device: we don't provide any way of freeing it on the user side, and it might be invalidated after a removal operation. For this reason, we advise to immediately use the returned pointer (to retrieve the peer name, etc.), then forget it. */ Noise_XK_peer_t *Noise_XK_device_lookup_peer_by_static(Noise_XK_device_t *dvp, uint8_t *s); /* Copy the peer information to the user provided pointer. */ void Noise_XK_device_get_info(Noise_XK_noise_string *out, Noise_XK_device_t *dvp); /* Return the current value of the sessions counter. The device keeps track of the number of sessions created so far, in order to give them unique identifiers. */ uint32_t Noise_XK_device_get_sessions_counter(Noise_XK_device_t *dvp); /* Return true if the sessions counter is saturated. It is not possible to create any more sessions if the counter is saturated. */ bool Noise_XK_device_sessions_counter_is_saturated(Noise_XK_device_t *dvp); /* Return the current value of the peers counter. The device keeps track of the number of peers created so far, in order to give them unique identifiers. */ uint32_t Noise_XK_device_get_peers_counter(Noise_XK_device_t *dvp); /* Return true if the peers counter is saturated. It is not possible to add any more peers to the device if the counter is saturated. */ bool Noise_XK_device_peers_counter_is_saturated(Noise_XK_device_t *dvp); /* Copy the device static private key to the user provided buffer. */ void Noise_XK_device_get_static_priv(uint8_t *out, Noise_XK_device_t *dvp); /* Copy the device static public key to the user provided buffer. */ void Noise_XK_device_get_static_pub(uint8_t *out, Noise_XK_device_t *dvp); /* Return the unique peer identifier. */ uint32_t Noise_XK_peer_get_id(Noise_XK_peer_t *pp); /* Copy the peer information to the user provided pointer. */ void Noise_XK_peer_get_info(Noise_XK_noise_string *out, Noise_XK_peer_t *pp); /* Copy the peer static public key to the user provided buffer. */ void Noise_XK_peer_get_static(uint8_t *out, Noise_XK_peer_t *pp); /* Create an initiator session. May fail and return NULL in case of invalid keys, unknown peer, etc. */ Noise_XK_session_t *Noise_XK_session_create_initiator(Noise_XK_device_t *dvp, uint32_t pid); /* Create a responder session. May fail and return NULL in case of invalid keys, unknown peer, etc. */ Noise_XK_session_t *Noise_XK_session_create_responder(Noise_XK_device_t *dvp); /* Free a session. Be sure to free all sessions before freeing the device used to create those sessions. */ void Noise_XK_session_free(Noise_XK_session_t *sn); /* Write a message with the current session. If successful, this function will allocate a buffer of the proper length in `*out` and will write the length of this buffer in `*out_len`. Note that using `out` and `out_len` is always safe: if the function fails, it will set `*outlen` to 0 and `*out` to NULL. */ Noise_XK_rcode Noise_XK_session_write( Noise_XK_encap_message_t *payload, Noise_XK_session_t *sn_p, uint32_t *out_len, uint8_t **out ); /* Read a message with the current session. If successful, this function will allocate a an encapsulated message in `*payload_out`. Note that using `payload_out` is always safe: if the function fails, it will set `*payload_out` to NULL. */ Noise_XK_rcode Noise_XK_session_read( Noise_XK_encap_message_t **payload_out, Noise_XK_session_t *sn_p, uint32_t inlen, uint8_t *input ); /* Compute the length of the next message, given a payload length. Note that the function may fail, if the length of the message is too long for example (though very unlikely). You thus need to check the returned value. Also note that the length of the next message is always equal to: payload length + a value depending only on the current step. */ bool Noise_XK_session_compute_next_message_len( uint32_t *out, Noise_XK_session_t *sn, uint32_t payload_len ); /* Return the current status. */ Noise_XK_status Noise_XK_session_get_status(Noise_XK_session_t *sn); /* Copy the session hash to the user provided buffer. Note that the session hash is always public. Using the session hash might be pertinent once the session has reached the transport phase. */ void Noise_XK_session_get_hash(uint8_t *out, Noise_XK_session_t *sn); /* Return the session unique identifier. */ uint32_t Noise_XK_session_get_id(Noise_XK_session_t *sn); /* Copy the session information to the user provided pointer. */ void Noise_XK_session_get_info(Noise_XK_noise_string *out, Noise_XK_session_t *sn); /* Return the session's peer unique identifier. The remote may be unknown, in which case the returned id will be 0. Note that you can safely use the returned peer id without testing it, because all the functions taking peer ids as parameters were written to correctly manipulate 0. In particular, looking up id 0 will return NULL, and trying to create a session with peer id 0 will cleanly fail by also returning NULL. */ uint32_t Noise_XK_session_get_peer_id(Noise_XK_session_t *sn); /* Copy the session peer information, if known, to the user provided pointer. The remote may be unknown yet, in which case there is no peer information in the device and the function will return false. */ bool Noise_XK_session_get_peer_info(Noise_XK_noise_string *out, Noise_XK_session_t *sn); /* Return true if this session has reached the maximum security level for this pattern. Once the maximum security level is reached, it is not possible to have better confidentiality/authentication guarantees for the payloads sent/received with this session. Note that the guarantees provided by the maximum reachable level vary with the pattern, which must thus be carefully chosen. In order to reach the maximum level, the session must have finished the handshake. Moreover, in case the session sends the last handshake message, it must wait for the first transport message from the remote: otherwise, we have no way to know whether the remote was itself able to finish the handshake. */ bool Noise_XK_session_reached_max_security(Noise_XK_session_t *snp); /* DO NOT use this: for tests and benchmarks only */ Noise_XK_session_t *Noise_XK__session_create_initiator_with_ephemeral( Noise_XK_device_t *dvp, uint8_t *epriv, uint8_t *epub, uint32_t pid ); /* DO NOT use this: for tests and benchmarks only */ Noise_XK_session_t *Noise_XK__session_create_responder_with_ephemeral( Noise_XK_device_t *dvp, uint8_t *epriv, uint8_t *epub ); #define __XK_H_DEFINED #endif liboprf-0.6.1/src/noise_xk/include/karmel/000077500000000000000000000000001474121727000204645ustar00rootroot00000000000000liboprf-0.6.1/src/noise_xk/include/karmel/README.txt000066400000000000000000000004221474121727000221600ustar00rootroot00000000000000contains snapshot of e5620ceb7c8a4996520d693f597872806dc0a1d3 from https://github.com/project-everest/hacl-star cp -r $(HACL_ROOT)/dist/karamel/krmllib/dist/minimal karmel cp -r $(HACL_ROOT)/dist/karamel/include/krml karmel/ cp -r ${HACL_ROOT}/dist/karamel/include karmel liboprf-0.6.1/src/noise_xk/include/karmel/krml/000077500000000000000000000000001474121727000214315ustar00rootroot00000000000000liboprf-0.6.1/src/noise_xk/include/karmel/krml/c_endianness.h000066400000000000000000000004641474121727000242370ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef __KRML_ENDIAN_H #define __KRML_ENDIAN_H #ifdef __GNUC__ #warning "c_endianness.h is deprecated, include lowstar_endianness.h instead" #endif #include "lowstar_endianness.h" #endif liboprf-0.6.1/src/noise_xk/include/karmel/krml/fstar_int.h000066400000000000000000000045651474121727000236050ustar00rootroot00000000000000#ifndef __FSTAR_INT_H #define __FSTAR_INT_H #include "internal/types.h" /* * Arithmetic Shift Right operator * * In all C standards, a >> b is implementation-defined when a has a signed * type and a negative value. See e.g. 6.5.7 in * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2310.pdf * * GCC, MSVC, and Clang implement a >> b as an arithmetic shift. * * GCC: https://gcc.gnu.org/onlinedocs/gcc-9.1.0/gcc/Integers-implementation.html#Integers-implementation * MSVC: https://docs.microsoft.com/en-us/cpp/cpp/left-shift-and-right-shift-operators-input-and-output?view=vs-2019#right-shifts * Clang: tested that Clang 7, 8 and 9 compile this to an arithmetic shift * * We implement arithmetic shift right simply as >> in these compilers * and bail out in others. */ #if !(defined(_MSC_VER) || defined(__GNUC__) || (defined(__clang__) && (__clang_major__ >= 7))) static inline int8_t FStar_Int8_shift_arithmetic_right(int8_t a, uint32_t b) { do { KRML_HOST_EPRINTF("Could not identify compiler so could not provide an implementation of signed arithmetic shift right.\n"); KRML_HOST_EXIT(255); } while (0); } static inline int16_t FStar_Int16_shift_arithmetic_right(int16_t a, uint32_t b) { do { KRML_HOST_EPRINTF("Could not identify compiler so could not provide an implementation of signed arithmetic shift right.\n"); KRML_HOST_EXIT(255); } while (0); } static inline int32_t FStar_Int32_shift_arithmetic_right(int32_t a, uint32_t b) { do { KRML_HOST_EPRINTF("Could not identify compiler so could not provide an implementation of signed arithmetic shift right.\n"); KRML_HOST_EXIT(255); } while (0); } static inline int64_t FStar_Int64_shift_arithmetic_right(int64_t a, uint32_t b) { do { KRML_HOST_EPRINTF("Could not identify compiler so could not provide an implementation of signed arithmetic shift right.\n"); KRML_HOST_EXIT(255); } while (0); } #else static inline int8_t FStar_Int8_shift_arithmetic_right(int8_t a, uint32_t b) { return (a >> b); } static inline int16_t FStar_Int16_shift_arithmetic_right(int16_t a, uint32_t b) { return (a >> b); } static inline int32_t FStar_Int32_shift_arithmetic_right(int32_t a, uint32_t b) { return (a >> b); } static inline int64_t FStar_Int64_shift_arithmetic_right(int64_t a, uint32_t b) { return (a >> b); } #endif /* !(defined(_MSC_VER) ... ) */ #endif /* __FSTAR_INT_H */ liboprf-0.6.1/src/noise_xk/include/karmel/krml/internal/000077500000000000000000000000001474121727000232455ustar00rootroot00000000000000liboprf-0.6.1/src/noise_xk/include/karmel/krml/internal/builtin.h000066400000000000000000000007731474121727000250730ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef __KRML_BUILTIN_H #define __KRML_BUILTIN_H /* For alloca, when using KaRaMeL's -falloca */ #if (defined(_WIN32) || defined(_WIN64)) # include #elif (defined(sun)) # include #endif /* If some globals need to be initialized before the main, then karamel will * generate and try to link last a function with this type: */ void krmlinit_globals(void); #endif liboprf-0.6.1/src/noise_xk/include/karmel/krml/internal/callconv.h000066400000000000000000000015221474121727000252170ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef __KRML_CALLCONV_H #define __KRML_CALLCONV_H /******************************************************************************/ /* Some macros to ease compatibility (TODO: move to miTLS) */ /******************************************************************************/ /* We want to generate __cdecl safely without worrying about it being undefined. * When using MSVC, these are always defined. When using MinGW, these are * defined too. They have no meaning for other platforms, so we define them to * be empty macros in other situations. */ #ifndef _MSC_VER #ifndef __cdecl #define __cdecl #endif #ifndef __stdcall #define __stdcall #endif #ifndef __fastcall #define __fastcall #endif #endif #endif liboprf-0.6.1/src/noise_xk/include/karmel/krml/internal/compat.h000066400000000000000000000024371474121727000247070ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef KRML_COMPAT_H #define KRML_COMPAT_H #include /* A series of macros that define C implementations of types that are not Low*, * to facilitate porting programs to Low*. */ typedef struct { uint32_t length; const char *data; } FStar_Bytes_bytes; typedef int32_t Prims_pos, Prims_nat, Prims_nonzero, Prims_int, krml_checked_int_t; #define RETURN_OR(x) \ do { \ int64_t __ret = x; \ if (__ret < INT32_MIN || INT32_MAX < __ret) { \ KRML_HOST_PRINTF( \ "Prims.{int,nat,pos} integer overflow at %s:%d\n", __FILE__, \ __LINE__); \ KRML_HOST_EXIT(252); \ } \ return (int32_t)__ret; \ } while (0) #endif liboprf-0.6.1/src/noise_xk/include/karmel/krml/internal/debug.h000066400000000000000000000057471474121727000245210ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef __KRML_DEBUG_H #define __KRML_DEBUG_H #include #include "krml/internal/target.h" /******************************************************************************/ /* Debugging helpers - intended only for KaRaMeL developers */ /******************************************************************************/ /* In support of "-wasm -d force-c": we might need this function to be * forward-declared, because the dependency on WasmSupport appears very late, * after SimplifyWasm, and sadly, after the topological order has been done. */ void WasmSupport_check_buffer_size(uint32_t s); /* A series of GCC atrocities to trace function calls (karamel's [-d c-calls] * option). Useful when trying to debug, say, Wasm, to compare traces. */ /* clang-format off */ #ifdef __GNUC__ #define KRML_FORMAT(X) _Generic((X), \ uint8_t : "0x%08" PRIx8, \ uint16_t: "0x%08" PRIx16, \ uint32_t: "0x%08" PRIx32, \ uint64_t: "0x%08" PRIx64, \ int8_t : "0x%08" PRIx8, \ int16_t : "0x%08" PRIx16, \ int32_t : "0x%08" PRIx32, \ int64_t : "0x%08" PRIx64, \ default : "%s") #define KRML_FORMAT_ARG(X) _Generic((X), \ uint8_t : X, \ uint16_t: X, \ uint32_t: X, \ uint64_t: X, \ int8_t : X, \ int16_t : X, \ int32_t : X, \ int64_t : X, \ default : "unknown") /* clang-format on */ # define KRML_DEBUG_RETURN(X) \ ({ \ __auto_type _ret = (X); \ KRML_HOST_PRINTF("returning: "); \ KRML_HOST_PRINTF(KRML_FORMAT(_ret), KRML_FORMAT_ARG(_ret)); \ KRML_HOST_PRINTF(" \n"); \ _ret; \ }) #endif #endif liboprf-0.6.1/src/noise_xk/include/karmel/krml/internal/target.h000066400000000000000000000325021474121727000247060ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef __KRML_TARGET_H #define __KRML_TARGET_H #include #include #include #include #include #include #include /* Since KaRaMeL emits the inline keyword unconditionally, we follow the * guidelines at https://gcc.gnu.org/onlinedocs/gcc/Inline.html and make this * __inline__ to ensure the code compiles with -std=c90 and earlier. */ #ifdef __GNUC__ # define inline __inline__ #endif /******************************************************************************/ /* Macros that KaRaMeL will generate. */ /******************************************************************************/ /* For "bare" targets that do not have a C stdlib, the user might want to use * [-add-early-include '"mydefinitions.h"'] and override these. */ #ifndef KRML_HOST_PRINTF # define KRML_HOST_PRINTF printf #endif #if ( \ (defined __STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ (!(defined KRML_HOST_EPRINTF))) # define KRML_HOST_EPRINTF(...) fprintf(stderr, __VA_ARGS__) #elif !(defined KRML_HOST_EPRINTF) && defined(_MSC_VER) # define KRML_HOST_EPRINTF(...) fprintf(stderr, __VA_ARGS__) #endif #ifndef KRML_HOST_EXIT # define KRML_HOST_EXIT exit #endif #ifndef KRML_HOST_MALLOC # define KRML_HOST_MALLOC malloc #endif #ifndef KRML_HOST_CALLOC # define KRML_HOST_CALLOC calloc #endif #ifndef KRML_HOST_FREE # define KRML_HOST_FREE free #endif #ifndef KRML_HOST_IGNORE # define KRML_HOST_IGNORE(x) (void)(x) #endif #ifndef KRML_MAYBE_UNUSED_VAR # define KRML_MAYBE_UNUSED_VAR(x) KRML_HOST_IGNORE(x) #endif #ifndef KRML_MAYBE_UNUSED # if defined(__GNUC__) # define KRML_MAYBE_UNUSED __attribute__((unused)) # else # define KRML_MAYBE_UNUSED # endif #endif #ifndef KRML_NOINLINE # if defined(_MSC_VER) # define KRML_NOINLINE __declspec(noinline) # elif defined (__GNUC__) # define KRML_NOINLINE __attribute__((noinline,unused)) # else # define KRML_NOINLINE # warning "The KRML_NOINLINE macro is not defined for this toolchain!" # warning "The compiler may defeat side-channel resistance with optimizations." # warning "Please locate target.h and try to fill it out with a suitable definition for this compiler." # endif #endif #ifndef KRML_PRE_ALIGN # ifdef _MSC_VER # define KRML_PRE_ALIGN(X) __declspec(align(X)) # else # define KRML_PRE_ALIGN(X) # endif #endif #ifndef KRML_POST_ALIGN # ifdef _MSC_VER # define KRML_POST_ALIGN(X) # else # define KRML_POST_ALIGN(X) __attribute__((aligned(X))) # endif #endif /* MinGW-W64 does not support C11 aligned_alloc, but it supports * MSVC's _aligned_malloc. */ #ifndef KRML_ALIGNED_MALLOC # ifdef __MINGW32__ # include <_mingw.h> # endif # if ( \ defined(_MSC_VER) || \ (defined(__MINGW32__) && defined(__MINGW64_VERSION_MAJOR))) # define KRML_ALIGNED_MALLOC(X, Y) _aligned_malloc(Y, X) # else # define KRML_ALIGNED_MALLOC(X, Y) aligned_alloc(X, Y) # endif #endif /* Since aligned allocations with MinGW-W64 are done with * _aligned_malloc (see above), such pointers must be freed with * _aligned_free. */ #ifndef KRML_ALIGNED_FREE # ifdef __MINGW32__ # include <_mingw.h> # endif # if ( \ defined(_MSC_VER) || \ (defined(__MINGW32__) && defined(__MINGW64_VERSION_MAJOR))) # define KRML_ALIGNED_FREE(X) _aligned_free(X) # else # define KRML_ALIGNED_FREE(X) free(X) # endif #endif #ifndef KRML_HOST_TIME # include /* Prims_nat not yet in scope */ inline static int32_t krml_time(void) { return (int32_t)time(NULL); } # define KRML_HOST_TIME krml_time #endif /* In statement position, exiting is easy. */ #define KRML_EXIT \ do { \ KRML_HOST_PRINTF("Unimplemented function at %s:%d\n", __FILE__, __LINE__); \ KRML_HOST_EXIT(254); \ } while (0) /* In expression position, use the comma-operator and a malloc to return an * expression of the right size. KaRaMeL passes t as the parameter to the macro. */ #define KRML_EABORT(t, msg) \ (KRML_HOST_PRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, msg), \ KRML_HOST_EXIT(255), *((t *)KRML_HOST_MALLOC(sizeof(t)))) /* In FStar.Buffer.fst, the size of arrays is uint32_t, but it's a number of * *elements*. Do an ugly, run-time check (some of which KaRaMeL can eliminate). */ #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4)) # define _KRML_CHECK_SIZE_PRAGMA \ _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") #else # define _KRML_CHECK_SIZE_PRAGMA #endif #define KRML_CHECK_SIZE(size_elt, sz) \ do { \ _KRML_CHECK_SIZE_PRAGMA \ if (((size_t)(sz)) > ((size_t)(SIZE_MAX / (size_elt)))) { \ KRML_HOST_PRINTF( \ "Maximum allocatable size exceeded, aborting before overflow at " \ "%s:%d\n", \ __FILE__, __LINE__); \ KRML_HOST_EXIT(253); \ } \ } while (0) #if defined(_MSC_VER) && _MSC_VER < 1900 # define KRML_HOST_SNPRINTF(buf, sz, fmt, arg) \ _snprintf_s(buf, sz, _TRUNCATE, fmt, arg) #else # define KRML_HOST_SNPRINTF(buf, sz, fmt, arg) snprintf(buf, sz, fmt, arg) #endif #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4)) # define KRML_DEPRECATED(x) __attribute__((deprecated(x))) #elif defined(__GNUC__) /* deprecated attribute is not defined in GCC < 4.5. */ # define KRML_DEPRECATED(x) #elif defined(_MSC_VER) # define KRML_DEPRECATED(x) __declspec(deprecated(x)) #endif /* Macros for prettier unrolling of loops */ #define KRML_LOOP1(i, n, x) { \ x \ i += n; \ (void) i; \ } #define KRML_LOOP2(i, n, x) \ KRML_LOOP1(i, n, x) \ KRML_LOOP1(i, n, x) #define KRML_LOOP3(i, n, x) \ KRML_LOOP2(i, n, x) \ KRML_LOOP1(i, n, x) #define KRML_LOOP4(i, n, x) \ KRML_LOOP2(i, n, x) \ KRML_LOOP2(i, n, x) #define KRML_LOOP5(i, n, x) \ KRML_LOOP4(i, n, x) \ KRML_LOOP1(i, n, x) #define KRML_LOOP6(i, n, x) \ KRML_LOOP4(i, n, x) \ KRML_LOOP2(i, n, x) #define KRML_LOOP7(i, n, x) \ KRML_LOOP4(i, n, x) \ KRML_LOOP3(i, n, x) #define KRML_LOOP8(i, n, x) \ KRML_LOOP4(i, n, x) \ KRML_LOOP4(i, n, x) #define KRML_LOOP9(i, n, x) \ KRML_LOOP8(i, n, x) \ KRML_LOOP1(i, n, x) #define KRML_LOOP10(i, n, x) \ KRML_LOOP8(i, n, x) \ KRML_LOOP2(i, n, x) #define KRML_LOOP11(i, n, x) \ KRML_LOOP8(i, n, x) \ KRML_LOOP3(i, n, x) #define KRML_LOOP12(i, n, x) \ KRML_LOOP8(i, n, x) \ KRML_LOOP4(i, n, x) #define KRML_LOOP13(i, n, x) \ KRML_LOOP8(i, n, x) \ KRML_LOOP5(i, n, x) #define KRML_LOOP14(i, n, x) \ KRML_LOOP8(i, n, x) \ KRML_LOOP6(i, n, x) #define KRML_LOOP15(i, n, x) \ KRML_LOOP8(i, n, x) \ KRML_LOOP7(i, n, x) #define KRML_LOOP16(i, n, x) \ KRML_LOOP8(i, n, x) \ KRML_LOOP8(i, n, x) #define KRML_UNROLL_FOR(i, z, n, k, x) \ do { \ uint32_t i = z; \ KRML_LOOP##n(i, k, x) \ } while (0) #define KRML_ACTUAL_FOR(i, z, n, k, x) \ do { \ for (uint32_t i = z; i < n; i += k) { \ x \ } \ } while (0) #ifndef KRML_UNROLL_MAX # define KRML_UNROLL_MAX 16 #endif /* 1 is the number of loop iterations, i.e. (n - z)/k as evaluated by krml */ #if 0 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR0(i, z, n, k, x) #else # define KRML_MAYBE_FOR0(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 1 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR1(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 1, k, x) #else # define KRML_MAYBE_FOR1(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 2 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR2(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 2, k, x) #else # define KRML_MAYBE_FOR2(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 3 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR3(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 3, k, x) #else # define KRML_MAYBE_FOR3(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 4 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR4(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 4, k, x) #else # define KRML_MAYBE_FOR4(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 5 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR5(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 5, k, x) #else # define KRML_MAYBE_FOR5(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 6 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR6(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 6, k, x) #else # define KRML_MAYBE_FOR6(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 7 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR7(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 7, k, x) #else # define KRML_MAYBE_FOR7(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 8 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR8(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 8, k, x) #else # define KRML_MAYBE_FOR8(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 9 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR9(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 9, k, x) #else # define KRML_MAYBE_FOR9(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 10 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR10(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 10, k, x) #else # define KRML_MAYBE_FOR10(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 11 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR11(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 11, k, x) #else # define KRML_MAYBE_FOR11(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 12 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR12(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 12, k, x) #else # define KRML_MAYBE_FOR12(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 13 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR13(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 13, k, x) #else # define KRML_MAYBE_FOR13(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 14 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR14(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 14, k, x) #else # define KRML_MAYBE_FOR14(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 15 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR15(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 15, k, x) #else # define KRML_MAYBE_FOR15(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #if 16 <= KRML_UNROLL_MAX # define KRML_MAYBE_FOR16(i, z, n, k, x) KRML_UNROLL_FOR(i, z, 16, k, x) #else # define KRML_MAYBE_FOR16(i, z, n, k, x) KRML_ACTUAL_FOR(i, z, n, k, x) #endif #endif liboprf-0.6.1/src/noise_xk/include/karmel/krml/internal/types.h000066400000000000000000000070221474121727000245630ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef KRML_TYPES_H #define KRML_TYPES_H #include #include #include #include /* Types which are either abstract, meaning that have to be implemented in C, or * which are models, meaning that they are swapped out at compile-time for * hand-written C types (in which case they're marked as noextract). */ typedef uint64_t FStar_UInt64_t, FStar_UInt64_t_; typedef int64_t FStar_Int64_t, FStar_Int64_t_; typedef uint32_t FStar_UInt32_t, FStar_UInt32_t_; typedef int32_t FStar_Int32_t, FStar_Int32_t_; typedef uint16_t FStar_UInt16_t, FStar_UInt16_t_; typedef int16_t FStar_Int16_t, FStar_Int16_t_; typedef uint8_t FStar_UInt8_t, FStar_UInt8_t_; typedef int8_t FStar_Int8_t, FStar_Int8_t_; /* Only useful when building krmllib, because it's in the dependency graph of * FStar.Int.Cast. */ typedef uint64_t FStar_UInt63_t, FStar_UInt63_t_; typedef int64_t FStar_Int63_t, FStar_Int63_t_; typedef double FStar_Float_float; typedef uint32_t FStar_Char_char; typedef FILE *FStar_IO_fd_read, *FStar_IO_fd_write; typedef void *FStar_Dyn_dyn; typedef const char *C_String_t, *C_String_t_, *C_Compat_String_t, *C_Compat_String_t_; typedef int exit_code; typedef FILE *channel; typedef unsigned long long TestLib_cycles; typedef uint64_t FStar_Date_dateTime, FStar_Date_timeSpan; /* Now Prims.string is no longer illegal with the new model in LowStar.Printf; * it's operations that produce Prims_string which are illegal. Bring the * definition into scope by default. */ typedef const char *Prims_string; #if (defined(_MSC_VER) && defined(_M_X64) && !defined(__clang__)) #define IS_MSVC64 1 #endif /* This code makes a number of assumptions and should be refined. In particular, * it assumes that: any non-MSVC amd64 compiler supports int128. Maybe it would * be easier to just test for defined(__SIZEOF_INT128__) only? */ #if (defined(__x86_64__) || \ defined(__x86_64) || \ defined(__aarch64__) || \ (defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)) || \ defined(__s390x__) || \ (defined(_MSC_VER) && defined(_M_X64) && defined(__clang__)) || \ (defined(__mips__) && defined(__LP64__)) || \ (defined(__riscv) && __riscv_xlen == 64) || \ defined(__SIZEOF_INT128__)) #define HAS_INT128 1 #endif /* The uint128 type is a special case since we offer several implementations of * it, depending on the compiler and whether the user wants the verified * implementation or not. */ #if !defined(KRML_VERIFIED_UINT128) && defined(IS_MSVC64) # include typedef __m128i FStar_UInt128_uint128; #elif !defined(KRML_VERIFIED_UINT128) && defined(HAS_INT128) typedef unsigned __int128 FStar_UInt128_uint128; #else typedef struct FStar_UInt128_uint128_s { uint64_t low; uint64_t high; } FStar_UInt128_uint128; #endif /* The former is defined once, here (otherwise, conflicts for test-c89. The * latter is for internal use. */ typedef FStar_UInt128_uint128 FStar_UInt128_t, uint128_t; #include "krml/lowstar_endianness.h" #endif /* Avoid a circular loop: if this header is included via FStar_UInt8_16_32_64, * then don't bring the uint128 definitions into scope. */ #ifndef __FStar_UInt_8_16_32_64_H #if !defined(KRML_VERIFIED_UINT128) && defined(IS_MSVC64) #include "fstar_uint128_msvc.h" #elif !defined(KRML_VERIFIED_UINT128) && defined(HAS_INT128) #include "fstar_uint128_gcc64.h" #else #include "FStar_UInt128_Verified.h" #include "fstar_uint128_struct_endianness.h" #endif #endif liboprf-0.6.1/src/noise_xk/include/karmel/krml/internal/wasmsupport.h000066400000000000000000000003551474121727000260250ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ /* This file is automatically included when compiling with -wasm -d force-c */ #define WasmSupport_check_buffer_size(X) liboprf-0.6.1/src/noise_xk/include/karmel/krml/lowstar_endianness.h000066400000000000000000000171151474121727000255110ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef __LOWSTAR_ENDIANNESS_H #define __LOWSTAR_ENDIANNESS_H #include #include /******************************************************************************/ /* Implementing C.fst (part 2: endian-ness macros) */ /******************************************************************************/ /* ... for Linux */ #if defined(__linux__) || defined(__CYGWIN__) || defined (__USE_SYSTEM_ENDIAN_H__) || defined(__GLIBC__) # include /* ... for OSX */ #elif defined(__APPLE__) # include # define htole64(x) OSSwapHostToLittleInt64(x) # define le64toh(x) OSSwapLittleToHostInt64(x) # define htobe64(x) OSSwapHostToBigInt64(x) # define be64toh(x) OSSwapBigToHostInt64(x) # define htole16(x) OSSwapHostToLittleInt16(x) # define le16toh(x) OSSwapLittleToHostInt16(x) # define htobe16(x) OSSwapHostToBigInt16(x) # define be16toh(x) OSSwapBigToHostInt16(x) # define htole32(x) OSSwapHostToLittleInt32(x) # define le32toh(x) OSSwapLittleToHostInt32(x) # define htobe32(x) OSSwapHostToBigInt32(x) # define be32toh(x) OSSwapBigToHostInt32(x) /* ... for Solaris */ #elif defined(__sun__) # include # define htole64(x) LE_64(x) # define le64toh(x) LE_64(x) # define htobe64(x) BE_64(x) # define be64toh(x) BE_64(x) # define htole16(x) LE_16(x) # define le16toh(x) LE_16(x) # define htobe16(x) BE_16(x) # define be16toh(x) BE_16(x) # define htole32(x) LE_32(x) # define le32toh(x) LE_32(x) # define htobe32(x) BE_32(x) # define be32toh(x) BE_32(x) /* ... for the BSDs */ #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) # include #elif defined(__OpenBSD__) # include /* ... for Windows (MSVC)... not targeting XBOX 360! */ #elif defined(_MSC_VER) # include # define htobe16(x) _byteswap_ushort(x) # define htole16(x) (x) # define be16toh(x) _byteswap_ushort(x) # define le16toh(x) (x) # define htobe32(x) _byteswap_ulong(x) # define htole32(x) (x) # define be32toh(x) _byteswap_ulong(x) # define le32toh(x) (x) # define htobe64(x) _byteswap_uint64(x) # define htole64(x) (x) # define be64toh(x) _byteswap_uint64(x) # define le64toh(x) (x) /* ... for Windows (GCC-like, e.g. mingw or clang) */ #elif (defined(_WIN32) || defined(_WIN64) || defined(__EMSCRIPTEN__)) && \ (defined(__GNUC__) || defined(__clang__)) # define htobe16(x) __builtin_bswap16(x) # define htole16(x) (x) # define be16toh(x) __builtin_bswap16(x) # define le16toh(x) (x) # define htobe32(x) __builtin_bswap32(x) # define htole32(x) (x) # define be32toh(x) __builtin_bswap32(x) # define le32toh(x) (x) # define htobe64(x) __builtin_bswap64(x) # define htole64(x) (x) # define be64toh(x) __builtin_bswap64(x) # define le64toh(x) (x) /* ... generic big-endian fallback code */ /* ... AIX doesn't have __BYTE_ORDER__ (with XLC compiler) & is always big-endian */ #elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || defined(_AIX) /* byte swapping code inspired by: * https://github.com/rweather/arduinolibs/blob/master/libraries/Crypto/utility/EndianUtil.h * */ # define htobe32(x) (x) # define be32toh(x) (x) # define htole32(x) \ (__extension__({ \ uint32_t _temp = (x); \ ((_temp >> 24) & 0x000000FF) | ((_temp >> 8) & 0x0000FF00) | \ ((_temp << 8) & 0x00FF0000) | ((_temp << 24) & 0xFF000000); \ })) # define le32toh(x) (htole32((x))) # define htobe64(x) (x) # define be64toh(x) (x) # define htole64(x) \ (__extension__({ \ uint64_t __temp = (x); \ uint32_t __low = htobe32((uint32_t)__temp); \ uint32_t __high = htobe32((uint32_t)(__temp >> 32)); \ (((uint64_t)__low) << 32) | __high; \ })) # define le64toh(x) (htole64((x))) /* ... generic little-endian fallback code */ #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define htole32(x) (x) # define le32toh(x) (x) # define htobe32(x) \ (__extension__({ \ uint32_t _temp = (x); \ ((_temp >> 24) & 0x000000FF) | ((_temp >> 8) & 0x0000FF00) | \ ((_temp << 8) & 0x00FF0000) | ((_temp << 24) & 0xFF000000); \ })) # define be32toh(x) (htobe32((x))) # define htole64(x) (x) # define le64toh(x) (x) # define htobe64(x) \ (__extension__({ \ uint64_t __temp = (x); \ uint32_t __low = htobe32((uint32_t)__temp); \ uint32_t __high = htobe32((uint32_t)(__temp >> 32)); \ (((uint64_t)__low) << 32) | __high; \ })) # define be64toh(x) (htobe64((x))) /* ... couldn't determine endian-ness of the target platform */ #else # error "Please define __BYTE_ORDER__!" #endif /* defined(__linux__) || ... */ /* Loads and stores. These avoid undefined behavior due to unaligned memory * accesses, via memcpy. */ inline static uint16_t load16(uint8_t *b) { uint16_t x; memcpy(&x, b, 2); return x; } inline static uint32_t load32(uint8_t *b) { uint32_t x; memcpy(&x, b, 4); return x; } inline static uint64_t load64(uint8_t *b) { uint64_t x; memcpy(&x, b, 8); return x; } inline static void store16(uint8_t *b, uint16_t i) { memcpy(b, &i, 2); } inline static void store32(uint8_t *b, uint32_t i) { memcpy(b, &i, 4); } inline static void store64(uint8_t *b, uint64_t i) { memcpy(b, &i, 8); } /* Legacy accessors so that this header can serve as an implementation of * C.Endianness */ #define load16_le(b) (le16toh(load16(b))) #define store16_le(b, i) (store16(b, htole16(i))) #define load16_be(b) (be16toh(load16(b))) #define store16_be(b, i) (store16(b, htobe16(i))) #define load32_le(b) (le32toh(load32(b))) #define store32_le(b, i) (store32(b, htole32(i))) #define load32_be(b) (be32toh(load32(b))) #define store32_be(b, i) (store32(b, htobe32(i))) #define load64_le(b) (le64toh(load64(b))) #define store64_le(b, i) (store64(b, htole64(i))) #define load64_be(b) (be64toh(load64(b))) #define store64_be(b, i) (store64(b, htobe64(i))) /* Co-existence of LowStar.Endianness and FStar.Endianness generates name * conflicts, because of course both insist on having no prefixes. Until a * prefix is added, or until we truly retire FStar.Endianness, solve this issue * in an elegant way. */ #define load16_le0 load16_le #define store16_le0 store16_le #define load16_be0 load16_be #define store16_be0 store16_be #define load32_le0 load32_le #define store32_le0 store32_le #define load32_be0 load32_be #define store32_be0 store32_be #define load64_le0 load64_le #define store64_le0 store64_le #define load64_be0 load64_be #define store64_be0 store64_be #define load128_le0 load128_le #define store128_le0 store128_le #define load128_be0 load128_be #define store128_be0 store128_be #endif liboprf-0.6.1/src/noise_xk/include/karmel/minimal/000077500000000000000000000000001474121727000221125ustar00rootroot00000000000000liboprf-0.6.1/src/noise_xk/include/karmel/minimal/FStar_UInt128.h000066400000000000000000000051511474121727000244760ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef __FStar_UInt128_H #define __FStar_UInt128_H #include #include #include "krml/internal/compat.h" #include "krml/lowstar_endianness.h" #include "krml/internal/types.h" #include "krml/internal/target.h" static inline FStar_UInt128_uint128 FStar_UInt128_add(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_add_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_add_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_sub(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_sub_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_sub_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_logand(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_logxor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_logor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_lognot(FStar_UInt128_uint128 a); static inline FStar_UInt128_uint128 FStar_UInt128_shift_left(FStar_UInt128_uint128 a, uint32_t s); static inline FStar_UInt128_uint128 FStar_UInt128_shift_right(FStar_UInt128_uint128 a, uint32_t s); static inline bool FStar_UInt128_eq(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline bool FStar_UInt128_gt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline bool FStar_UInt128_lt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline bool FStar_UInt128_gte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline bool FStar_UInt128_lte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_eq_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_gte_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); static inline FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t a); static inline uint64_t FStar_UInt128_uint128_to_uint64(FStar_UInt128_uint128 a); static inline FStar_UInt128_uint128 FStar_UInt128_mul32(uint64_t x, uint32_t y); static inline FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x, uint64_t y); #define __FStar_UInt128_H_DEFINED #endif liboprf-0.6.1/src/noise_xk/include/karmel/minimal/FStar_UInt128_Verified.h000066400000000000000000000222071474121727000263140ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef __FStar_UInt128_Verified_H #define __FStar_UInt128_Verified_H #include "FStar_UInt_8_16_32_64.h" #include #include #include "krml/internal/types.h" #include "krml/internal/target.h" static inline uint64_t FStar_UInt128_constant_time_carry(uint64_t a, uint64_t b) { return (a ^ ((a ^ b) | ((a - b) ^ b))) >> 63U; } static inline uint64_t FStar_UInt128_carry(uint64_t a, uint64_t b) { return FStar_UInt128_constant_time_carry(a, b); } static inline FStar_UInt128_uint128 FStar_UInt128_add(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = a.low + b.low; lit.high = a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low); return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_add_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = a.low + b.low; lit.high = a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low); return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_add_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = a.low + b.low; lit.high = a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low); return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_sub(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = a.low - b.low; lit.high = a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low); return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_sub_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = a.low - b.low; lit.high = a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low); return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_sub_mod_impl(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = a.low - b.low; lit.high = a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low); return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_sub_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { return FStar_UInt128_sub_mod_impl(a, b); } static inline FStar_UInt128_uint128 FStar_UInt128_logand(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = a.low & b.low; lit.high = a.high & b.high; return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_logxor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = a.low ^ b.low; lit.high = a.high ^ b.high; return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_logor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = a.low | b.low; lit.high = a.high | b.high; return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_lognot(FStar_UInt128_uint128 a) { FStar_UInt128_uint128 lit; lit.low = ~a.low; lit.high = ~a.high; return lit; } static uint32_t FStar_UInt128_u32_64 = 64U; static inline uint64_t FStar_UInt128_add_u64_shift_left(uint64_t hi, uint64_t lo, uint32_t s) { return (hi << s) + (lo >> (FStar_UInt128_u32_64 - s)); } static inline uint64_t FStar_UInt128_add_u64_shift_left_respec(uint64_t hi, uint64_t lo, uint32_t s) { return FStar_UInt128_add_u64_shift_left(hi, lo, s); } static inline FStar_UInt128_uint128 FStar_UInt128_shift_left_small(FStar_UInt128_uint128 a, uint32_t s) { if (s == 0U) { return a; } else { FStar_UInt128_uint128 lit; lit.low = a.low << s; lit.high = FStar_UInt128_add_u64_shift_left_respec(a.high, a.low, s); return lit; } } static inline FStar_UInt128_uint128 FStar_UInt128_shift_left_large(FStar_UInt128_uint128 a, uint32_t s) { FStar_UInt128_uint128 lit; lit.low = 0ULL; lit.high = a.low << (s - FStar_UInt128_u32_64); return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_shift_left(FStar_UInt128_uint128 a, uint32_t s) { if (s < FStar_UInt128_u32_64) { return FStar_UInt128_shift_left_small(a, s); } else { return FStar_UInt128_shift_left_large(a, s); } } static inline uint64_t FStar_UInt128_add_u64_shift_right(uint64_t hi, uint64_t lo, uint32_t s) { return (lo >> s) + (hi << (FStar_UInt128_u32_64 - s)); } static inline uint64_t FStar_UInt128_add_u64_shift_right_respec(uint64_t hi, uint64_t lo, uint32_t s) { return FStar_UInt128_add_u64_shift_right(hi, lo, s); } static inline FStar_UInt128_uint128 FStar_UInt128_shift_right_small(FStar_UInt128_uint128 a, uint32_t s) { if (s == 0U) { return a; } else { FStar_UInt128_uint128 lit; lit.low = FStar_UInt128_add_u64_shift_right_respec(a.high, a.low, s); lit.high = a.high >> s; return lit; } } static inline FStar_UInt128_uint128 FStar_UInt128_shift_right_large(FStar_UInt128_uint128 a, uint32_t s) { FStar_UInt128_uint128 lit; lit.low = a.high >> (s - FStar_UInt128_u32_64); lit.high = 0ULL; return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_shift_right(FStar_UInt128_uint128 a, uint32_t s) { if (s < FStar_UInt128_u32_64) { return FStar_UInt128_shift_right_small(a, s); } else { return FStar_UInt128_shift_right_large(a, s); } } static inline bool FStar_UInt128_eq(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { return a.low == b.low && a.high == b.high; } static inline bool FStar_UInt128_gt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { return a.high > b.high || (a.high == b.high && a.low > b.low); } static inline bool FStar_UInt128_lt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { return a.high < b.high || (a.high == b.high && a.low < b.low); } static inline bool FStar_UInt128_gte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { return a.high > b.high || (a.high == b.high && a.low >= b.low); } static inline bool FStar_UInt128_lte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { return a.high < b.high || (a.high == b.high && a.low <= b.low); } static inline FStar_UInt128_uint128 FStar_UInt128_eq_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = FStar_UInt64_eq_mask(a.low, b.low) & FStar_UInt64_eq_mask(a.high, b.high); lit.high = FStar_UInt64_eq_mask(a.low, b.low) & FStar_UInt64_eq_mask(a.high, b.high); return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_gte_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = (FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high)) | (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low)); lit.high = (FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high)) | (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low)); return lit; } static inline FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t a) { FStar_UInt128_uint128 lit; lit.low = a; lit.high = 0ULL; return lit; } static inline uint64_t FStar_UInt128_uint128_to_uint64(FStar_UInt128_uint128 a) { return a.low; } static inline uint64_t FStar_UInt128_u64_mod_32(uint64_t a) { return a & 0xffffffffULL; } static uint32_t FStar_UInt128_u32_32 = 32U; static inline uint64_t FStar_UInt128_u32_combine(uint64_t hi, uint64_t lo) { return lo + (hi << FStar_UInt128_u32_32); } static inline FStar_UInt128_uint128 FStar_UInt128_mul32(uint64_t x, uint32_t y) { FStar_UInt128_uint128 lit; lit.low = FStar_UInt128_u32_combine((x >> FStar_UInt128_u32_32) * (uint64_t)y + (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32), FStar_UInt128_u64_mod_32(FStar_UInt128_u64_mod_32(x) * (uint64_t)y)); lit.high = ((x >> FStar_UInt128_u32_32) * (uint64_t)y + (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32)) >> FStar_UInt128_u32_32; return lit; } static inline uint64_t FStar_UInt128_u32_combine_(uint64_t hi, uint64_t lo) { return lo + (hi << FStar_UInt128_u32_32); } static inline FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x, uint64_t y) { FStar_UInt128_uint128 lit; lit.low = FStar_UInt128_u32_combine_(FStar_UInt128_u64_mod_32(x) * (y >> FStar_UInt128_u32_32) + FStar_UInt128_u64_mod_32((x >> FStar_UInt128_u32_32) * FStar_UInt128_u64_mod_32(y) + (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32)), FStar_UInt128_u64_mod_32(FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y))); lit.high = (x >> FStar_UInt128_u32_32) * (y >> FStar_UInt128_u32_32) + (((x >> FStar_UInt128_u32_32) * FStar_UInt128_u64_mod_32(y) + (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32)) >> FStar_UInt128_u32_32) + ((FStar_UInt128_u64_mod_32(x) * (y >> FStar_UInt128_u32_32) + FStar_UInt128_u64_mod_32((x >> FStar_UInt128_u32_32) * FStar_UInt128_u64_mod_32(y) + (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32))) >> FStar_UInt128_u32_32); return lit; } #define __FStar_UInt128_Verified_H_DEFINED #endif liboprf-0.6.1/src/noise_xk/include/karmel/minimal/FStar_UInt_8_16_32_64.h000066400000000000000000000135021474121727000256140ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef __FStar_UInt_8_16_32_64_H #define __FStar_UInt_8_16_32_64_H #include #include #include "krml/internal/compat.h" #include "krml/lowstar_endianness.h" #include "krml/internal/types.h" #include "krml/internal/target.h" extern krml_checked_int_t FStar_UInt64_n; extern bool FStar_UInt64_uu___is_Mk(uint64_t projectee); extern krml_checked_int_t FStar_UInt64___proj__Mk__item__v(uint64_t projectee); extern krml_checked_int_t FStar_UInt64_v(uint64_t x); extern uint64_t FStar_UInt64_uint_to_t(krml_checked_int_t x); extern uint64_t FStar_UInt64_zero; extern uint64_t FStar_UInt64_one; extern uint64_t FStar_UInt64_minus(uint64_t a); extern uint32_t FStar_UInt64_n_minus_one; static KRML_NOINLINE uint64_t FStar_UInt64_eq_mask(uint64_t a, uint64_t b) { uint64_t x = a ^ b; uint64_t minus_x = ~x + 1ULL; uint64_t x_or_minus_x = x | minus_x; uint64_t xnx = x_or_minus_x >> 63U; return xnx - 1ULL; } static KRML_NOINLINE uint64_t FStar_UInt64_gte_mask(uint64_t a, uint64_t b) { uint64_t x = a; uint64_t y = b; uint64_t x_xor_y = x ^ y; uint64_t x_sub_y = x - y; uint64_t x_sub_y_xor_y = x_sub_y ^ y; uint64_t q = x_xor_y | x_sub_y_xor_y; uint64_t x_xor_q = x ^ q; uint64_t x_xor_q_ = x_xor_q >> 63U; return x_xor_q_ - 1ULL; } extern Prims_string FStar_UInt64_to_string(uint64_t uu___); extern Prims_string FStar_UInt64_to_string_hex(uint64_t uu___); extern Prims_string FStar_UInt64_to_string_hex_pad(uint64_t uu___); extern uint64_t FStar_UInt64_of_string(Prims_string uu___); extern krml_checked_int_t FStar_UInt32_n; extern bool FStar_UInt32_uu___is_Mk(uint32_t projectee); extern krml_checked_int_t FStar_UInt32___proj__Mk__item__v(uint32_t projectee); extern krml_checked_int_t FStar_UInt32_v(uint32_t x); extern uint32_t FStar_UInt32_uint_to_t(krml_checked_int_t x); extern uint32_t FStar_UInt32_zero; extern uint32_t FStar_UInt32_one; extern uint32_t FStar_UInt32_minus(uint32_t a); extern uint32_t FStar_UInt32_n_minus_one; static KRML_NOINLINE uint32_t FStar_UInt32_eq_mask(uint32_t a, uint32_t b) { uint32_t x = a ^ b; uint32_t minus_x = ~x + 1U; uint32_t x_or_minus_x = x | minus_x; uint32_t xnx = x_or_minus_x >> 31U; return xnx - 1U; } static KRML_NOINLINE uint32_t FStar_UInt32_gte_mask(uint32_t a, uint32_t b) { uint32_t x = a; uint32_t y = b; uint32_t x_xor_y = x ^ y; uint32_t x_sub_y = x - y; uint32_t x_sub_y_xor_y = x_sub_y ^ y; uint32_t q = x_xor_y | x_sub_y_xor_y; uint32_t x_xor_q = x ^ q; uint32_t x_xor_q_ = x_xor_q >> 31U; return x_xor_q_ - 1U; } extern Prims_string FStar_UInt32_to_string(uint32_t uu___); extern Prims_string FStar_UInt32_to_string_hex(uint32_t uu___); extern Prims_string FStar_UInt32_to_string_hex_pad(uint32_t uu___); extern uint32_t FStar_UInt32_of_string(Prims_string uu___); extern krml_checked_int_t FStar_UInt16_n; extern bool FStar_UInt16_uu___is_Mk(uint16_t projectee); extern krml_checked_int_t FStar_UInt16___proj__Mk__item__v(uint16_t projectee); extern krml_checked_int_t FStar_UInt16_v(uint16_t x); extern uint16_t FStar_UInt16_uint_to_t(krml_checked_int_t x); extern uint16_t FStar_UInt16_zero; extern uint16_t FStar_UInt16_one; extern uint16_t FStar_UInt16_minus(uint16_t a); extern uint32_t FStar_UInt16_n_minus_one; static KRML_NOINLINE uint16_t FStar_UInt16_eq_mask(uint16_t a, uint16_t b) { uint16_t x = (uint32_t)a ^ (uint32_t)b; uint16_t minus_x = (uint32_t)~x + 1U; uint16_t x_or_minus_x = (uint32_t)x | (uint32_t)minus_x; uint16_t xnx = (uint32_t)x_or_minus_x >> 15U; return (uint32_t)xnx - 1U; } static KRML_NOINLINE uint16_t FStar_UInt16_gte_mask(uint16_t a, uint16_t b) { uint16_t x = a; uint16_t y = b; uint16_t x_xor_y = (uint32_t)x ^ (uint32_t)y; uint16_t x_sub_y = (uint32_t)x - (uint32_t)y; uint16_t x_sub_y_xor_y = (uint32_t)x_sub_y ^ (uint32_t)y; uint16_t q = (uint32_t)x_xor_y | (uint32_t)x_sub_y_xor_y; uint16_t x_xor_q = (uint32_t)x ^ (uint32_t)q; uint16_t x_xor_q_ = (uint32_t)x_xor_q >> 15U; return (uint32_t)x_xor_q_ - 1U; } extern Prims_string FStar_UInt16_to_string(uint16_t uu___); extern Prims_string FStar_UInt16_to_string_hex(uint16_t uu___); extern Prims_string FStar_UInt16_to_string_hex_pad(uint16_t uu___); extern uint16_t FStar_UInt16_of_string(Prims_string uu___); extern krml_checked_int_t FStar_UInt8_n; extern bool FStar_UInt8_uu___is_Mk(uint8_t projectee); extern krml_checked_int_t FStar_UInt8___proj__Mk__item__v(uint8_t projectee); extern krml_checked_int_t FStar_UInt8_v(uint8_t x); extern uint8_t FStar_UInt8_uint_to_t(krml_checked_int_t x); extern uint8_t FStar_UInt8_zero; extern uint8_t FStar_UInt8_one; extern uint8_t FStar_UInt8_minus(uint8_t a); extern uint32_t FStar_UInt8_n_minus_one; static KRML_NOINLINE uint8_t FStar_UInt8_eq_mask(uint8_t a, uint8_t b) { uint8_t x = (uint32_t)a ^ (uint32_t)b; uint8_t minus_x = (uint32_t)~x + 1U; uint8_t x_or_minus_x = (uint32_t)x | (uint32_t)minus_x; uint8_t xnx = (uint32_t)x_or_minus_x >> 7U; return (uint32_t)xnx - 1U; } static KRML_NOINLINE uint8_t FStar_UInt8_gte_mask(uint8_t a, uint8_t b) { uint8_t x = a; uint8_t y = b; uint8_t x_xor_y = (uint32_t)x ^ (uint32_t)y; uint8_t x_sub_y = (uint32_t)x - (uint32_t)y; uint8_t x_sub_y_xor_y = (uint32_t)x_sub_y ^ (uint32_t)y; uint8_t q = (uint32_t)x_xor_y | (uint32_t)x_sub_y_xor_y; uint8_t x_xor_q = (uint32_t)x ^ (uint32_t)q; uint8_t x_xor_q_ = (uint32_t)x_xor_q >> 7U; return (uint32_t)x_xor_q_ - 1U; } extern Prims_string FStar_UInt8_to_string(uint8_t uu___); extern Prims_string FStar_UInt8_to_string_hex(uint8_t uu___); extern Prims_string FStar_UInt8_to_string_hex_pad(uint8_t uu___); extern uint8_t FStar_UInt8_of_string(Prims_string uu___); typedef uint8_t FStar_UInt8_byte; #define __FStar_UInt_8_16_32_64_H_DEFINED #endif liboprf-0.6.1/src/noise_xk/include/karmel/minimal/LowStar_Endianness.h000066400000000000000000000012471474121727000260310ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef __LowStar_Endianness_H #define __LowStar_Endianness_H #include #include #include "krml/internal/compat.h" #include "krml/lowstar_endianness.h" #include "krml/internal/types.h" #include "krml/internal/target.h" static inline void store128_le(uint8_t *x0, FStar_UInt128_uint128 x1); static inline FStar_UInt128_uint128 load128_le(uint8_t *x0); static inline void store128_be(uint8_t *x0, FStar_UInt128_uint128 x1); static inline FStar_UInt128_uint128 load128_be(uint8_t *x0); #define __LowStar_Endianness_H_DEFINED #endif liboprf-0.6.1/src/noise_xk/include/karmel/minimal/Makefile.basic000066400000000000000000000026061474121727000246360ustar00rootroot00000000000000# A basic Makefile that KaRaMeL copies in the output directory; this is not # guaranteed to work and will only work well for very simple projects. This # Makefile uses: # - the custom C files passed to your krml invocation # - the custom C flags passed to your krml invocation # - the -o option passed to your krml invocation include Makefile.include ifeq (,$(KRML_HOME)) $(error please define KRML_HOME to point to the root of your KaRaMeL git checkout) endif CFLAGS += -I. -I $(KRML_HOME)/include -I $(KRML_HOME)/krmllib/dist/minimal CFLAGS += -Wall -Wextra -Werror -std=c11 \ -Wno-unknown-warning-option \ -Wno-infinite-recursion \ -g -fwrapv -D_BSD_SOURCE -D_DEFAULT_SOURCE ifeq ($(OS),Windows_NT) CFLAGS += -D__USE_MINGW_ANSI_STDIO else CFLAGS += -fPIC endif CFLAGS += $(USER_CFLAGS) SOURCES += $(ALL_C_FILES) $(USER_C_FILES) ifneq (,$(BLACKLIST)) SOURCES := $(filter-out $(BLACKLIST),$(SOURCES)) endif OBJS += $(patsubst %.c,%.o,$(SOURCES)) all: $(USER_TARGET) $(USER_TARGET): $(OBJS) AR ?= ar %.a: $(AR) cr $@ $^ %.exe: $(CC) $(CFLAGS) -o $@ $^ $(KRML_HOME)/krmllib/dist/generic/libkrmllib.a %.so: $(CC) $(CFLAGS) -shared -o $@ $^ %.d: %.c @set -e; rm -f $@; \ $(CC) -MM -MG $(CFLAGS) $< > $@.$$$$; \ sed 's,\($(notdir $*)\)\.o[ :]*,$(dir $@)\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ include $(patsubst %.c,%.d,$(SOURCES)) clean: rm -rf *.o *.d $(USER_TARGET) liboprf-0.6.1/src/noise_xk/include/karmel/minimal/Makefile.include000066400000000000000000000002311474121727000251700ustar00rootroot00000000000000USER_TARGET=libkrmllib.a USER_CFLAGS= USER_C_FILES=fstar_uint128.c ALL_C_FILES= ALL_H_FILES=FStar_UInt128.h FStar_UInt_8_16_32_64.h LowStar_Endianness.h liboprf-0.6.1/src/noise_xk/include/karmel/minimal/fstar_uint128_gcc64.h000066400000000000000000000111161474121727000256620ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ /******************************************************************************/ /* Machine integers (128-bit arithmetic) */ /******************************************************************************/ /* This header contains two things. * * First, an implementation of 128-bit arithmetic suitable for 64-bit GCC and * Clang, i.e. all the operations from FStar.UInt128. * * Second, 128-bit operations from C.Endianness (or LowStar.Endianness), * suitable for any compiler and platform (via a series of ifdefs). This second * part is unfortunate, and should be fixed by moving {load,store}128_{be,le} to * FStar.UInt128 to avoid a maze of preprocessor guards and hand-written code. * */ /* This file is used for both the minimal and generic krmllib distributions. As * such, it assumes that the machine integers have been bundled the exact same * way in both cases. */ #ifndef FSTAR_UINT128_GCC64 #define FSTAR_UINT128_GCC64 #include "FStar_UInt128.h" #include "FStar_UInt_8_16_32_64.h" #include "LowStar_Endianness.h" /* GCC + using native unsigned __int128 support */ inline static uint128_t load128_le(uint8_t *b) { uint128_t l = (uint128_t)load64_le(b); uint128_t h = (uint128_t)load64_le(b + 8); return (h << 64 | l); } inline static void store128_le(uint8_t *b, uint128_t n) { store64_le(b, (uint64_t)n); store64_le(b + 8, (uint64_t)(n >> 64)); } inline static uint128_t load128_be(uint8_t *b) { uint128_t h = (uint128_t)load64_be(b); uint128_t l = (uint128_t)load64_be(b + 8); return (h << 64 | l); } inline static void store128_be(uint8_t *b, uint128_t n) { store64_be(b, (uint64_t)(n >> 64)); store64_be(b + 8, (uint64_t)n); } inline static uint128_t FStar_UInt128_add(uint128_t x, uint128_t y) { return x + y; } inline static uint128_t FStar_UInt128_mul(uint128_t x, uint128_t y) { return x * y; } inline static uint128_t FStar_UInt128_add_mod(uint128_t x, uint128_t y) { return x + y; } inline static uint128_t FStar_UInt128_sub(uint128_t x, uint128_t y) { return x - y; } inline static uint128_t FStar_UInt128_sub_mod(uint128_t x, uint128_t y) { return x - y; } inline static uint128_t FStar_UInt128_logand(uint128_t x, uint128_t y) { return x & y; } inline static uint128_t FStar_UInt128_logor(uint128_t x, uint128_t y) { return x | y; } inline static uint128_t FStar_UInt128_logxor(uint128_t x, uint128_t y) { return x ^ y; } inline static uint128_t FStar_UInt128_lognot(uint128_t x) { return ~x; } inline static uint128_t FStar_UInt128_shift_left(uint128_t x, uint32_t y) { return x << y; } inline static uint128_t FStar_UInt128_shift_right(uint128_t x, uint32_t y) { return x >> y; } inline static uint128_t FStar_UInt128_uint64_to_uint128(uint64_t x) { return (uint128_t)x; } inline static uint64_t FStar_UInt128_uint128_to_uint64(uint128_t x) { return (uint64_t)x; } inline static uint128_t FStar_UInt128_mul_wide(uint64_t x, uint64_t y) { return ((uint128_t) x) * y; } inline static uint128_t FStar_UInt128_eq_mask(uint128_t x, uint128_t y) { uint64_t mask = FStar_UInt64_eq_mask((uint64_t)(x >> 64), (uint64_t)(y >> 64)) & FStar_UInt64_eq_mask((uint64_t)x, (uint64_t)y); return ((uint128_t)mask) << 64 | mask; } inline static uint128_t FStar_UInt128_gte_mask(uint128_t x, uint128_t y) { uint64_t mask = (FStar_UInt64_gte_mask(x >> 64, y >> 64) & ~(FStar_UInt64_eq_mask(x >> 64, y >> 64))) | (FStar_UInt64_eq_mask(x >> 64, y >> 64) & FStar_UInt64_gte_mask((uint64_t)x, (uint64_t)y)); return ((uint128_t)mask) << 64 | mask; } inline static uint64_t FStar_UInt128___proj__Mkuint128__item__low(uint128_t x) { return (uint64_t) x; } inline static uint64_t FStar_UInt128___proj__Mkuint128__item__high(uint128_t x) { return (uint64_t) (x >> 64); } inline static uint128_t FStar_UInt128_add_underspec(uint128_t x, uint128_t y) { return x + y; } inline static uint128_t FStar_UInt128_sub_underspec(uint128_t x, uint128_t y) { return x - y; } inline static bool FStar_UInt128_eq(uint128_t x, uint128_t y) { return x == y; } inline static bool FStar_UInt128_gt(uint128_t x, uint128_t y) { return x > y; } inline static bool FStar_UInt128_lt(uint128_t x, uint128_t y) { return x < y; } inline static bool FStar_UInt128_gte(uint128_t x, uint128_t y) { return x >= y; } inline static bool FStar_UInt128_lte(uint128_t x, uint128_t y) { return x <= y; } inline static uint128_t FStar_UInt128_mul32(uint64_t x, uint32_t y) { return (uint128_t) x * (uint128_t) y; } #endif liboprf-0.6.1/src/noise_xk/include/karmel/minimal/fstar_uint128_msvc.h000066400000000000000000000362401474121727000257310ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ /* This file was generated by KaRaMeL * then hand-edited to use MSVC intrinsics KaRaMeL invocation: * C:\users\barrybo\mitls2c\karamel\_build\src\Karamel.native -minimal -fnouint128 C:/users/barrybo/mitls2c/FStar/ulib/FStar.UInt128.fst -tmpdir ../secure_api/out/runtime_switch/uint128 -skip-compilation -add-include "krmllib0.h" -drop FStar.Int.Cast.Full -bundle FStar.UInt128=FStar.*,Prims * F* version: 15104ff8 * KaRaMeL version: 318b7fa8 */ #ifndef FSTAR_UINT128_MSVC #define FSTAR_UINT128_MSVC #include "krml/internal/types.h" #include "FStar_UInt128.h" #include "FStar_UInt_8_16_32_64.h" #ifndef _MSC_VER # error This file only works with the MSVC compiler #endif /* JP: need to rip out HAS_OPTIMIZED since the header guards in types.h are now * done properly and only include this file when we know for sure we are on * 64-bit MSVC. */ #if defined(_M_X64) && !defined(KRML_VERIFIED_UINT128) #define HAS_OPTIMIZED 1 #else #define HAS_OPTIMIZED 0 #endif // Define .low and .high in terms of the __m128i fields, to reduce // the amount of churn in this file. #if HAS_OPTIMIZED #include #include #define low m128i_u64[0] #define high m128i_u64[1] #endif inline static FStar_UInt128_uint128 load128_le(uint8_t *b) { #if HAS_OPTIMIZED return _mm_loadu_si128((__m128i *)b); #else FStar_UInt128_uint128 lit; lit.low = load64_le(b); lit.high = load64_le(b + 8); return lit; #endif } inline static void store128_le(uint8_t *b, FStar_UInt128_uint128 n) { store64_le(b, n.low); store64_le(b + 8, n.high); } inline static FStar_UInt128_uint128 load128_be(uint8_t *b) { uint64_t l = load64_be(b + 8); uint64_t h = load64_be(b); #if HAS_OPTIMIZED return _mm_set_epi64x(h, l); #else FStar_UInt128_uint128 lit; lit.low = l; lit.high = h; return lit; #endif } inline static void store128_be(uint8_t *b, uint128_t n) { store64_be(b, n.high); store64_be(b + 8, n.low); } inline static uint64_t FStar_UInt128_constant_time_carry(uint64_t a, uint64_t b) { return (a ^ (a ^ b | a - b ^ b)) >> (uint32_t)63U; } inline static uint64_t FStar_UInt128_carry(uint64_t a, uint64_t b) { return FStar_UInt128_constant_time_carry(a, b); } inline static FStar_UInt128_uint128 FStar_UInt128_add(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { #if HAS_OPTIMIZED uint64_t l, h; unsigned char carry = _addcarry_u64(0, a.low, b.low, &l); // low/CF = a.low+b.low+0 _addcarry_u64(carry, a.high, b.high, &h); // high = a.high+b.high+CF return _mm_set_epi64x(h, l); #else FStar_UInt128_uint128 lit; lit.low = a.low + b.low; lit.high = a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low); return lit; #endif } inline static FStar_UInt128_uint128 FStar_UInt128_add_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { #if HAS_OPTIMIZED return FStar_UInt128_add(a, b); #else FStar_UInt128_uint128 lit; lit.low = a.low + b.low; lit.high = a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low; return lit; #endif } inline static FStar_UInt128_uint128 FStar_UInt128_add_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { #if HAS_OPTIMIZED return FStar_UInt128_add(a, b); #else FStar_UInt128_uint128 lit; lit.low = a.low + b.low; lit.high = a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low); return lit; #endif } inline static FStar_UInt128_uint128 FStar_UInt128_sub(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { #if HAS_OPTIMIZED uint64_t l, h; unsigned char borrow = _subborrow_u64(0, a.low, b.low, &l); _subborrow_u64(borrow, a.high, b.high, &h); return _mm_set_epi64x(h, l); #else FStar_UInt128_uint128 lit; lit.low = a.low - b.low; lit.high = a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low); return lit; #endif } inline static FStar_UInt128_uint128 FStar_UInt128_sub_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { #if HAS_OPTIMIZED return FStar_UInt128_sub(a, b); #else FStar_UInt128_uint128 lit; lit.low = a.low - b.low; lit.high = a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low); return lit; #endif } inline static FStar_UInt128_uint128 FStar_UInt128_sub_mod_impl(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { FStar_UInt128_uint128 lit; lit.low = a.low - b.low; lit.high = a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low); return lit; } inline static FStar_UInt128_uint128 FStar_UInt128_sub_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { #if HAS_OPTIMIZED return FStar_UInt128_sub(a, b); #else return FStar_UInt128_sub_mod_impl(a, b); #endif } inline static FStar_UInt128_uint128 FStar_UInt128_logand(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { #if HAS_OPTIMIZED return _mm_and_si128(a, b); #else FStar_UInt128_uint128 lit; lit.low = a.low & b.low; lit.high = a.high & b.high; return lit; #endif } inline static FStar_UInt128_uint128 FStar_UInt128_logxor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { #if HAS_OPTIMIZED return _mm_xor_si128(a, b); #else FStar_UInt128_uint128 lit; lit.low = a.low ^ b.low; lit.high = a.high ^ b.high; return lit; #endif } inline static FStar_UInt128_uint128 FStar_UInt128_logor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { #if HAS_OPTIMIZED return _mm_or_si128(a, b); #else FStar_UInt128_uint128 lit; lit.low = a.low | b.low; lit.high = a.high | b.high; return lit; #endif } inline static FStar_UInt128_uint128 FStar_UInt128_lognot(FStar_UInt128_uint128 a) { #if HAS_OPTIMIZED return _mm_andnot_si128(a, a); #else FStar_UInt128_uint128 lit; lit.low = ~a.low; lit.high = ~a.high; return lit; #endif } static const uint32_t FStar_UInt128_u32_64 = (uint32_t)64U; inline static uint64_t FStar_UInt128_add_u64_shift_left(uint64_t hi, uint64_t lo, uint32_t s) { return (hi << s) + (lo >> FStar_UInt128_u32_64 - s); } inline static uint64_t FStar_UInt128_add_u64_shift_left_respec(uint64_t hi, uint64_t lo, uint32_t s) { return FStar_UInt128_add_u64_shift_left(hi, lo, s); } inline static FStar_UInt128_uint128 FStar_UInt128_shift_left_small(FStar_UInt128_uint128 a, uint32_t s) { if (s == (uint32_t)0U) return a; else { FStar_UInt128_uint128 lit; lit.low = a.low << s; lit.high = FStar_UInt128_add_u64_shift_left_respec(a.high, a.low, s); return lit; } } inline static FStar_UInt128_uint128 FStar_UInt128_shift_left_large(FStar_UInt128_uint128 a, uint32_t s) { FStar_UInt128_uint128 lit; lit.low = (uint64_t)0U; lit.high = a.low << s - FStar_UInt128_u32_64; return lit; } inline static FStar_UInt128_uint128 FStar_UInt128_shift_left(FStar_UInt128_uint128 a, uint32_t s) { #if HAS_OPTIMIZED if (s == 0) { return a; } else if (s < FStar_UInt128_u32_64) { uint64_t l = a.low << s; uint64_t h = __shiftleft128(a.low, a.high, (unsigned char)s); return _mm_set_epi64x(h, l); } else { return _mm_set_epi64x(a.low << (s - FStar_UInt128_u32_64), 0); } #else if (s < FStar_UInt128_u32_64) return FStar_UInt128_shift_left_small(a, s); else return FStar_UInt128_shift_left_large(a, s); #endif } inline static uint64_t FStar_UInt128_add_u64_shift_right(uint64_t hi, uint64_t lo, uint32_t s) { return (lo >> s) + (hi << FStar_UInt128_u32_64 - s); } inline static uint64_t FStar_UInt128_add_u64_shift_right_respec(uint64_t hi, uint64_t lo, uint32_t s) { return FStar_UInt128_add_u64_shift_right(hi, lo, s); } inline static FStar_UInt128_uint128 FStar_UInt128_shift_right_small(FStar_UInt128_uint128 a, uint32_t s) { if (s == (uint32_t)0U) return a; else { FStar_UInt128_uint128 lit; lit.low = FStar_UInt128_add_u64_shift_right_respec(a.high, a.low, s); lit.high = a.high >> s; return lit; } } inline static FStar_UInt128_uint128 FStar_UInt128_shift_right_large(FStar_UInt128_uint128 a, uint32_t s) { FStar_UInt128_uint128 lit; lit.low = a.high >> s - FStar_UInt128_u32_64; lit.high = (uint64_t)0U; return lit; } inline static FStar_UInt128_uint128 FStar_UInt128_shift_right(FStar_UInt128_uint128 a, uint32_t s) { #if HAS_OPTIMIZED if (s == 0) { return a; } else if (s < FStar_UInt128_u32_64) { uint64_t l = __shiftright128(a.low, a.high, (unsigned char)s); uint64_t h = a.high >> s; return _mm_set_epi64x(h, l); } else { return _mm_set_epi64x(0, a.high >> (s - FStar_UInt128_u32_64)); } #else if (s < FStar_UInt128_u32_64) return FStar_UInt128_shift_right_small(a, s); else return FStar_UInt128_shift_right_large(a, s); #endif } inline static bool FStar_UInt128_eq(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { return a.low == b.low && a.high == b.high; } inline static bool FStar_UInt128_gt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { return a.high > b.high || a.high == b.high && a.low > b.low; } inline static bool FStar_UInt128_lt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { return a.high < b.high || a.high == b.high && a.low < b.low; } inline static bool FStar_UInt128_gte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { return a.high > b.high || a.high == b.high && a.low >= b.low; } inline static bool FStar_UInt128_lte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { return a.high < b.high || a.high == b.high && a.low <= b.low; } inline static FStar_UInt128_uint128 FStar_UInt128_eq_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { #if HAS_OPTIMIZED // PCMPW to produce 4 32-bit values, all either 0x0 or 0xffffffff __m128i r32 = _mm_cmpeq_epi32(a, b); // Shuffle 3,2,1,0 into 2,3,0,1 (swapping dwords inside each half) __m128i s32 = _mm_shuffle_epi32(r32, _MM_SHUFFLE(2, 3, 0, 1)); // Bitwise and to compute (3&2),(2&3),(1&0),(0&1) __m128i ret64 = _mm_and_si128(r32, s32); // Swap the two 64-bit values to form s64 __m128i s64 = _mm_shuffle_epi32(ret64, _MM_SHUFFLE(1, 0, 3, 2)); // 3,2,1,0 -> 1,0,3,2 // And them together return _mm_and_si128(ret64, s64); #else FStar_UInt128_uint128 lit; lit.low = FStar_UInt64_eq_mask(a.low, b.low) & FStar_UInt64_eq_mask(a.high, b.high); lit.high = FStar_UInt64_eq_mask(a.low, b.low) & FStar_UInt64_eq_mask(a.high, b.high); return lit; #endif } inline static FStar_UInt128_uint128 FStar_UInt128_gte_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) { #if HAS_OPTIMIZED && 0 // ge - compare 3,2,1,0 for >= and generating 0 or 0xffffffff for each // eq - compare 3,2,1,0 for == and generating 0 or 0xffffffff for each // slot 0 = ge0 | (eq0 & ge1) | (eq0 & eq1 & ge2) | (eq0 & eq1 & eq2 & ge3) // then splat slot 0 to 3,2,1,0 __m128i gt = _mm_cmpgt_epi32(a, b); __m128i eq = _mm_cmpeq_epi32(a, b); __m128i ge = _mm_or_si128(gt, eq); __m128i ge0 = ge; __m128i eq0 = eq; __m128i ge1 = _mm_srli_si128(ge, 4); // shift ge from 3,2,1,0 to 0x0,3,2,1 __m128i t1 = _mm_and_si128(eq0, ge1); __m128i ret = _mm_or_si128(ge, t1); // ge0 | (eq0 & ge1) is now in 0 __m128i eq1 = _mm_srli_si128(eq, 4); // shift eq from 3,2,1,0 to 0x0,3,2,1 __m128i ge2 = _mm_srli_si128(ge1, 4); // shift original ge from 3,2,1,0 to 0x0,0x0,3,2 __m128i t2 = _mm_and_si128(eq0, _mm_and_si128(eq1, ge2)); // t2 = (eq0 & eq1 & ge2) ret = _mm_or_si128(ret, t2); __m128i eq2 = _mm_srli_si128(eq1, 4); // shift eq from 3,2,1,0 to 0x0,00,00,3 __m128i ge3 = _mm_srli_si128(ge2, 4); // shift original ge from 3,2,1,0 to 0x0,0x0,0x0,3 __m128i t3 = _mm_and_si128( eq0, _mm_and_si128( eq1, _mm_and_si128(eq2, ge3))); // t3 = (eq0 & eq1 & eq2 & ge3) ret = _mm_or_si128(ret, t3); return _mm_shuffle_epi32( ret, _MM_SHUFFLE(0, 0, 0, 0)); // the result is in 0. Shuffle into all dwords. #else FStar_UInt128_uint128 lit; lit.low = FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high) | FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low); lit.high = FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high) | FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low); return lit; #endif } inline static FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t a) { #if HAS_OPTIMIZED return _mm_set_epi64x(0, a); #else FStar_UInt128_uint128 lit; lit.low = a; lit.high = (uint64_t)0U; return lit; #endif } inline static uint64_t FStar_UInt128_uint128_to_uint64(FStar_UInt128_uint128 a) { return a.low; } inline static uint64_t FStar_UInt128_u64_mod_32(uint64_t a) { return a & (uint64_t)0xffffffffU; } static uint32_t FStar_UInt128_u32_32 = (uint32_t)32U; inline static uint64_t FStar_UInt128_u32_combine(uint64_t hi, uint64_t lo) { return lo + (hi << FStar_UInt128_u32_32); } inline static FStar_UInt128_uint128 FStar_UInt128_mul32(uint64_t x, uint32_t y) { #if HAS_OPTIMIZED uint64_t l, h; l = _umul128(x, (uint64_t)y, &h); return _mm_set_epi64x(h, l); #else FStar_UInt128_uint128 lit; lit.low = FStar_UInt128_u32_combine( (x >> FStar_UInt128_u32_32) * (uint64_t)y + (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32), FStar_UInt128_u64_mod_32(FStar_UInt128_u64_mod_32(x) * (uint64_t)y)); lit.high = (x >> FStar_UInt128_u32_32) * (uint64_t)y + (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32) >> FStar_UInt128_u32_32; return lit; #endif } /* Note: static headers bring scope collision issues when they define types! * Because now client (karamel-generated) code will include this header and * there might be type collisions if the client code uses quadruples of uint64s. * So, we cannot use the karamel-generated name. */ typedef struct K_quad_s { uint64_t fst; uint64_t snd; uint64_t thd; uint64_t f3; } K_quad; inline static K_quad FStar_UInt128_mul_wide_impl_t_(uint64_t x, uint64_t y) { K_quad tmp; tmp.fst = FStar_UInt128_u64_mod_32(x); tmp.snd = FStar_UInt128_u64_mod_32( FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y)); tmp.thd = x >> FStar_UInt128_u32_32; tmp.f3 = (x >> FStar_UInt128_u32_32) * FStar_UInt128_u64_mod_32(y) + (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32); return tmp; } static uint64_t FStar_UInt128_u32_combine_(uint64_t hi, uint64_t lo) { return lo + (hi << FStar_UInt128_u32_32); } inline static FStar_UInt128_uint128 FStar_UInt128_mul_wide_impl(uint64_t x, uint64_t y) { K_quad scrut = FStar_UInt128_mul_wide_impl_t_(x, y); uint64_t u1 = scrut.fst; uint64_t w3 = scrut.snd; uint64_t x_ = scrut.thd; uint64_t t_ = scrut.f3; FStar_UInt128_uint128 lit; lit.low = FStar_UInt128_u32_combine_( u1 * (y >> FStar_UInt128_u32_32) + FStar_UInt128_u64_mod_32(t_), w3); lit.high = x_ * (y >> FStar_UInt128_u32_32) + (t_ >> FStar_UInt128_u32_32) + (u1 * (y >> FStar_UInt128_u32_32) + FStar_UInt128_u64_mod_32(t_) >> FStar_UInt128_u32_32); return lit; } inline static FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x, uint64_t y) { #if HAS_OPTIMIZED uint64_t l, h; l = _umul128(x, y, &h); return _mm_set_epi64x(h, l); #else return FStar_UInt128_mul_wide_impl(x, y); #endif } #undef low #undef high #endif liboprf-0.6.1/src/noise_xk/include/karmel/minimal/fstar_uint128_struct_endianness.h000066400000000000000000000031611474121727000305100ustar00rootroot00000000000000/* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. Licensed under the Apache 2.0 License. */ #ifndef FSTAR_UINT128_STRUCT_ENDIANNESS_H #define FSTAR_UINT128_STRUCT_ENDIANNESS_H /* Hand-written implementation of endianness-related uint128 functions * for the extracted uint128 implementation */ /* Access 64-bit fields within the int128. */ #define HIGH64_OF(x) ((x)->high) #define LOW64_OF(x) ((x)->low) /* A series of definitions written using pointers. */ inline static void load128_le_(uint8_t *b, uint128_t *r) { LOW64_OF(r) = load64_le(b); HIGH64_OF(r) = load64_le(b + 8); } inline static void store128_le_(uint8_t *b, uint128_t *n) { store64_le(b, LOW64_OF(n)); store64_le(b + 8, HIGH64_OF(n)); } inline static void load128_be_(uint8_t *b, uint128_t *r) { HIGH64_OF(r) = load64_be(b); LOW64_OF(r) = load64_be(b + 8); } inline static void store128_be_(uint8_t *b, uint128_t *n) { store64_be(b, HIGH64_OF(n)); store64_be(b + 8, LOW64_OF(n)); } #ifndef KRML_NOSTRUCT_PASSING inline static uint128_t load128_le(uint8_t *b) { uint128_t r; load128_le_(b, &r); return r; } inline static void store128_le(uint8_t *b, uint128_t n) { store128_le_(b, &n); } inline static uint128_t load128_be(uint8_t *b) { uint128_t r; load128_be_(b, &r); return r; } inline static void store128_be(uint8_t *b, uint128_t n) { store128_be_(b, &n); } #else /* !defined(KRML_STRUCT_PASSING) */ # define print128 print128_ # define load128_le load128_le_ # define store128_le store128_le_ # define load128_be load128_be_ # define store128_be store128_be_ #endif /* KRML_STRUCT_PASSING */ #endif liboprf-0.6.1/src/noise_xk/include/karmel/minimal/libkrmllib.def000066400000000000000000000003261474121727000247160ustar00rootroot00000000000000LIBRARY libkrmllib EXPORTS FStar_UInt64_eq_mask FStar_UInt64_gte_mask FStar_UInt32_eq_mask FStar_UInt32_gte_mask FStar_UInt16_eq_mask FStar_UInt16_gte_mask FStar_UInt8_eq_mask FStar_UInt8_gte_mask liboprf-0.6.1/src/noise_xk/include/noise_private.h000066400000000000000000000036441474121727000222400ustar00rootroot00000000000000#ifndef noise_xk_private_h #define noise_xk_private_h #include #include "XK.h" #undef Noise_XK_init_state_t_s typedef struct Noise_XK_init_state_t_s { Noise_XK_init_state_t_tags tag; union { struct { uint32_t step; uint8_t *cipher_key; uint8_t *chaining_key; uint8_t *h; uint8_t *spriv; uint8_t *spub; uint8_t *epriv; uint8_t *epub; uint8_t *rs; uint8_t *re; } case_IMS_Handshake; struct { uint8_t *h; bool recv_transport_message; uint8_t *send_key; uint64_t send_nonce; uint8_t *receive_key; uint64_t receive_nonce; } case_IMS_Transport; } val; } Noise_XK_init_state_t; #undef Noise_XK_resp_state_t_s typedef struct Noise_XK_resp_state_t_s { Noise_XK_init_state_t_tags tag; union { struct { uint32_t step; uint8_t *cipher_key; uint8_t *chaining_key; uint8_t *h; uint8_t *spriv; uint8_t *spub; uint8_t *epriv; uint8_t *epub; uint8_t *rs; uint8_t *re; } case_IMS_Handshake; struct { uint8_t *h; uint8_t *send_key; uint64_t send_nonce; uint8_t *receive_key; uint64_t receive_nonce; } case_IMS_Transport; } val; } Noise_XK_resp_state_t; #undef Noise_XK_session_t_s typedef struct Noise_XK_session_t_s { Noise_XK_session_t_tags tag; union { struct { Noise_XK_init_state_t state; uint32_t id; Noise_XK_noise_string *info; uint8_t *spriv; uint8_t *spub; uint32_t pid; Noise_XK_noise_string *pinfo; Noise_XK_device_t *dv; } case_DS_Initiator; struct { Noise_XK_resp_state_t state; uint32_t id; Noise_XK_noise_string *info; uint8_t *spriv; uint8_t *spub; uint32_t pid; Noise_XK_noise_string *pinfo; Noise_XK_device_t *dv; } case_DS_Responder; } val; } Noise_XK_session_t; #endif // noise_xk_private_h liboprf-0.6.1/src/noise_xk/makefile000066400000000000000000000043251474121727000172720ustar00rootroot00000000000000PREFIX?=/usr/local LDFLAGS=-lsodium SOURCES=src/Noise_XK.c src/XK.c CFLAGS ?= -Iinclude -I include/karmel -I include/karmel/minimal \ -Wall -Wextra -Werror -std=c11 -Wno-unused-variable \ -Wno-unknown-warning-option -Wno-unused-but-set-variable \ -Wno-unused-parameter -Wno-infinite-recursion -fpic \ -g -fwrapv -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM \ -O2 -fstack-protector-strong -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \ -fasynchronous-unwind-tables -fpic \ -Werror=format-security -Werror=implicit-function-declaration \ -ftrapv CC?=gcc SOEXT?=so STATICEXT?=a SOVER=0 UNAME := $(shell uname -s) ARCH := $(shell uname -m) ifeq ($(UNAME),Darwin) SOEXT=dylib SOFLAGS=-Wl,-install_name,$(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(SOEXT) else ifeq ($(shell uname),Linux) CFLAGS += -Wl,--error-unresolved-symbols -Wl,-z,defs -Wl,-z,relro -Wl,-z,noexecstack SOEXT=so SOFLAGS=-Wl,-soname,liboprf-noiseXK.$(SOEXT).$(SOVER) endif ifeq ($(ARCH),x86_64) CFLAGS+=-fcf-protection=full endif ifeq ($(ARCH),parisc64) else ifeq ($(ARCH),parisc64) else CFLAGS+=-fstack-clash-protection endif endif OBJS += $(patsubst %.c,%.o,$(SOURCES)) all: liboprf-noiseXK.$(STATICEXT) liboprf-noiseXK.$(SOEXT) AR ?= ar %.$(STATICEXT): $(OBJS) $(AR) rcs $@ $^ %.$(SOEXT): $(OBJS) $(CC) $(CFLAGS) -fPIC -shared $(SOFLAGS) -o $@ $^ $(LDFLAGS) clean: rm -rf *.so *.a src/*.o make -C example clean liboprf-noiseXK.$(SOEXT).$(SOVER): liboprf-noiseXK.$(SOEXT) ln -sf $^ $@ install: $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(SOEXT) $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(STATICEXT) $(DESTDIR)$(PREFIX)/include/oprf/noiseXK uninstall: $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(SOEXT) $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(STATICEXT) $(DESTDIR)$(PREFIX)/include/oprf/noiseXK rm -rf $^ $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(SOEXT): liboprf-noiseXK.$(SOEXT) mkdir -p $(DESTDIR)$(PREFIX)/lib/ cp $< $@.$(SOVER) ln -sf $@.$(SOVER) $@ $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(STATICEXT): liboprf-noiseXK.$(STATICEXT) mkdir -p $(DESTDIR)$(PREFIX)/lib/ cp $< $@ $(DESTDIR)$(PREFIX)/include/oprf/noiseXK: include cp -r $< $@ test: liboprf-noiseXK.$(SOEXT).$(SOVER) make -C example test liboprf-0.6.1/src/noise_xk/noise-star.patch000066400000000000000000000354411474121727000207020ustar00rootroot00000000000000diff --git a/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Makefile.basic b/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Makefile.basic index 1698d85..c4b7fef 100644 --- a/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Makefile.basic +++ b/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Makefile.basic @@ -29,6 +29,7 @@ OBJS += $(patsubst %.c,%.o,$(SOURCES)) all: $(USER_TARGET) $(USER_TARGET): $(OBJS) + cc $(CFLAGS) $^ xk-ex.c -o $@ $(LDFLAGS) AR ?= ar diff --git a/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Makefile.include b/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Makefile.include index ea66194..024d749 100644 --- a/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Makefile.include +++ b/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Makefile.include @@ -1,5 +1,8 @@ -USER_TARGET=libnoiseapi.a -USER_CFLAGS= +LDFLAGS=-lsodium +#LDFLAGS=-L$(HACL_HOME)/dist/gcc-compatible -levercrypt +USER_TARGET=libnoiseapi.a xk-ex +USER_CFLAGS= -DWITH_SODIUM +#USER_CFLAGS= USER_C_FILES= ALL_C_FILES=Noise_XK.c XK.c ALL_H_FILES=Hacl.h Noise_XK.h XK.h diff --git a/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Noise_XK.c b/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Noise_XK.c index 746f704..c953f01 100644 --- a/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Noise_XK.c +++ b/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Noise_XK.c @@ -1,6 +1,5 @@ /** This file was automatically generated */ - #include "Noise_XK.h" inline bool Noise_XK_lbytes_eq(uint32_t len, uint8_t *b1, uint8_t *b2) @@ -28,13 +27,22 @@ uint64_t Noise_XK_bytes_to_nonce(uint8_t *n8) Noise_XK_error_code Noise_XK_dh_secret_to_public(uint8_t *dest, uint8_t *priv) { +#ifdef WITH_SODIUM + crypto_scalarmult_base(dest, priv); +#else // WITH_SODIUM Hacl_Curve25519_64_secret_to_public(dest, priv); +#endif // WITH_SODIUM return Noise_XK_CSuccess; } Noise_XK_error_code Noise_XK_dh(uint8_t *dest, uint8_t *priv, uint8_t *pub) { +#ifdef WITH_SODIUM + bool b = crypto_scalarmult(dest, priv, pub) == 0; +#else // WITH_SODIUM bool b = Hacl_Curve25519_64_ecdh(dest, priv, pub); +#endif // WITH_SODIUM + if (b) return Noise_XK_CSuccess; else @@ -52,6 +60,9 @@ Noise_XK_aead_encrypt( uint8_t *cipher ) { +#ifdef WITH_SODIUM + crypto_aead_chacha20poly1305_encrypt(cipher, NULL, plain, plen, aad, aad_len, NULL, (uint8_t*) &nonce, key); +#else uint8_t n12[12U] = { 0U }; uint8_t *nonce12_end = n12 + (uint32_t)4U; store64_le(nonce12_end, nonce); @@ -59,6 +70,7 @@ Noise_XK_aead_encrypt( uint8_t *tag = cipher + plen; Hacl_Chacha20Poly1305_32_aead_encrypt(key, n12, aad_len, aad, plen, plain, output, tag); Lib_Memzero0_memzero(n12, (uint32_t)12U * sizeof (n12[0U])); +#endif // WITH_SODIUM } Noise_XK_error_code @@ -72,6 +84,18 @@ Noise_XK_aead_decrypt( uint8_t *cipher ) { +#ifdef WITH_SODIUM + uint32_t + r = crypto_aead_chacha20poly1305_decrypt(plain, // plaintext + NULL, // *plen + NULL, // nsec + cipher, + plen + crypto_aead_chacha20poly1305_ABYTES, + aad, + aad_len, + (uint8_t*) &nonce, + key); +#else // WITH_SODIUM uint8_t n12[12U] = { 0U }; uint8_t *nonce12_end = n12 + (uint32_t)4U; store64_le(nonce12_end, nonce); @@ -80,6 +104,7 @@ Noise_XK_aead_decrypt( uint32_t r = Hacl_Chacha20Poly1305_32_aead_decrypt(key, n12, aad_len, aad, plen, plain, output, tag); Lib_Memzero0_memzero(n12, (uint32_t)12U * sizeof (n12[0U])); +#endif // WITH_SODIUM if (r == (uint32_t)0U) return Noise_XK_CSuccess; else @@ -88,11 +113,22 @@ Noise_XK_aead_decrypt( void Noise_XK_hash(uint8_t *output, uint32_t inlen, uint8_t *input) { +#ifdef WITH_SODIUM + crypto_generichash(output, (uint32_t)64U, input, inlen, NULL, 0); +#else // WITH_SODIUM Hacl_Blake2b_32_blake2b((uint32_t)64U, output, inlen, input, (uint32_t)0U, NULL); +#endif // WITH_SODIUM } void Noise_XK_mix_hash(uint8_t *hash1, uint32_t inlen, uint8_t *input) { +#ifdef WITH_SODIUM + crypto_generichash_state state; + crypto_generichash_init(&state, NULL, 0, 64); + crypto_generichash_update(&state, hash1, 64); + crypto_generichash_update(&state, input, inlen); + crypto_generichash_final(&state, hash1, 64); +#else // WITH_SODIUM KRML_CHECK_SIZE(sizeof (uint8_t), Hacl_Streaming_Blake2_blocks_state_len(Spec_Blake2_Blake2B, Hacl_Impl_Blake2_Core_M32)); uint8_t @@ -121,12 +157,17 @@ void Noise_XK_mix_hash(uint8_t *hash1, uint32_t inlen, uint8_t *input) Hacl_Streaming_Blake2_blake2b_32_no_key_update(s0, hash1, (uint32_t)64U); Hacl_Streaming_Blake2_blake2b_32_no_key_update(s0, input, inlen); Hacl_Streaming_Blake2_blake2b_32_no_key_finish(s0, hash1); +#endif // WITH_SODIUM } void Noise_XK_hmac(uint8_t *output, uint32_t keylen, uint8_t *key, uint32_t datalen, uint8_t *data) { +#ifdef WITH_SODIUM + crypto_generichash(output, 64, data, datalen, key, keylen); +#else // WITH_SODIUM Hacl_HMAC_compute_blake2b_32(output, key, keylen, data, datalen); +#endif // WITH_SODIUM } void @@ -162,8 +203,13 @@ Noise_XK_kdf( } } } +#ifdef WITH_SODIUM + sodium_memzero(output, (uint32_t)65U * sizeof (output[0U])); + sodium_memzero(secret, (uint32_t)64U * sizeof (secret[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(output, (uint32_t)65U * sizeof (output[0U])); Lib_Memzero0_memzero(secret, (uint32_t)64U * sizeof (secret[0U])); +#endif // WITH_SODIUM } void Noise_XK_mix_psk(uint8_t *psk, uint8_t *st_cs_k, uint8_t *st_ck, uint8_t *st_h) @@ -172,9 +218,17 @@ void Noise_XK_mix_psk(uint8_t *psk, uint8_t *st_cs_k, uint8_t *st_ck, uint8_t *s uint8_t temp_k[64U] = { 0U }; Noise_XK_kdf(st_ck, (uint32_t)32U, psk, st_ck, temp_hash, temp_k); memcpy(st_cs_k, temp_k, (uint32_t)32U * sizeof (uint8_t)); +#ifdef WITH_SODIUM + sodium_memzero(temp_k, (uint32_t)64U * sizeof (temp_k[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(temp_k, (uint32_t)64U * sizeof (temp_k[0U])); +#endif // WITH_SODIUM Noise_XK_mix_hash(st_h, (uint32_t)64U, temp_hash); +#ifdef WITH_SODIUM + sodium_memzero(temp_hash, (uint32_t)64U * sizeof (temp_hash[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(temp_hash, (uint32_t)64U * sizeof (temp_hash[0U])); +#endif // WITH_SODIUM } void @@ -224,13 +278,21 @@ Noise_XK_mix_dh(uint8_t *sec, uint8_t *pub, uint8_t *cipher_key, uint8_t *ck, ui uint8_t temp_k[64U] = { 0U }; Noise_XK_kdf(ck, (uint32_t)32U, dh_key, ck, temp_k, NULL); memcpy(cipher_key, temp_k, (uint32_t)32U * sizeof (uint8_t)); +#ifdef WITH_SODIUM + sodium_memzero(temp_k, (uint32_t)64U * sizeof (temp_k[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(temp_k, (uint32_t)64U * sizeof (temp_k[0U])); +#endif // WITH_SODIUM r2 = Noise_XK_CSuccess; } else r2 = r1; Noise_XK_error_code r = r2; +#ifdef WITH_SODIUM + sodium_memzero(dh_key, (uint32_t)32U * sizeof (dh_key[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(dh_key, (uint32_t)32U * sizeof (dh_key[0U])); +#endif // WITH_SODIUM return r; } diff --git a/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Noise_XK.h b/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Noise_XK.h index b92393c..f99a332 100644 --- a/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Noise_XK.h +++ b/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/Noise_XK.h @@ -8,7 +8,11 @@ #include "krml/internal/types.h" +#ifdef WITH_SODIUM +#include +#else // WITH_SODIUM #include "Hacl.h" +#endif // WITH_SODIUM #define Noise_XK_CSuccess 0 #define Noise_XK_CIncorrect_transition 1 diff --git a/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/XK.c b/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/XK.c index bd4c689..63f42c7 100644 --- a/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/XK.c +++ b/noise-all/api-XK/XK_25519_ChaChaPoly_BLAKE2b/XK.c @@ -754,7 +754,11 @@ void Noise_XK_serialize_device_secret(uint32_t *outlen, uint8_t **out, Noise_XK_ uint8_t *name_raw = scrut.snd; uint8_t *n8 = outb; uint8_t *c = outb + (uint32_t)8U; +#ifdef WITH_SODIUM + randombytes_buf(n8, (uint32_t)8U); +#else // WITH_SODIUM Lib_RandomBuffer_System_crypto_random(n8, (uint32_t)8U); +#endif // WITH_SODIUM uint64_t n = Noise_XK_bytes_to_nonce(n8); Noise_XK_aead_encrypt(dv.dv_sk, n, name_raw_len, name_raw, (uint32_t)32U, dv.dv_spriv, c); out[0U] = outb; @@ -995,7 +999,11 @@ void Noise_XK_device_remove_peer(Noise_XK_device_t *dvp, uint32_t pid) if (!(str == NULL)) KRML_HOST_FREE(str); KRML_HOST_FREE(p.p_info); +#ifdef WITH_SODIUM + sodium_memzero(p.p_s, (uint32_t)32U * sizeof (p.p_s[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(p.p_s, (uint32_t)32U * sizeof (p.p_s[0U])); +#endif // WITH_SODIUM KRML_HOST_FREE(p.p_s); KRML_HOST_FREE(c1.data); KRML_HOST_FREE(c01.next); @@ -1011,7 +1019,11 @@ void Noise_XK_device_remove_peer(Noise_XK_device_t *dvp, uint32_t pid) if (!(str == NULL)) KRML_HOST_FREE(str); KRML_HOST_FREE(p.p_info); +#ifdef WITH_SODIUM + sodium_memzero(p.p_s, (uint32_t)32U * sizeof (p.p_s[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(p.p_s, (uint32_t)32U * sizeof (p.p_s[0U])); +#endif // WITH_SODIUM KRML_HOST_FREE(p.p_s); KRML_HOST_FREE(elem1); } @@ -1077,7 +1089,11 @@ Noise_XK_serialize_peer_secret( uint8_t *name_raw = scrut.snd; uint8_t *n8 = outb; uint8_t *c = outb + (uint32_t)8U; +#ifdef WITH_SODIUM + randombytes_buf(n8, (uint32_t)8U); +#else // WITH_SODIUM Lib_RandomBuffer_System_crypto_random(n8, (uint32_t)8U); +#endif // WITH_SODIUM uint64_t n = Noise_XK_bytes_to_nonce(n8); Noise_XK_aead_encrypt(dv.dv_sk, n, name_raw_len, name_raw, (uint32_t)32U, concat_keys, c); out[0U] = outb; @@ -1634,7 +1650,11 @@ Noise_XK_session_t *Noise_XK_session_create_initiator(Noise_XK_device_t *dvp, ui { uint8_t epriv[32U] = { 0U }; uint8_t epub[32U] = { 0U }; +#ifdef WITH_SODIUM + randombytes_buf(epriv, (uint32_t)32U); +#else // WITH_SODIUM Lib_RandomBuffer_System_crypto_random(epriv, (uint32_t)32U); +#endif // WITH_SODIUM Noise_XK_error_code res0 = Noise_XK_dh_secret_to_public(epub, epriv); Noise_XK_session_t *res; switch (res0) @@ -1929,8 +1949,13 @@ Noise_XK_session_t *Noise_XK_session_create_initiator(Noise_XK_device_t *dvp, ui res = NULL; } } +#ifdef WITH_SODIUM + sodium_memzero(epriv, (uint32_t)32U * sizeof (epriv[0U])); + sodium_memzero(epub, (uint32_t)32U * sizeof (epub[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(epriv, (uint32_t)32U * sizeof (epriv[0U])); Lib_Memzero0_memzero(epub, (uint32_t)32U * sizeof (epub[0U])); +#endif // WITH_SODIUM Noise_XK_session_t *res1 = res; return res1; } @@ -1944,7 +1969,11 @@ Noise_XK_session_t *Noise_XK_session_create_responder(Noise_XK_device_t *dvp) { uint8_t epriv[32U] = { 0U }; uint8_t epub[32U] = { 0U }; +#ifdef WITH_SODIUM + randombytes_buf(epriv, (uint32_t)32U); +#else // WITH_SODIUM Lib_RandomBuffer_System_crypto_random(epriv, (uint32_t)32U); +#endif // WITH_SODIUM Noise_XK_error_code res0 = Noise_XK_dh_secret_to_public(epub, epriv); Noise_XK_session_t *res; switch (res0) @@ -2134,8 +2163,13 @@ Noise_XK_session_t *Noise_XK_session_create_responder(Noise_XK_device_t *dvp) res = NULL; } } +#ifdef WITH_SODIUM + sodium_memzero(epriv, (uint32_t)32U * sizeof (epriv[0U])); + sodium_memzero(epub, (uint32_t)32U * sizeof (epub[0U])); +#else //WITH_SODIUM Lib_Memzero0_memzero(epriv, (uint32_t)32U * sizeof (epriv[0U])); Lib_Memzero0_memzero(epub, (uint32_t)32U * sizeof (epub[0U])); +#endif //WITH_SODIUM Noise_XK_session_t *res1 = res; return res1; } @@ -2520,8 +2554,13 @@ state_handshake_write( Noise_XK_kdf(st_ck1, (uint32_t)0U, NULL, temp_k1, temp_k2, NULL); memcpy(k1, temp_k1, (uint32_t)32U * sizeof (uint8_t)); memcpy(k2, temp_k2, (uint32_t)32U * sizeof (uint8_t)); +#ifdef WITH_SODIUM + sodium_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); + sodium_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); Lib_Memzero0_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); +#endif // WITH_SODIUM KRML_HOST_FREE(st_k); KRML_HOST_FREE(st_ck1); KRML_HOST_FREE(st_epriv1); @@ -2721,8 +2760,13 @@ state_handshake_write( Noise_XK_kdf(st_ck1, (uint32_t)0U, NULL, temp_k1, temp_k2, NULL); memcpy(k1, temp_k1, (uint32_t)32U * sizeof (uint8_t)); memcpy(k2, temp_k2, (uint32_t)32U * sizeof (uint8_t)); +#ifdef WITH_SODIUM + sodium_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); + sodium_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); Lib_Memzero0_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); +#endif // WITH_SODIUM KRML_HOST_FREE(st_k); KRML_HOST_FREE(st_ck1); KRML_HOST_FREE(st_epriv1); @@ -3190,8 +3234,13 @@ state_handshake_read( Noise_XK_kdf(st_ck1, (uint32_t)0U, NULL, temp_k1, temp_k2, NULL); memcpy(k1, temp_k1, (uint32_t)32U * sizeof (uint8_t)); memcpy(k2, temp_k2, (uint32_t)32U * sizeof (uint8_t)); +#ifdef WITH_SODIUM + sodium_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); + sodium_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); Lib_Memzero0_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); +#endif // WITH_SODIUM KRML_HOST_FREE(st_k); KRML_HOST_FREE(st_ck1); KRML_HOST_FREE(st_epriv1); @@ -3647,8 +3696,13 @@ state_handshake_read( Noise_XK_kdf(st_ck1, (uint32_t)0U, NULL, temp_k1, temp_k2, NULL); memcpy(k1, temp_k1, (uint32_t)32U * sizeof (uint8_t)); memcpy(k2, temp_k2, (uint32_t)32U * sizeof (uint8_t)); +#ifdef WITH_SODIUM + sodium_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); + sodium_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); +#else // WITH_SODIUM Lib_Memzero0_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); Lib_Memzero0_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); +#endif // WITH_SODIUM KRML_HOST_FREE(st_k); KRML_HOST_FREE(st_ck1); KRML_HOST_FREE(st_epriv1); liboprf-0.6.1/src/noise_xk/src/000077500000000000000000000000001474121727000163555ustar00rootroot00000000000000liboprf-0.6.1/src/noise_xk/src/Noise_XK.c000066400000000000000000000251221474121727000202020ustar00rootroot00000000000000/** This file was automatically generated */ #include "Noise_XK.h" inline bool Noise_XK_lbytes_eq(uint32_t len, uint8_t *b1, uint8_t *b2) { uint8_t accp = (uint8_t)0U; for (uint32_t i = (uint32_t)0U; i < len; i++) { uint8_t x1 = b1[i]; uint8_t x2 = b2[i]; uint8_t diff = x1 ^ x2; uint8_t acc = accp; uint8_t acc_ = diff | acc; accp = acc_; } uint8_t r = accp; return r == (uint8_t)0U; } uint64_t Noise_XK_bytes_to_nonce(uint8_t *n8) { uint64_t u = load64_le(n8); uint64_t nonce = u; return nonce; } Noise_XK_error_code Noise_XK_dh_secret_to_public(uint8_t *dest, uint8_t *priv) { #ifndef WITH_HACL crypto_scalarmult_base(dest, priv); #else // WITH_SODIUM Hacl_Curve25519_64_secret_to_public(dest, priv); #endif // WITH_SODIUM return Noise_XK_CSuccess; } Noise_XK_error_code Noise_XK_dh(uint8_t *dest, uint8_t *priv, uint8_t *pub) { #ifndef WITH_HACL bool b = crypto_scalarmult(dest, priv, pub) == 0; #else // WITH_SODIUM bool b = Hacl_Curve25519_64_ecdh(dest, priv, pub); #endif // WITH_SODIUM if (b) return Noise_XK_CSuccess; else return Noise_XK_CDH_error; } void Noise_XK_aead_encrypt( uint8_t *key, uint64_t nonce, uint32_t aad_len, uint8_t *aad, uint32_t plen, uint8_t *plain, uint8_t *cipher ) { uint8_t n12[12U] = { 0U }; uint8_t *nonce12_end = n12 + (uint32_t)4U; store64_le(nonce12_end, nonce); #ifndef WITH_HACL crypto_aead_chacha20poly1305_ietf_encrypt(cipher, NULL, plain, plen, aad, aad_len, NULL, n12, key); sodium_memzero(n12, (uint32_t)12U * sizeof (n12[0U])); #else uint8_t *output = cipher; uint8_t *tag = cipher + plen; Hacl_Chacha20Poly1305_32_aead_encrypt(key, n12, aad_len, aad, plen, plain, output, tag); Lib_Memzero0_memzero(n12, (uint32_t)12U * sizeof (n12[0U])); #endif // WITH_SODIUM } Noise_XK_error_code Noise_XK_aead_decrypt( uint8_t *key, uint64_t nonce, uint32_t aad_len, uint8_t *aad, uint32_t plen, uint8_t *plain, uint8_t *cipher ) { uint8_t n12[12U] = { 0U }; uint8_t *nonce12_end = n12 + (uint32_t)4U; store64_le(nonce12_end, nonce); #ifndef WITH_HACL uint32_t r = crypto_aead_chacha20poly1305_ietf_decrypt(plain, NULL, // *plen NULL, // nsec cipher, plen + crypto_aead_chacha20poly1305_ABYTES, aad, aad_len, n12, key); sodium_memzero(n12, (uint32_t)12U * sizeof (n12[0U])); #else // WITH_SODIUM uint8_t *output = cipher; uint8_t *tag = cipher + plen; uint32_t r = Hacl_Chacha20Poly1305_32_aead_decrypt(key, n12, aad_len, aad, plen, plain, output, tag); Lib_Memzero0_memzero(n12, (uint32_t)12U * sizeof (n12[0U])); #endif // WITH_SODIUM if (r == (uint32_t)0U) return Noise_XK_CSuccess; else return Noise_XK_CDecrypt_error; } void Noise_XK_hash(uint8_t *output, uint32_t inlen, uint8_t *input) { #ifndef WITH_HACL crypto_generichash(output, (uint32_t)64U, input, inlen, NULL, 0); #else // WITH_SODIUM Hacl_Blake2b_32_blake2b((uint32_t)64U, output, inlen, input, (uint32_t)0U, NULL); #endif // WITH_SODIUM } void Noise_XK_mix_hash(uint8_t *hash1, uint32_t inlen, uint8_t *input) { #ifndef WITH_HACL crypto_generichash_state state; crypto_generichash_init(&state, NULL, 0, 64); crypto_generichash_update(&state, hash1, 64); crypto_generichash_update(&state, input, inlen); crypto_generichash_final(&state, hash1, 64); #else // WITH_SODIUM KRML_CHECK_SIZE(sizeof (uint8_t), Hacl_Streaming_Blake2_blocks_state_len(Spec_Blake2_Blake2B, Hacl_Impl_Blake2_Core_M32)); uint8_t buf[Hacl_Streaming_Blake2_blocks_state_len(Spec_Blake2_Blake2B, Hacl_Impl_Blake2_Core_M32)]; memset(buf, 0U, Hacl_Streaming_Blake2_blocks_state_len(Spec_Blake2_Blake2B, Hacl_Impl_Blake2_Core_M32) * sizeof (uint8_t)); KRML_CHECK_SIZE(sizeof (uint64_t), (uint32_t)4U * (uint32_t)4U); uint64_t wv[(uint32_t)4U * (uint32_t)4U]; memset(wv, 0U, (uint32_t)4U * (uint32_t)4U * sizeof (uint64_t)); KRML_CHECK_SIZE(sizeof (uint64_t), (uint32_t)4U * (uint32_t)4U); uint64_t b[(uint32_t)4U * (uint32_t)4U]; memset(b, 0U, (uint32_t)4U * (uint32_t)4U * sizeof (uint64_t)); Hacl_Streaming_Blake2_blake2b_32_block_state block_state = { .fst = wv, .snd = b }; Hacl_Streaming_Blake2_blake2b_32_state s = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)0U }; Hacl_Streaming_Blake2_blake2b_32_state p = s; Hacl_Blake2b_32_blake2b_init(block_state.fst, block_state.snd, (uint32_t)0U, NULL, (uint32_t)64U); Hacl_Streaming_Blake2_blake2b_32_state *s0 = &p; Hacl_Streaming_Blake2_blake2b_32_no_key_update(s0, hash1, (uint32_t)64U); Hacl_Streaming_Blake2_blake2b_32_no_key_update(s0, input, inlen); Hacl_Streaming_Blake2_blake2b_32_no_key_finish(s0, hash1); #endif // WITH_SODIUM } #ifndef WITH_HACL #define HMAC_IPAD 0x36 #define HMAC_OPAD 0x5C static void Noise_XK_hashstate_xor_key(uint8_t *key, size_t key_len, uint8_t value) { while (key_len > 0) { *key++ ^= value; --key_len; } } #endif // WITH_SODIUM void Noise_XK_hmac(uint8_t *output, uint32_t keylen, uint8_t *key, uint32_t datalen, uint8_t *data) { #ifndef WITH_HACL size_t hash_len = 64; size_t block_len = 128; uint8_t key_block[block_len]; crypto_generichash_state state; /* Format the key for the inner hashing context */ if (keylen <= block_len) { memcpy(key_block, key, keylen); memset(key_block + keylen, 0, block_len - keylen); } else { crypto_generichash_blake2b_init(&state, NULL, 0, crypto_generichash_blake2b_BYTES_MAX); crypto_generichash_blake2b_update(&state, key, keylen); crypto_generichash_blake2b_final(&state, key_block, crypto_generichash_blake2b_BYTES_MAX); memset(key_block + hash_len, 0, block_len - hash_len); } Noise_XK_hashstate_xor_key(key_block, block_len, HMAC_IPAD); /* Calculate the inner hash */ crypto_generichash_blake2b_init(&state, NULL, 0, crypto_generichash_blake2b_BYTES_MAX); crypto_generichash_blake2b_update(&state, key_block, block_len); crypto_generichash_blake2b_update(&state, data, datalen); crypto_generichash_blake2b_final(&state, output, crypto_generichash_blake2b_BYTES_MAX); /* Format the key for the outer hashing context */ Noise_XK_hashstate_xor_key(key_block, block_len, HMAC_IPAD ^ HMAC_OPAD); /* Calculate the outer hash */ crypto_generichash_blake2b_init(&state, NULL, 0, crypto_generichash_blake2b_BYTES_MAX); crypto_generichash_blake2b_update(&state, key_block, block_len); crypto_generichash_blake2b_update(&state, output, hash_len); crypto_generichash_blake2b_final(&state, output, crypto_generichash_blake2b_BYTES_MAX); /* Clean up and exit */ sodium_memzero(key_block,sizeof key_block); #else // WITH_SODIUM Hacl_HMAC_compute_blake2b_32(output, key, keylen, data, datalen); #endif // WITH_SODIUM } void Noise_XK_kdf( uint8_t *hash1, uint32_t keylen, uint8_t *key, uint8_t *dst1, uint8_t *dst2, uint8_t *dst3 ) { uint8_t output[65U] = { 0U }; uint8_t secret[64U] = { 0U }; uint8_t *output_hash = output; uint8_t *output1 = output; Noise_XK_hmac(secret, (uint32_t)64U, hash1, keylen, key); if (!(dst1 == NULL)) { output[0U] = (uint8_t)1U; Noise_XK_hmac(output_hash, (uint32_t)64U, secret, (uint32_t)1U, output1); memcpy(dst1, output_hash, (uint32_t)64U * sizeof (uint8_t)); if (!(dst2 == NULL)) { output[64U] = (uint8_t)2U; Noise_XK_hmac(output_hash, (uint32_t)64U, secret, (uint32_t)65U, output); memcpy(dst2, output_hash, (uint32_t)64U * sizeof (uint8_t)); if (!(dst3 == NULL)) { output[64U] = (uint8_t)3U; Noise_XK_hmac(output_hash, (uint32_t)64U, secret, (uint32_t)65U, output); memcpy(dst3, output_hash, (uint32_t)64U * sizeof (uint8_t)); } } } #ifndef WITH_HACL sodium_memzero(output, (uint32_t)65U * sizeof (output[0U])); sodium_memzero(secret, (uint32_t)64U * sizeof (secret[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(output, (uint32_t)65U * sizeof (output[0U])); Lib_Memzero0_memzero(secret, (uint32_t)64U * sizeof (secret[0U])); #endif // WITH_SODIUM } void Noise_XK_mix_psk(uint8_t *psk, uint8_t *st_cs_k, uint8_t *st_ck, uint8_t *st_h) { uint8_t temp_hash[64U] = { 0U }; uint8_t temp_k[64U] = { 0U }; Noise_XK_kdf(st_ck, (uint32_t)32U, psk, st_ck, temp_hash, temp_k); memcpy(st_cs_k, temp_k, (uint32_t)32U * sizeof (uint8_t)); #ifndef WITH_HACL sodium_memzero(temp_k, (uint32_t)64U * sizeof (temp_k[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(temp_k, (uint32_t)64U * sizeof (temp_k[0U])); #endif // WITH_SODIUM Noise_XK_mix_hash(st_h, (uint32_t)64U, temp_hash); #ifndef WITH_HACL sodium_memzero(temp_hash, (uint32_t)64U * sizeof (temp_hash[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(temp_hash, (uint32_t)64U * sizeof (temp_hash[0U])); #endif // WITH_SODIUM } void Noise_XK_encrypt_and_hash( uint32_t msg_len, uint8_t *msg, uint8_t *cipher, uint8_t *st_cs_k, uint8_t *st_h, uint64_t nonce ) { Noise_XK_aead_encrypt(st_cs_k, nonce, (uint32_t)64U, st_h, msg_len, msg, cipher); uint32_t cipher_len = msg_len + (uint32_t)16U; Noise_XK_mix_hash(st_h, cipher_len, cipher); } Noise_XK_error_code Noise_XK_decrypt_and_hash( uint32_t msg_len, uint8_t *msg, uint8_t *cipher, uint8_t *st_cs_k, uint8_t *st_h, uint64_t nonce ) { Noise_XK_error_code r1 = Noise_XK_aead_decrypt(st_cs_k, nonce, (uint32_t)64U, st_h, msg_len, msg, cipher); if (r1 == Noise_XK_CSuccess) { Noise_XK_mix_hash(st_h, msg_len + (uint32_t)16U, cipher); return Noise_XK_CSuccess; } else return r1; } Noise_XK_error_code Noise_XK_mix_dh(uint8_t *sec, uint8_t *pub, uint8_t *cipher_key, uint8_t *ck, uint8_t *hash1) { uint8_t dh_key[32U] = { 0U }; Noise_XK_error_code r1 = Noise_XK_dh(dh_key, sec, pub); Noise_XK_error_code r2; if (r1 == Noise_XK_CSuccess) { uint8_t temp_k[64U] = { 0U }; Noise_XK_kdf(ck, (uint32_t)32U, dh_key, ck, temp_k, NULL); memcpy(cipher_key, temp_k, (uint32_t)32U * sizeof (uint8_t)); #ifndef WITH_HACL sodium_memzero(temp_k, (uint32_t)64U * sizeof (temp_k[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(temp_k, (uint32_t)64U * sizeof (temp_k[0U])); #endif // WITH_SODIUM r2 = Noise_XK_CSuccess; } else r2 = r1; Noise_XK_error_code r = r2; #ifndef WITH_HACL sodium_memzero(dh_key, (uint32_t)32U * sizeof (dh_key[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(dh_key, (uint32_t)32U * sizeof (dh_key[0U])); #endif // WITH_SODIUM return r; } liboprf-0.6.1/src/noise_xk/src/XK.c000066400000000000000000006163531474121727000170610ustar00rootroot00000000000000/** This file was automatically generated */ #include "XK.h" bool Noise_XK_uu___is_Success(Noise_XK_rcode projectee) { if (projectee.tag == Noise_XK_Success) return true; else return false; } bool Noise_XK_uu___is_Error(Noise_XK_rcode projectee) { if (projectee.tag == Noise_XK_Error) return true; else return false; } Noise_XK_error_code Noise_XK___proj__Error__item___0(Noise_XK_rcode projectee) { if (projectee.tag == Noise_XK_Error) return projectee.val.case_Error; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } bool Noise_XK_uu___is_Stuck(Noise_XK_rcode projectee) { if (projectee.tag == Noise_XK_Stuck) return true; else return false; } Noise_XK_error_code Noise_XK___proj__Stuck__item___0(Noise_XK_rcode projectee) { if (projectee.tag == Noise_XK_Stuck) return projectee.val.case_Stuck; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } bool Noise_XK_uu___is_Auth_level(Noise_XK_ac_level_t projectee) { if (projectee.tag == Noise_XK_Auth_level) return true; else return false; } uint8_t Noise_XK___proj__Auth_level__item__l(Noise_XK_ac_level_t projectee) { if (projectee.tag == Noise_XK_Auth_level) return projectee.val.case_Auth_level; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } bool Noise_XK_uu___is_Conf_level(Noise_XK_ac_level_t projectee) { if (projectee.tag == Noise_XK_Conf_level) return true; else return false; } uint8_t Noise_XK___proj__Conf_level__item__l(Noise_XK_ac_level_t projectee) { if (projectee.tag == Noise_XK_Conf_level) return projectee.val.case_Conf_level; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } bool Noise_XK_uu___is_No_level(Noise_XK_ac_level_t projectee) { if (projectee.tag == Noise_XK_No_level) return true; else return false; } typedef struct Noise_XK_encap_message_t_s { Noise_XK_ac_level_t em_ac_level; uint32_t em_message_len; uint8_t *em_message; } Noise_XK_encap_message_t; Noise_XK_encap_message_t *Noise_XK___proj__Mkencap_message_p_or_null__item__emp(Noise_XK_encap_message_t *projectee) { return projectee; } bool Noise_XK_encap_message_p_is_null(Noise_XK_encap_message_t *emp) { return emp == NULL; } void Noise_XK_encap_message_p_free(Noise_XK_encap_message_t *emp) { Noise_XK_encap_message_t em = emp[0U]; if (!(em.em_message == NULL)) KRML_HOST_FREE(em.em_message); KRML_HOST_FREE(emp); } Noise_XK_encap_message_t *Noise_XK_pack_message_with_conf_level( uint8_t requested_conf_level, uint32_t msg_len, uint8_t *msg ) { uint8_t *msg_; if (msg_len > (uint32_t)0U) { KRML_CHECK_SIZE(sizeof (uint8_t), msg_len); uint8_t *o = KRML_HOST_CALLOC(msg_len, sizeof (uint8_t)); memcpy(o, msg, msg_len * sizeof (uint8_t)); msg_ = o; } else msg_ = NULL; KRML_CHECK_SIZE(sizeof (Noise_XK_encap_message_t), (uint32_t)1U); Noise_XK_encap_message_t *emp_p = KRML_HOST_MALLOC(sizeof (Noise_XK_encap_message_t)); emp_p[0U] = ( (Noise_XK_encap_message_t){ .em_ac_level = { .tag = Noise_XK_Conf_level, .val = { .case_Conf_level = requested_conf_level } }, .em_message_len = msg_len, .em_message = msg_ } ); return emp_p; } Noise_XK_encap_message_t *Noise_XK_pack_message(uint32_t msg_len, uint8_t *msg) { return Noise_XK_pack_message_with_conf_level(NOISE_XK_MAX_CONF_LEVEL, msg_len, msg); } bool Noise_XK_unpack_message_with_auth_level( uint32_t *out_msg_len, uint8_t **out_msg, uint8_t requested_auth_level, Noise_XK_encap_message_t *emp ) { Noise_XK_encap_message_t em = emp[0U]; bool ok; if (em.em_message_len == (uint32_t)0U) ok = true; else if (em.em_ac_level.tag == Noise_XK_Auth_level) { uint8_t l = em.em_ac_level.val.case_Auth_level; ok = l >= requested_auth_level; } else ok = false; if (ok) { uint8_t *msg; if (em.em_message_len > (uint32_t)0U) { KRML_CHECK_SIZE(sizeof (uint8_t), em.em_message_len); uint8_t *o = KRML_HOST_CALLOC(em.em_message_len, sizeof (uint8_t)); memcpy(o, em.em_message, em.em_message_len * sizeof (uint8_t)); msg = o; } else msg = NULL; out_msg_len[0U] = em.em_message_len; out_msg[0U] = msg; return true; } else { out_msg[0U] = NULL; return false; } } bool Noise_XK_unpack_message( uint32_t *out_msg_len, uint8_t **out_msg, Noise_XK_encap_message_t *emp ) { return Noise_XK_unpack_message_with_auth_level(out_msg_len, out_msg, NOISE_XK_MAX_AUTH_LEVEL, emp); } void Noise_XK_unsafe_unpack_message( Noise_XK_ac_level_t *out_ac_level, uint32_t *out_msg_len, uint8_t **out_msg, Noise_XK_encap_message_t *emp ) { Noise_XK_encap_message_t em = emp[0U]; uint8_t *msg; if (em.em_message_len > (uint32_t)0U) { KRML_CHECK_SIZE(sizeof (uint8_t), em.em_message_len); uint8_t *o = KRML_HOST_CALLOC(em.em_message_len, sizeof (uint8_t)); memcpy(o, em.em_message, em.em_message_len * sizeof (uint8_t)); msg = o; } else msg = NULL; out_ac_level[0U] = em.em_ac_level; out_msg_len[0U] = em.em_message_len; out_msg[0U] = msg; } Prims_int Noise_XK_num_pattern_messages = (krml_checked_int_t)3; bool Noise_XK_rcode_is_success(Noise_XK_rcode c) { if (c.tag == Noise_XK_Success) return true; else return false; } bool Noise_XK_rcode_is_error(Noise_XK_rcode c) { if (c.tag == Noise_XK_Error) return true; else return false; } bool Noise_XK_rcode_is_stuck(Noise_XK_rcode c) { if (c.tag == Noise_XK_Stuck) return true; else return false; } #include "noise_private.h" typedef struct Noise_XK_peer_t_s { uint32_t p_id; Noise_XK_noise_string *p_info; uint8_t *p_s; } Noise_XK_peer_t; typedef Noise_XK_peer_t *peer_p; typedef Noise_XK_cell **t___Impl_Noise_API_Instances_X1N_25519_AESGCM_BLAKE2b_peer_p; typedef struct Noise_XK_device_t_s { Noise_XK_noise_string *dv_info; uint8_t *dv_sk; uint8_t *dv_spriv; uint8_t *dv_spub; Noise_XK_sized_buffer dv_prologue; uint32_t dv_states_counter; Noise_XK_cell **dv_peers; uint32_t dv_peers_counter; } Noise_XK_device_t; typedef Noise_XK_device_t *device_p; typedef Noise_XK_session_t *session_p; /* Create a device. Parameters: * `prlg`: Prologue for session initialization * `info`: Device name * `sk`: (if present) symmetric key used to serialize/deserialize private data * `spriv`: (if present) static private key May fail and return NULL if provided unvalid keys. */ Noise_XK_device_t *Noise_XK_device_create( uint32_t prlg_len, uint8_t *prlg, uint8_t *info, uint8_t *sk, uint8_t *spriv ) { uint8_t *o0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(o0, sk, (uint32_t)32U * sizeof (uint8_t)); uint8_t *sk_ = o0; uint8_t *o1 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(o1, spriv, (uint32_t)32U * sizeof (uint8_t)); uint8_t *spriv_ = o1; uint8_t *spub_ = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); Noise_XK_error_code res = Noise_XK_dh_secret_to_public(spub_, spriv_); switch (res) { case Noise_XK_CSuccess: { uint8_t *prlg_; if (prlg_len > (uint32_t)0U) { KRML_CHECK_SIZE(sizeof (uint8_t), prlg_len); uint8_t *o = KRML_HOST_CALLOC(prlg_len, sizeof (uint8_t)); memcpy(o, prlg, prlg_len * sizeof (uint8_t)); prlg_ = o; } else prlg_ = NULL; Noise_XK_sized_buffer prlg_1 = { .size = prlg_len, .buffer = prlg_ }; bool b = info == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = info[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = info[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = info[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = info[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = info[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr[0U] = out_str; Noise_XK_noise_string *info_ = out_ptr; KRML_CHECK_SIZE(sizeof (Noise_XK_cell *), (uint32_t)1U); Noise_XK_cell **ptr = KRML_HOST_MALLOC(sizeof (Noise_XK_cell *)); ptr[0U] = NULL; Noise_XK_cell **peers = ptr; Noise_XK_device_t dv = { .dv_info = info_, .dv_sk = sk_, .dv_spriv = spriv_, .dv_spub = spub_, .dv_prologue = prlg_1, .dv_states_counter = (uint32_t)1U, .dv_peers = peers, .dv_peers_counter = (uint32_t)1U }; KRML_CHECK_SIZE(sizeof (Noise_XK_device_t), (uint32_t)1U); Noise_XK_device_t *dvp = KRML_HOST_MALLOC(sizeof (Noise_XK_device_t)); dvp[0U] = dv; return dvp; } default: { return NULL; } } } typedef struct __uint32_t__uint8_t__s { uint32_t fst; uint8_t *snd; } __uint32_t__uint8_t_; /* Create a device. Takes as arguments a symmetric key `sk` for secret data serialization/ deserialization, and an encrypted static private key `spriv`. The device name `info` is used as authentication data to encrypt/decrypt the device private key. May fail and return NULL if provided unvalid keys. */ Noise_XK_device_t *Noise_XK_device_create_from_secret( uint32_t prlg_len, uint8_t *prlg, uint8_t *info, uint8_t *sk, uint8_t *spriv ) { uint8_t *spriv_ = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); __uint32_t__uint8_t_ scrut; if (info == NULL) scrut = ((__uint32_t__uint8_t_){ .fst = (uint32_t)0U, .snd = NULL }); else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c = info[i0]; bool cond = c != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = info[i0]; cond = c != (uint8_t)0U; } uint32_t l = ip; if (l == (uint32_t)0U) scrut = ((__uint32_t__uint8_t_){ .fst = (uint32_t)0U, .snd = NULL }); else { uint8_t *s = info; scrut = ((__uint32_t__uint8_t_){ .fst = l, .snd = s }); } } uint32_t name_raw_len = scrut.fst; uint8_t *name_raw = scrut.snd; uint8_t *n8 = spriv; uint8_t *c0 = spriv + (uint32_t)8U; uint64_t n0 = Noise_XK_bytes_to_nonce(n8); Noise_XK_error_code res0 = Noise_XK_aead_decrypt(sk, n0, name_raw_len, name_raw, (uint32_t)32U, spriv_, c0); if (!(res0 == Noise_XK_CSuccess)) { KRML_HOST_FREE(spriv_); return NULL; } else { uint8_t *o0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(o0, sk, (uint32_t)32U * sizeof (uint8_t)); uint8_t *sk_ = o0; uint8_t *spub_ = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); Noise_XK_error_code res1 = Noise_XK_dh_secret_to_public(spub_, spriv_); uint8_t *prlg_; if (prlg_len > (uint32_t)0U) { KRML_CHECK_SIZE(sizeof (uint8_t), prlg_len); uint8_t *o = KRML_HOST_CALLOC(prlg_len, sizeof (uint8_t)); memcpy(o, prlg, prlg_len * sizeof (uint8_t)); prlg_ = o; } else prlg_ = NULL; Noise_XK_sized_buffer prlg_1 = { .size = prlg_len, .buffer = prlg_ }; bool b = info == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = info[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = info[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = info[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = info[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = info[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr[0U] = out_str; Noise_XK_noise_string *info_ = out_ptr; KRML_CHECK_SIZE(sizeof (Noise_XK_cell *), (uint32_t)1U); Noise_XK_cell **ptr = KRML_HOST_MALLOC(sizeof (Noise_XK_cell *)); ptr[0U] = NULL; Noise_XK_cell **peers = ptr; Noise_XK_device_t dv = { .dv_info = info_, .dv_sk = sk_, .dv_spriv = spriv_, .dv_spub = spub_, .dv_prologue = prlg_1, .dv_states_counter = (uint32_t)1U, .dv_peers = peers, .dv_peers_counter = (uint32_t)1U }; KRML_CHECK_SIZE(sizeof (Noise_XK_device_t), (uint32_t)1U); Noise_XK_device_t *dvp = KRML_HOST_MALLOC(sizeof (Noise_XK_device_t)); dvp[0U] = dv; return dvp; } } static void free___Impl_Noise_API_Device_raw_peer_p_or_null_raw_Impl_Noise_API_Device_raw_peer_t_raw_uint32_t_Impl_Noise_String_hstring__uint8_t____( Noise_XK_cell *l ) { if (!(l == NULL)) { free___Impl_Noise_API_Device_raw_peer_p_or_null_raw_Impl_Noise_API_Device_raw_peer_t_raw_uint32_t_Impl_Noise_String_hstring__uint8_t____((*l).next); KRML_HOST_FREE(l); } } static void free__Impl_Noise_API_Device_raw_peer_p_or_null_raw_Impl_Noise_API_Device_raw_peer_t_raw_uint32_t_Impl_Noise_String_hstring__uint8_t____( Noise_XK_cell **pl ) { free___Impl_Noise_API_Device_raw_peer_p_or_null_raw_Impl_Noise_API_Device_raw_peer_t_raw_uint32_t_Impl_Noise_String_hstring__uint8_t____(*pl); *pl = NULL; } /* Free a device. Take care to free the device **AFTER** having freed all the sessions created from this device. */ void Noise_XK_device_free(Noise_XK_device_t *dvp) { Noise_XK_device_t dv = dvp[0U]; uint8_t *str = dv.dv_info[0U]; if (!(str == NULL)) KRML_HOST_FREE(str); KRML_HOST_FREE(dv.dv_info); free__Impl_Noise_API_Device_raw_peer_p_or_null_raw_Impl_Noise_API_Device_raw_peer_t_raw_uint32_t_Impl_Noise_String_hstring__uint8_t____(dv.dv_peers); KRML_HOST_FREE(dv.dv_peers); KRML_HOST_FREE(dv.dv_spriv); KRML_HOST_FREE(dv.dv_spub); if (!(dv.dv_prologue.buffer == NULL)) KRML_HOST_FREE(dv.dv_prologue.buffer); KRML_HOST_FREE(dvp); } /* Encrypt and derialize a device's secret. Uses the device symmetric key to encrypt the device's secret key. Uses a randomly generated nonce together with the device name as authentication data. */ void Noise_XK_serialize_device_secret(uint32_t *outlen, uint8_t **out, Noise_XK_device_t *dvp) { Noise_XK_device_t dv = dvp[0U]; uint8_t *outb = KRML_HOST_CALLOC((uint32_t)56U, sizeof (uint8_t)); uint8_t *name = dv.dv_info[0U]; __uint32_t__uint8_t_ scrut; if (name == NULL) scrut = ((__uint32_t__uint8_t_){ .fst = (uint32_t)0U, .snd = NULL }); else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c = name[i0]; bool cond = c != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = name[i0]; cond = c != (uint8_t)0U; } uint32_t l = ip; if (l == (uint32_t)0U) scrut = ((__uint32_t__uint8_t_){ .fst = (uint32_t)0U, .snd = NULL }); else { uint8_t *s = name; scrut = ((__uint32_t__uint8_t_){ .fst = l, .snd = s }); } } uint32_t name_raw_len = scrut.fst; uint8_t *name_raw = scrut.snd; uint8_t *n8 = outb; uint8_t *c = outb + (uint32_t)8U; #ifndef WITH_HACL randombytes_buf(n8, (uint32_t)8U); #else // WITH_SODIUM Lib_RandomBuffer_System_crypto_random(n8, (uint32_t)8U); #endif // WITH_SODIUM uint64_t n = Noise_XK_bytes_to_nonce(n8); Noise_XK_aead_encrypt(dv.dv_sk, n, name_raw_len, name_raw, (uint32_t)32U, dv.dv_spriv, c); out[0U] = outb; outlen[0U] = (uint32_t)56U; } static void push__Impl_Noise_API_Device_raw_peer_p_or_null_raw_Impl_Noise_API_Device_raw_peer_t_raw_uint32_t_Impl_Noise_String_hstring__uint8_t____( Noise_XK_cell **pl, Noise_XK_peer_t *x ) { Noise_XK_cell *l = *pl; Noise_XK_cell c = { .next = l, .data = x }; KRML_CHECK_SIZE(sizeof (Noise_XK_cell), (uint32_t)1U); Noise_XK_cell *pc = KRML_HOST_MALLOC(sizeof (Noise_XK_cell)); pc[0U] = c; *pl = pc; } /* Add a peer to the device and return a pointer to the newly created peer. May fail and return NULL if the device already contains a peer with the same public static key. Note that the peer is owned by the device: we don't provide any way of freeing it on the user side, and it might be invalidated after a removal operation. For this reason, we advise to immediately use the returned pointer (to retrieve the peer id for instance), then forget it. */ Noise_XK_peer_t *Noise_XK_device_add_peer(Noise_XK_device_t *dvp, uint8_t *pinfo, uint8_t *rs) { Noise_XK_device_t dv = dvp[0U]; uint32_t pcounter = dv.dv_peers_counter; bool b1 = pcounter == (uint32_t)4294967295U; Noise_XK_cell *llt = *dv.dv_peers; Noise_XK_cell *lltp = llt; Noise_XK_cell *llt10 = lltp; bool b0; if (llt10 == NULL) b0 = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b = Noise_XK_lbytes_eq((uint32_t)32U, x.p_s, rs); bool b1 = b; b0 = !b1; } bool cond = b0; while (cond) { Noise_XK_cell *llt1 = lltp; Noise_XK_cell c0 = llt1[0U]; lltp = c0.next; Noise_XK_cell *llt10 = lltp; bool b; if (llt10 == NULL) b = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b0 = Noise_XK_lbytes_eq((uint32_t)32U, x.p_s, rs); bool b1 = b0; b = !b1; } cond = b; } Noise_XK_cell *llt1 = *&lltp; Noise_XK_peer_t *res; if (llt1 == NULL) res = NULL; else { Noise_XK_cell c = *llt1; res = c.data; } bool b2 = !(res == NULL); if (b1 || b2) return NULL; else { Noise_XK_noise_string *info1 = dv.dv_info; uint8_t *sk1 = dv.dv_sk; uint8_t *spriv1 = dv.dv_spriv; uint8_t *spub1 = dv.dv_spub; Noise_XK_sized_buffer prologue1 = dv.dv_prologue; uint32_t scounter1 = dv.dv_states_counter; Noise_XK_cell **peers1 = dv.dv_peers; uint32_t pcounter1 = dv.dv_peers_counter; uint8_t *rs1 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(rs1, rs, (uint32_t)32U * sizeof (uint8_t)); bool b = pinfo == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = pinfo[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = pinfo[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = pinfo[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = pinfo[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = pinfo[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr[0U] = out_str; Noise_XK_noise_string *pinfo1 = out_ptr; Noise_XK_peer_t x_ = { .p_id = pcounter1, .p_info = pinfo1, .p_s = rs1 }; KRML_CHECK_SIZE(sizeof (Noise_XK_peer_t), (uint32_t)1U); Noise_XK_peer_t *xp_ = KRML_HOST_MALLOC(sizeof (Noise_XK_peer_t)); xp_[0U] = x_; Noise_XK_peer_t *x = xp_; push__Impl_Noise_API_Device_raw_peer_p_or_null_raw_Impl_Noise_API_Device_raw_peer_t_raw_uint32_t_Impl_Noise_String_hstring__uint8_t____(peers1, x); Noise_XK_peer_t *pp = x; dvp[0U] = ( (Noise_XK_device_t){ .dv_info = info1, .dv_sk = sk1, .dv_spriv = spriv1, .dv_spub = spub1, .dv_prologue = prologue1, .dv_states_counter = scounter1, .dv_peers = peers1, .dv_peers_counter = pcounter1 + (uint32_t)1U } ); Noise_XK_peer_t *pp0 = pp; return pp0; } } static Noise_XK_peer_t *pop__Impl_Noise_API_Device_raw_peer_p_or_null_raw_Impl_Noise_API_Device_raw_peer_t_raw_uint32_t_Impl_Noise_String_hstring__uint8_t____( Noise_XK_cell **pl ) { Noise_XK_cell *l = *pl; Noise_XK_peer_t *r1 = (*l).data; Noise_XK_cell *next = (*l).next; *pl = next; KRML_HOST_FREE(l); return r1; } /* Remove a peer designated by its unique identifier. */ void Noise_XK_device_remove_peer(Noise_XK_device_t *dvp, uint32_t pid) { if (!(pid == (uint32_t)0U)) { Noise_XK_device_t dv = dvp[0U]; Noise_XK_cell *llt = *dv.dv_peers; if (!(llt == NULL)) { Noise_XK_cell c0 = *llt; Noise_XK_peer_t x = c0.data[0U]; if (x.p_id != pid) { Noise_XK_cell *llt1 = *dv.dv_peers; Noise_XK_cell *lltp = llt1; Noise_XK_cell *llt20 = lltp; Noise_XK_cell *next = llt20->next; bool b0; if (next == NULL) b0 = false; else { Noise_XK_cell c = next[0U]; Noise_XK_peer_t x = c.data[0U]; b0 = x.p_id != pid; } bool cond = b0; while (cond) { Noise_XK_cell *llt2 = lltp; Noise_XK_cell c0 = llt2[0U]; lltp = c0.next; Noise_XK_cell *llt20 = lltp; Noise_XK_cell *next = llt20->next; bool b; if (next == NULL) b = false; else { Noise_XK_cell c = next[0U]; Noise_XK_peer_t x = c.data[0U]; b = x.p_id != pid; } cond = b; } Noise_XK_cell *llt2 = *&lltp; Noise_XK_cell c01 = *llt2; if (!(c01.next == NULL)) { Noise_XK_cell c1 = *c01.next; llt2[0U] = ((Noise_XK_cell){ .next = c1.next, .data = c01.data }); Noise_XK_peer_t p = c1.data[0U]; uint8_t *str = p.p_info[0U]; if (!(str == NULL)) KRML_HOST_FREE(str); KRML_HOST_FREE(p.p_info); #ifndef WITH_HACL sodium_memzero(p.p_s, (uint32_t)32U * sizeof (p.p_s[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(p.p_s, (uint32_t)32U * sizeof (p.p_s[0U])); #endif // WITH_SODIUM KRML_HOST_FREE(p.p_s); KRML_HOST_FREE(c1.data); KRML_HOST_FREE(c01.next); } } else { Noise_XK_peer_t *elem1 = pop__Impl_Noise_API_Device_raw_peer_p_or_null_raw_Impl_Noise_API_Device_raw_peer_t_raw_uint32_t_Impl_Noise_String_hstring__uint8_t____(dv.dv_peers); Noise_XK_peer_t p = elem1[0U]; uint8_t *str = p.p_info[0U]; if (!(str == NULL)) KRML_HOST_FREE(str); KRML_HOST_FREE(p.p_info); #ifndef WITH_HACL sodium_memzero(p.p_s, (uint32_t)32U * sizeof (p.p_s[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(p.p_s, (uint32_t)32U * sizeof (p.p_s[0U])); #endif // WITH_SODIUM KRML_HOST_FREE(p.p_s); KRML_HOST_FREE(elem1); } } } } /* Encrypt and serialize a peer's key(s). Uses the device symmetric key to encrypt the peer's key(s). Uses a randomly generated nonce together with the peer name as authentication data. */ void Noise_XK_serialize_peer_secret( uint32_t *outlen, uint8_t **out, Noise_XK_device_t *dvp, Noise_XK_peer_t *peer ) { if (peer == NULL) { outlen[0U] = (uint32_t)0U; out[0U] = NULL; } else { Noise_XK_device_t dv = dvp[0U]; Noise_XK_peer_t p = peer[0U]; uint8_t *concat_keys = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *outb = KRML_HOST_CALLOC((uint32_t)56U, sizeof (uint8_t)); memcpy(concat_keys, p.p_s, (uint32_t)32U * sizeof (uint8_t)); uint8_t *name = p.p_info[0U]; __uint32_t__uint8_t_ scrut; if (name == NULL) scrut = ((__uint32_t__uint8_t_){ .fst = (uint32_t)0U, .snd = NULL }); else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c = name[i0]; bool cond = c != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = name[i0]; cond = c != (uint8_t)0U; } uint32_t l = ip; if (l == (uint32_t)0U) scrut = ((__uint32_t__uint8_t_){ .fst = (uint32_t)0U, .snd = NULL }); else { uint8_t *s = name; scrut = ((__uint32_t__uint8_t_){ .fst = l, .snd = s }); } } uint32_t name_raw_len = scrut.fst; uint8_t *name_raw = scrut.snd; uint8_t *n8 = outb; uint8_t *c = outb + (uint32_t)8U; #ifndef WITH_HACL randombytes_buf(n8, (uint32_t)8U); #else // WITH_SODIUM Lib_RandomBuffer_System_crypto_random(n8, (uint32_t)8U); #endif // WITH_SODIUM uint64_t n = Noise_XK_bytes_to_nonce(n8); Noise_XK_aead_encrypt(dv.dv_sk, n, name_raw_len, name_raw, (uint32_t)32U, concat_keys, c); out[0U] = outb; outlen[0U] = (uint32_t)56U; KRML_HOST_FREE(concat_keys); } } /* Decrypt and deserialize a peer's secret data and add it to the device. */ Noise_XK_peer_t *Noise_XK_deserialize_peer_secret( Noise_XK_device_t *dvp, uint8_t *peer_name, uint32_t inlen, uint8_t *enc_keys ) { Noise_XK_device_t dv = dvp[0U]; if ((uint32_t)56U != inlen) return NULL; else { uint8_t *concat_keys = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); __uint32_t__uint8_t_ scrut; if (peer_name == NULL) scrut = ((__uint32_t__uint8_t_){ .fst = (uint32_t)0U, .snd = NULL }); else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c = peer_name[i0]; bool cond = c != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = peer_name[i0]; cond = c != (uint8_t)0U; } uint32_t l = ip; if (l == (uint32_t)0U) scrut = ((__uint32_t__uint8_t_){ .fst = (uint32_t)0U, .snd = NULL }); else { uint8_t *s = peer_name; scrut = ((__uint32_t__uint8_t_){ .fst = l, .snd = s }); } } uint32_t name_raw_len = scrut.fst; uint8_t *name_raw = scrut.snd; uint8_t *n8 = enc_keys; uint8_t *c0 = enc_keys + (uint32_t)8U; uint64_t n0 = Noise_XK_bytes_to_nonce(n8); Noise_XK_error_code res = Noise_XK_aead_decrypt(dv.dv_sk, n0, name_raw_len, name_raw, (uint32_t)32U, concat_keys, c0); if (res == Noise_XK_CSuccess) { uint8_t *p_s = concat_keys; Noise_XK_device_t dv1 = dvp[0U]; uint32_t pcounter = dv1.dv_peers_counter; bool b1 = pcounter == (uint32_t)4294967295U; Noise_XK_cell *llt = *dv1.dv_peers; Noise_XK_cell *lltp = llt; Noise_XK_cell *llt10 = lltp; bool b0; if (llt10 == NULL) b0 = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b = Noise_XK_lbytes_eq((uint32_t)32U, x.p_s, p_s); bool b1 = b; b0 = !b1; } bool cond = b0; while (cond) { Noise_XK_cell *llt1 = lltp; Noise_XK_cell c0 = llt1[0U]; lltp = c0.next; Noise_XK_cell *llt10 = lltp; bool b; if (llt10 == NULL) b = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b0 = Noise_XK_lbytes_eq((uint32_t)32U, x.p_s, p_s); bool b1 = b0; b = !b1; } cond = b; } Noise_XK_cell *llt1 = *&lltp; Noise_XK_peer_t *res1; if (llt1 == NULL) res1 = NULL; else { Noise_XK_cell c = *llt1; res1 = c.data; } bool b2 = !(res1 == NULL); Noise_XK_peer_t *peer; if (b1 || b2) peer = NULL; else { Noise_XK_noise_string *info1 = dv1.dv_info; uint8_t *sk1 = dv1.dv_sk; uint8_t *spriv1 = dv1.dv_spriv; uint8_t *spub1 = dv1.dv_spub; Noise_XK_sized_buffer prologue1 = dv1.dv_prologue; uint32_t scounter1 = dv1.dv_states_counter; Noise_XK_cell **peers1 = dv1.dv_peers; uint32_t pcounter1 = dv1.dv_peers_counter; uint8_t *rs = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(rs, p_s, (uint32_t)32U * sizeof (uint8_t)); bool b = peer_name == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = peer_name[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = peer_name[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = peer_name[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = peer_name[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = peer_name[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr[0U] = out_str; Noise_XK_noise_string *pinfo = out_ptr; Noise_XK_peer_t x_ = { .p_id = pcounter1, .p_info = pinfo, .p_s = rs }; KRML_CHECK_SIZE(sizeof (Noise_XK_peer_t), (uint32_t)1U); Noise_XK_peer_t *xp_ = KRML_HOST_MALLOC(sizeof (Noise_XK_peer_t)); xp_[0U] = x_; Noise_XK_peer_t *x = xp_; push__Impl_Noise_API_Device_raw_peer_p_or_null_raw_Impl_Noise_API_Device_raw_peer_t_raw_uint32_t_Impl_Noise_String_hstring__uint8_t____(peers1, x); Noise_XK_peer_t *pp = x; dvp[0U] = ( (Noise_XK_device_t){ .dv_info = info1, .dv_sk = sk1, .dv_spriv = spriv1, .dv_spub = spub1, .dv_prologue = prologue1, .dv_states_counter = scounter1, .dv_peers = peers1, .dv_peers_counter = pcounter1 + (uint32_t)1U } ); Noise_XK_peer_t *pp0 = pp; peer = pp0; } KRML_HOST_FREE(concat_keys); return peer; } else { KRML_HOST_FREE(concat_keys); return NULL; } } } /* Lookup a peer by using its unique identifier. Return NULL is no peer was found. Note that the peer is owned by the device: we don't provide any way of freeing it on the user side, and it might be invalidated after a removal operation. For this reason, we advise to immediately use the returned pointer (to retrieve the peer name, etc.), then forget it. */ Noise_XK_peer_t *Noise_XK_device_lookup_peer_by_id(Noise_XK_device_t *dvp, uint32_t id) { Noise_XK_device_t dv = dvp[0U]; if (id == (uint32_t)0U) return NULL; else { Noise_XK_cell *llt = *dv.dv_peers; Noise_XK_cell *lltp = llt; Noise_XK_cell *llt10 = lltp; bool b0; if (llt10 == NULL) b0 = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b = x.p_id == id; b0 = !b; } bool cond = b0; while (cond) { Noise_XK_cell *llt1 = lltp; Noise_XK_cell c0 = llt1[0U]; lltp = c0.next; Noise_XK_cell *llt10 = lltp; bool b; if (llt10 == NULL) b = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b0 = x.p_id == id; b = !b0; } cond = b; } Noise_XK_cell *llt1 = *&lltp; if (llt1 == NULL) return NULL; else { Noise_XK_cell c = *llt1; return c.data; } } } /* Lookup a peer by using its static public key. Return NULL is no peer was found. Note that the peer is owned by the device: we don't provide any way of freeing it on the user side, and it might be invalidated after a removal operation. For this reason, we advise to immediately use the returned pointer (to retrieve the peer name, etc.), then forget it. */ Noise_XK_peer_t *Noise_XK_device_lookup_peer_by_static(Noise_XK_device_t *dvp, uint8_t *s) { Noise_XK_device_t dv = dvp[0U]; Noise_XK_cell *llt = *dv.dv_peers; Noise_XK_cell *lltp = llt; Noise_XK_cell *llt10 = lltp; bool b0; if (llt10 == NULL) b0 = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b = Noise_XK_lbytes_eq((uint32_t)32U, x.p_s, s); bool b1 = b; b0 = !b1; } bool cond = b0; while (cond) { Noise_XK_cell *llt1 = lltp; Noise_XK_cell c0 = llt1[0U]; lltp = c0.next; Noise_XK_cell *llt10 = lltp; bool b; if (llt10 == NULL) b = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b0 = Noise_XK_lbytes_eq((uint32_t)32U, x.p_s, s); bool b1 = b0; b = !b1; } cond = b; } Noise_XK_cell *llt1 = *&lltp; if (llt1 == NULL) return NULL; else { Noise_XK_cell c = *llt1; return c.data; } } /* Copy the peer information to the user provided pointer. */ void Noise_XK_device_get_info(Noise_XK_noise_string *out, Noise_XK_device_t *dvp) { Noise_XK_device_t dv = dvp[0U]; uint8_t *input_str = dv.dv_info[0U]; bool b = input_str == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = input_str[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = input_str[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = input_str[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } out[0U] = out_str; } /* Return the current value of the sessions counter. The device keeps track of the number of sessions created so far, in order to give them unique identifiers. */ uint32_t Noise_XK_device_get_sessions_counter(Noise_XK_device_t *dvp) { Noise_XK_device_t dv = dvp[0U]; return dv.dv_states_counter; } /* Return true if the sessions counter is saturated. It is not possible to create any more sessions if the counter is saturated. */ bool Noise_XK_device_sessions_counter_is_saturated(Noise_XK_device_t *dvp) { Noise_XK_device_t dv = dvp[0U]; uint32_t cnt = dv.dv_states_counter; return cnt == (uint32_t)4294967295U; } /* Return the current value of the peers counter. The device keeps track of the number of peers created so far, in order to give them unique identifiers. */ uint32_t Noise_XK_device_get_peers_counter(Noise_XK_device_t *dvp) { Noise_XK_device_t dv = dvp[0U]; return dv.dv_peers_counter; } /* Return true if the peers counter is saturated. It is not possible to add any more peers to the device if the counter is saturated. */ bool Noise_XK_device_peers_counter_is_saturated(Noise_XK_device_t *dvp) { Noise_XK_device_t dv = dvp[0U]; uint32_t cnt = dv.dv_peers_counter; return cnt == (uint32_t)4294967295U; } /* Copy the device static private key to the user provided buffer. */ void Noise_XK_device_get_static_priv(uint8_t *out, Noise_XK_device_t *dvp) { Noise_XK_device_t dv = dvp[0U]; memcpy(out, dv.dv_spriv, (uint32_t)32U * sizeof (uint8_t)); } /* Copy the device static public key to the user provided buffer. */ void Noise_XK_device_get_static_pub(uint8_t *out, Noise_XK_device_t *dvp) { Noise_XK_device_t dv = dvp[0U]; memcpy(out, dv.dv_spub, (uint32_t)32U * sizeof (uint8_t)); } /* Return the unique peer identifier. */ uint32_t Noise_XK_peer_get_id(Noise_XK_peer_t *pp) { Noise_XK_peer_t p = pp[0U]; return p.p_id; } /* Copy the peer information to the user provided pointer. */ void Noise_XK_peer_get_info(Noise_XK_noise_string *out, Noise_XK_peer_t *pp) { Noise_XK_peer_t p = pp[0U]; uint8_t *input_str = p.p_info[0U]; bool b = input_str == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = input_str[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = input_str[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = input_str[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } out[0U] = out_str; } /* Copy the peer static public key to the user provided buffer. */ void Noise_XK_peer_get_static(uint8_t *out, Noise_XK_peer_t *pp) { Noise_XK_peer_t p = pp[0U]; memcpy(out, p.p_s, (uint32_t)32U * sizeof (uint8_t)); } typedef struct _________________s { } ________________; #define Res 0 #define Fail 1 typedef uint8_t result_session_t_tags; typedef struct result_session_t_s { result_session_t_tags tag; union { Noise_XK_session_t case_Res; Noise_XK_error_code case_Fail; } val; } result_session_t; typedef struct ______________s { } _____________; typedef struct ________s { } _______; /* Create an initiator session. May fail and return NULL in case of invalid keys, unknown peer, etc. */ Noise_XK_session_t *Noise_XK_session_create_initiator(Noise_XK_device_t *dvp, uint32_t pid) { uint8_t epriv[32U] = { 0U }; uint8_t epub[32U] = { 0U }; #ifndef WITH_HACL randombytes_buf(epriv, (uint32_t)32U); #else // WITH_SODIUM Lib_RandomBuffer_System_crypto_random(epriv, (uint32_t)32U); #endif // WITH_SODIUM Noise_XK_error_code res0 = Noise_XK_dh_secret_to_public(epub, epriv); Noise_XK_session_t *res; switch (res0) { case Noise_XK_CSuccess: { Noise_XK_device_t dv = dvp[0U]; result_session_t res10; if (dv.dv_states_counter == (uint32_t)4294967295U) res10 = ( (result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } } ); else { Noise_XK_device_t dv1 = dvp[0U]; Noise_XK_peer_t *peer_ptr; if (pid == (uint32_t)0U) peer_ptr = NULL; else { Noise_XK_cell *llt = *dv1.dv_peers; Noise_XK_cell *lltp = llt; Noise_XK_cell *llt10 = lltp; bool b0; if (llt10 == NULL) b0 = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b = x.p_id == pid; b0 = !b; } bool cond = b0; while (cond) { Noise_XK_cell *llt1 = lltp; Noise_XK_cell c0 = llt1[0U]; lltp = c0.next; Noise_XK_cell *llt10 = lltp; bool b; if (llt10 == NULL) b = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b0 = x.p_id == pid; b = !b0; } cond = b; } Noise_XK_cell *llt1 = *&lltp; Noise_XK_peer_t *res1; if (llt1 == NULL) res1 = NULL; else { Noise_XK_cell c = *llt1; res1 = c.data; } peer_ptr = res1; } bool p_is_null = peer_ptr == NULL; if (p_is_null) res10 = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CUnknown_peer_id } }); else { uint8_t *o0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(o0, dv.dv_spriv, (uint32_t)32U * sizeof (uint8_t)); uint8_t *st_spriv = o0; uint8_t *o = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(o, dv.dv_spub, (uint32_t)32U * sizeof (uint8_t)); uint8_t *st_spub = o; uint8_t *str0 = dv.dv_info[0U]; bool b0 = str0 == NULL; uint8_t *out_str0; if (b0) out_str0 = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = str0[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = str0[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str0 = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = str0[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = str0[n]; out_str[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = str0[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str[n] = (uint8_t)0U; uint8_t *out_str1 = out_str; out_str0 = out_str1; } } KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr[0U] = out_str0; Noise_XK_noise_string *st_info = out_ptr; Noise_XK_peer_t peer = peer_ptr[0U]; uint8_t *str = peer.p_info[0U]; bool b = str == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = str[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = str[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = str[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = str[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = str[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr0 = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr0[0U] = out_str; Noise_XK_noise_string *st_pinfo = out_ptr0; uint8_t *rs = peer.p_s; dvp[0U] = ( (Noise_XK_device_t){ .dv_info = dv.dv_info, .dv_sk = dv.dv_sk, .dv_spriv = dv.dv_spriv, .dv_spub = dv.dv_spub, .dv_prologue = dv.dv_prologue, .dv_states_counter = dv.dv_states_counter + (uint32_t)1U, .dv_peers = dv.dv_peers, .dv_peers_counter = dv.dv_peers_counter } ); uint8_t *st_k = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_ck0 = KRML_HOST_CALLOC((uint32_t)64U, sizeof (uint8_t)); uint8_t *st_h0 = KRML_HOST_CALLOC((uint32_t)64U, sizeof (uint8_t)); uint8_t *st_spriv1 = st_spriv; uint8_t *st_spub1 = st_spub; uint8_t *st_epriv0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_epub0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_rs0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_re = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); Noise_XK_init_state_t st = { .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = (uint32_t)0U, .cipher_key = st_k, .chaining_key = st_ck0, .h = st_h0, .spriv = st_spriv1, .spub = st_spub1, .epriv = st_epriv0, .epub = st_epub0, .rs = st_rs0, .re = st_re } } }; uint8_t pname[33U] = { (uint8_t)78U, (uint8_t)111U, (uint8_t)105U, (uint8_t)115U, (uint8_t)101U, (uint8_t)95U, (uint8_t)88U, (uint8_t)75U, (uint8_t)95U, (uint8_t)50U, (uint8_t)53U, (uint8_t)53U, (uint8_t)49U, (uint8_t)57U, (uint8_t)95U, (uint8_t)67U, (uint8_t)104U, (uint8_t)97U, (uint8_t)67U, (uint8_t)104U, (uint8_t)97U, (uint8_t)80U, (uint8_t)111U, (uint8_t)108U, (uint8_t)121U, (uint8_t)95U, (uint8_t)66U, (uint8_t)76U, (uint8_t)65U, (uint8_t)75U, (uint8_t)69U, (uint8_t)50U, (uint8_t)98U }; if (st.tag == Noise_XK_IMS_Handshake) { uint8_t *st_rs = st.val.case_IMS_Handshake.rs; uint8_t *st_epub = st.val.case_IMS_Handshake.epub; uint8_t *st_epriv = st.val.case_IMS_Handshake.epriv; uint8_t *st_h = st.val.case_IMS_Handshake.h; uint8_t *st_ck = st.val.case_IMS_Handshake.chaining_key; if ((uint32_t)33U <= (uint32_t)64U) memcpy(st_h, pname, (uint32_t)33U * sizeof (uint8_t)); else Noise_XK_hash(st_h, (uint32_t)33U, pname); memcpy(st_ck, st_h, (uint32_t)64U * sizeof (uint8_t)); Noise_XK_mix_hash(st_h, dv.dv_prologue.size, dv.dv_prologue.buffer); memcpy(st_epriv, epriv, (uint32_t)32U * sizeof (uint8_t)); memcpy(st_epub, epub, (uint32_t)32U * sizeof (uint8_t)); memcpy(st_rs, rs, (uint32_t)32U * sizeof (uint8_t)); Noise_XK_mix_hash(st_h, (uint32_t)32U, rs); } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } Noise_XK_init_state_t st0 = st; result_session_t res1 = { .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = st0, .id = dv.dv_states_counter, .info = st_info, .spriv = st_spriv, .spub = st_spub, .pid = pid, .pinfo = st_pinfo, .dv = dvp } } } } }; res10 = res1; } } Noise_XK_session_t *res1; if (res10.tag == Fail) res1 = NULL; else if (res10.tag == Res) { Noise_XK_session_t st = res10.val.case_Res; KRML_CHECK_SIZE(sizeof (Noise_XK_session_t), (uint32_t)1U); Noise_XK_session_t *ptr = KRML_HOST_MALLOC(sizeof (Noise_XK_session_t)); ptr[0U] = st; res1 = ptr; } else res1 = KRML_EABORT(Noise_XK_session_t *, "unreachable (pattern matches are exhaustive in F*)"); res = res1; break; } default: { res = NULL; } } #ifndef WITH_HACL sodium_memzero(epriv, (uint32_t)32U * sizeof (epriv[0U])); sodium_memzero(epub, (uint32_t)32U * sizeof (epub[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(epriv, (uint32_t)32U * sizeof (epriv[0U])); Lib_Memzero0_memzero(epub, (uint32_t)32U * sizeof (epub[0U])); #endif // WITH_SODIUM Noise_XK_session_t *res1 = res; return res1; } /* Create a responder session. May fail and return NULL in case of invalid keys, unknown peer, etc. */ Noise_XK_session_t *Noise_XK_session_create_responder(Noise_XK_device_t *dvp) { uint8_t epriv[32U] = { 0U }; uint8_t epub[32U] = { 0U }; #ifndef WITH_HACL randombytes_buf(epriv, (uint32_t)32U); #else // WITH_SODIUM Lib_RandomBuffer_System_crypto_random(epriv, (uint32_t)32U); #endif // WITH_SODIUM Noise_XK_error_code res0 = Noise_XK_dh_secret_to_public(epub, epriv); Noise_XK_session_t *res; switch (res0) { case Noise_XK_CSuccess: { Noise_XK_device_t dv = dvp[0U]; result_session_t res10; if (dv.dv_states_counter == (uint32_t)4294967295U) res10 = ( (result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } } ); else { uint8_t *o0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(o0, dv.dv_spriv, (uint32_t)32U * sizeof (uint8_t)); uint8_t *st_spriv = o0; uint8_t *o = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(o, dv.dv_spub, (uint32_t)32U * sizeof (uint8_t)); uint8_t *st_spub = o; uint8_t *str = dv.dv_info[0U]; bool b = str == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = str[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = str[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = str[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = str[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = str[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr0 = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr0[0U] = out_str; Noise_XK_noise_string *st_info = out_ptr0; KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr[0U] = NULL; Noise_XK_noise_string *st_pinfo = out_ptr; dvp[0U] = ( (Noise_XK_device_t){ .dv_info = dv.dv_info, .dv_sk = dv.dv_sk, .dv_spriv = dv.dv_spriv, .dv_spub = dv.dv_spub, .dv_prologue = dv.dv_prologue, .dv_states_counter = dv.dv_states_counter + (uint32_t)1U, .dv_peers = dv.dv_peers, .dv_peers_counter = dv.dv_peers_counter } ); uint8_t *st_k = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_ck0 = KRML_HOST_CALLOC((uint32_t)64U, sizeof (uint8_t)); uint8_t *st_h0 = KRML_HOST_CALLOC((uint32_t)64U, sizeof (uint8_t)); uint8_t *st_spriv1 = st_spriv; uint8_t *st_spub10 = st_spub; uint8_t *st_epriv0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_epub0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_rs = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_re = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); Noise_XK_resp_state_t st = { .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = (uint32_t)0U, .cipher_key = st_k, .chaining_key = st_ck0, .h = st_h0, .spriv = st_spriv1, .spub = st_spub10, .epriv = st_epriv0, .epub = st_epub0, .rs = st_rs, .re = st_re } } }; uint8_t pname[33U] = { (uint8_t)78U, (uint8_t)111U, (uint8_t)105U, (uint8_t)115U, (uint8_t)101U, (uint8_t)95U, (uint8_t)88U, (uint8_t)75U, (uint8_t)95U, (uint8_t)50U, (uint8_t)53U, (uint8_t)53U, (uint8_t)49U, (uint8_t)57U, (uint8_t)95U, (uint8_t)67U, (uint8_t)104U, (uint8_t)97U, (uint8_t)67U, (uint8_t)104U, (uint8_t)97U, (uint8_t)80U, (uint8_t)111U, (uint8_t)108U, (uint8_t)121U, (uint8_t)95U, (uint8_t)66U, (uint8_t)76U, (uint8_t)65U, (uint8_t)75U, (uint8_t)69U, (uint8_t)50U, (uint8_t)98U }; if (st.tag == Noise_XK_IMS_Handshake) { uint8_t *st_epub = st.val.case_IMS_Handshake.epub; uint8_t *st_epriv = st.val.case_IMS_Handshake.epriv; uint8_t *st_spub1 = st.val.case_IMS_Handshake.spub; uint8_t *st_h = st.val.case_IMS_Handshake.h; uint8_t *st_ck = st.val.case_IMS_Handshake.chaining_key; if ((uint32_t)33U <= (uint32_t)64U) memcpy(st_h, pname, (uint32_t)33U * sizeof (uint8_t)); else Noise_XK_hash(st_h, (uint32_t)33U, pname); memcpy(st_ck, st_h, (uint32_t)64U * sizeof (uint8_t)); Noise_XK_mix_hash(st_h, dv.dv_prologue.size, dv.dv_prologue.buffer); memcpy(st_epriv, epriv, (uint32_t)32U * sizeof (uint8_t)); memcpy(st_epub, epub, (uint32_t)32U * sizeof (uint8_t)); Noise_XK_mix_hash(st_h, (uint32_t)32U, st_spub1); } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } Noise_XK_resp_state_t st0 = st; result_session_t res1 = { .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = st0, .id = dv.dv_states_counter, .info = st_info, .spriv = st_spriv, .spub = st_spub, .pid = (uint32_t)0U, .pinfo = st_pinfo, .dv = dvp } } } } }; res10 = res1; } Noise_XK_session_t *res1; if (res10.tag == Fail) res1 = NULL; else if (res10.tag == Res) { Noise_XK_session_t st = res10.val.case_Res; KRML_CHECK_SIZE(sizeof (Noise_XK_session_t), (uint32_t)1U); Noise_XK_session_t *ptr = KRML_HOST_MALLOC(sizeof (Noise_XK_session_t)); ptr[0U] = st; res1 = ptr; } else res1 = KRML_EABORT(Noise_XK_session_t *, "unreachable (pattern matches are exhaustive in F*)"); res = res1; break; } default: { res = NULL; } } #ifndef WITH_HACL sodium_memzero(epriv, (uint32_t)32U * sizeof (epriv[0U])); sodium_memzero(epub, (uint32_t)32U * sizeof (epub[0U])); #else //WITH_SODIUM Lib_Memzero0_memzero(epriv, (uint32_t)32U * sizeof (epriv[0U])); Lib_Memzero0_memzero(epub, (uint32_t)32U * sizeof (epub[0U])); #endif //WITH_SODIUM Noise_XK_session_t *res1 = res; return res1; } /* Free a session. Be sure to free all sessions before freeing the device used to create those sessions. */ void Noise_XK_session_free(Noise_XK_session_t *sn) { Noise_XK_session_t st = sn[0U]; if (st.tag == Noise_XK_DS_Initiator) { Noise_XK_noise_string *pinfo = st.val.case_DS_Initiator.pinfo; uint8_t *spub = st.val.case_DS_Initiator.spub; uint8_t *spriv = st.val.case_DS_Initiator.spriv; Noise_XK_noise_string *info = st.val.case_DS_Initiator.info; Noise_XK_init_state_t state = st.val.case_DS_Initiator.state; if (state.tag == Noise_XK_IMS_Handshake) { uint8_t *st_re = state.val.case_IMS_Handshake.re; uint8_t *st_rs = state.val.case_IMS_Handshake.rs; uint8_t *st_epub = state.val.case_IMS_Handshake.epub; uint8_t *st_epriv = state.val.case_IMS_Handshake.epriv; uint8_t *st_h = state.val.case_IMS_Handshake.h; uint8_t *st_ck = state.val.case_IMS_Handshake.chaining_key; uint8_t *st_k = state.val.case_IMS_Handshake.cipher_key; KRML_HOST_FREE(st_k); KRML_HOST_FREE(st_ck); KRML_HOST_FREE(st_h); KRML_HOST_FREE(st_epriv); KRML_HOST_FREE(st_epub); KRML_HOST_FREE(st_rs); KRML_HOST_FREE(st_re); } else if (state.tag == Noise_XK_IMS_Transport) { uint8_t *receive_key = state.val.case_IMS_Transport.receive_key; uint8_t *send_key = state.val.case_IMS_Transport.send_key; uint8_t *st_h = state.val.case_IMS_Transport.h; KRML_HOST_FREE(st_h); KRML_HOST_FREE(send_key); KRML_HOST_FREE(receive_key); } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } uint8_t *str = info[0U]; if (!(str == NULL)) KRML_HOST_FREE(str); KRML_HOST_FREE(info); uint8_t *str0 = pinfo[0U]; if (!(str0 == NULL)) KRML_HOST_FREE(str0); KRML_HOST_FREE(pinfo); KRML_HOST_FREE(spriv); KRML_HOST_FREE(spub); } else if (st.tag == Noise_XK_DS_Responder) { Noise_XK_noise_string *pinfo = st.val.case_DS_Responder.pinfo; uint8_t *spub = st.val.case_DS_Responder.spub; uint8_t *spriv = st.val.case_DS_Responder.spriv; Noise_XK_noise_string *info = st.val.case_DS_Responder.info; Noise_XK_resp_state_t state = st.val.case_DS_Responder.state; if (state.tag == Noise_XK_IMS_Handshake) { uint8_t *st_re = state.val.case_IMS_Handshake.re; uint8_t *st_rs = state.val.case_IMS_Handshake.rs; uint8_t *st_epub = state.val.case_IMS_Handshake.epub; uint8_t *st_epriv = state.val.case_IMS_Handshake.epriv; uint8_t *st_h = state.val.case_IMS_Handshake.h; uint8_t *st_ck = state.val.case_IMS_Handshake.chaining_key; uint8_t *st_k = state.val.case_IMS_Handshake.cipher_key; KRML_HOST_FREE(st_k); KRML_HOST_FREE(st_ck); KRML_HOST_FREE(st_h); KRML_HOST_FREE(st_epriv); KRML_HOST_FREE(st_epub); KRML_HOST_FREE(st_rs); KRML_HOST_FREE(st_re); } else if (state.tag == Noise_XK_IMS_Transport) { uint8_t *receive_key = state.val.case_IMS_Transport.receive_key; uint8_t *send_key = state.val.case_IMS_Transport.send_key; uint8_t *st_h = state.val.case_IMS_Transport.h; KRML_HOST_FREE(st_h); KRML_HOST_FREE(send_key); KRML_HOST_FREE(receive_key); } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } uint8_t *str = info[0U]; if (!(str == NULL)) KRML_HOST_FREE(str); KRML_HOST_FREE(info); uint8_t *str0 = pinfo[0U]; if (!(str0 == NULL)) KRML_HOST_FREE(str0); KRML_HOST_FREE(pinfo); KRML_HOST_FREE(spriv); KRML_HOST_FREE(spub); } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } KRML_HOST_FREE(sn); } typedef struct result_init_state_t_s { result_session_t_tags tag; union { Noise_XK_init_state_t case_Res; Noise_XK_error_code case_Fail; } val; } result_init_state_t; typedef struct result_resp_state_t_s { result_session_t_tags tag; union { Noise_XK_resp_state_t case_Res; Noise_XK_error_code case_Fail; } val; } result_resp_state_t; static Noise_XK_error_code state_handshake_write( uint32_t payload_len, uint8_t *payload, Noise_XK_session_t *dst_p, uint32_t outlen, uint8_t *out ) { Noise_XK_session_t *dst_p1 = dst_p; Noise_XK_session_t *stp = dst_p1; Noise_XK_session_t dst = stp[0U]; result_session_t res0; if (dst.tag == Noise_XK_DS_Initiator) { Noise_XK_device_t *dst_dv = dst.val.case_DS_Initiator.dv; Noise_XK_noise_string *dst_pinfo = dst.val.case_DS_Initiator.pinfo; uint32_t dst_pid = dst.val.case_DS_Initiator.pid; uint8_t *dst_spub = dst.val.case_DS_Initiator.spub; uint8_t *dst_spriv = dst.val.case_DS_Initiator.spriv; Noise_XK_noise_string *dst_info = dst.val.case_DS_Initiator.info; uint32_t dst_id = dst.val.case_DS_Initiator.id; Noise_XK_init_state_t dst_st = dst.val.case_DS_Initiator.state; if (dst_st.tag == Noise_XK_IMS_Handshake) { uint8_t *st_re = dst_st.val.case_IMS_Handshake.re; uint8_t *st_rs = dst_st.val.case_IMS_Handshake.rs; uint8_t *st_epub = dst_st.val.case_IMS_Handshake.epub; uint8_t *st_epriv = dst_st.val.case_IMS_Handshake.epriv; uint8_t *st_spub = dst_st.val.case_IMS_Handshake.spub; uint8_t *st_spriv = dst_st.val.case_IMS_Handshake.spriv; uint8_t *st_h = dst_st.val.case_IMS_Handshake.h; uint8_t *st_ck = dst_st.val.case_IMS_Handshake.chaining_key; uint8_t *st_cipher = dst_st.val.case_IMS_Handshake.cipher_key; uint32_t st_step = dst_st.val.case_IMS_Handshake.step; if (st_step >= (uint32_t)3U) res0 = ( (result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } } ); else if (!(true == (st_step % (uint32_t)2U == (uint32_t)0U))) res0 = ( (result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } } ); else { result_init_state_t res1; if (st_step == (uint32_t)0U) { result_init_state_t res; if (!(payload_len <= (uint32_t)4294967215U && outlen == (uint32_t)48U + payload_len)) res = ((result_init_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CInput_size } }); else { uint32_t pat_outlen = (uint32_t)32U; uint8_t *pat_out = out; uint8_t *payload_out = out + pat_outlen; uint8_t *tk_out = pat_out; Noise_XK_mix_hash(st_h, (uint32_t)32U, st_epub); memcpy(tk_out, st_epub, (uint32_t)32U * sizeof (uint8_t)); Noise_XK_error_code r0 = Noise_XK_mix_dh(st_epriv, st_rs, st_cipher, st_ck, st_h); Noise_XK_error_code r2 = r0; Noise_XK_error_code r1 = r2; Noise_XK_error_code r; if (!(r1 == Noise_XK_CSuccess)) r = r1; else { Noise_XK_encrypt_and_hash(payload_len, payload, payload_out, st_cipher, st_h, (uint64_t)0U); r = Noise_XK_CSuccess; } Noise_XK_error_code res0 = r; if (res0 == Noise_XK_CSuccess) res = ( (result_init_state_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = st_step + (uint32_t)1U, .cipher_key = st_cipher, .chaining_key = st_ck, .h = st_h, .spriv = st_spriv, .spub = st_spub, .epriv = st_epriv, .epub = st_epub, .rs = st_rs, .re = st_re } } } } } ); else switch (res0) { case Noise_XK_CDH_error: { res = ( (result_init_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CDH_error } } ); break; } default: { KRML_HOST_EPRINTF("KaRaMeL incomplete match at %s:%d\n", __FILE__, __LINE__); KRML_HOST_EXIT(253U); } } } result_init_state_t res0 = res; res1 = res0; } else { result_init_state_t res; if (!(payload_len <= (uint32_t)4294967215U && outlen == (uint32_t)64U + payload_len)) res = ((result_init_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CInput_size } }); else { uint32_t pat_outlen = (uint32_t)48U; uint8_t *pat_out = out; uint8_t *payload_out = out + pat_outlen; uint8_t *tk_out = pat_out; Noise_XK_encrypt_and_hash((uint32_t)32U, st_spub, tk_out, st_cipher, st_h, (uint64_t)1U); Noise_XK_error_code r0 = Noise_XK_mix_dh(st_spriv, st_re, st_cipher, st_ck, st_h); Noise_XK_error_code r2 = r0; Noise_XK_error_code r1 = r2; Noise_XK_error_code r; if (!(r1 == Noise_XK_CSuccess)) r = r1; else { Noise_XK_encrypt_and_hash(payload_len, payload, payload_out, st_cipher, st_h, (uint64_t)0U); r = Noise_XK_CSuccess; } Noise_XK_error_code res0 = r; if (res0 == Noise_XK_CSuccess) res = ( (result_init_state_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = st_step + (uint32_t)1U, .cipher_key = st_cipher, .chaining_key = st_ck, .h = st_h, .spriv = st_spriv, .spub = st_spub, .epriv = st_epriv, .epub = st_epub, .rs = st_rs, .re = st_re } } } } } ); else switch (res0) { case Noise_XK_CDH_error: { res = ( (result_init_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CDH_error } } ); break; } default: { KRML_HOST_EPRINTF("KaRaMeL incomplete match at %s:%d\n", __FILE__, __LINE__); KRML_HOST_EXIT(253U); } } } result_init_state_t res0 = res; res1 = res0; } if (res1.tag == Fail) { Noise_XK_error_code e = res1.val.case_Fail; res0 = ((result_session_t){ .tag = Fail, .val = { .case_Fail = e } }); } else if (res1.tag == Res) { Noise_XK_init_state_t st1 = res1.val.case_Res; Noise_XK_session_t ite; if (st_step == (uint32_t)2U) { Noise_XK_init_state_t st11; if (st1.tag == Noise_XK_IMS_Handshake) { uint8_t *st_re1 = st1.val.case_IMS_Handshake.re; uint8_t *st_rs1 = st1.val.case_IMS_Handshake.rs; uint8_t *st_epub1 = st1.val.case_IMS_Handshake.epub; uint8_t *st_epriv1 = st1.val.case_IMS_Handshake.epriv; uint8_t *st_h1 = st1.val.case_IMS_Handshake.h; uint8_t *st_ck1 = st1.val.case_IMS_Handshake.chaining_key; uint8_t *st_k = st1.val.case_IMS_Handshake.cipher_key; uint8_t *k1 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *k2 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t temp_k1[64U] = { 0U }; uint8_t temp_k2[64U] = { 0U }; Noise_XK_kdf(st_ck1, (uint32_t)0U, NULL, temp_k1, temp_k2, NULL); memcpy(k1, temp_k1, (uint32_t)32U * sizeof (uint8_t)); memcpy(k2, temp_k2, (uint32_t)32U * sizeof (uint8_t)); #ifndef WITH_HACL sodium_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); sodium_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); Lib_Memzero0_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); #endif // WITH_SODIUM KRML_HOST_FREE(st_k); KRML_HOST_FREE(st_ck1); KRML_HOST_FREE(st_epriv1); KRML_HOST_FREE(st_epub1); KRML_HOST_FREE(st_rs1); KRML_HOST_FREE(st_re1); st11 = ( (Noise_XK_init_state_t){ .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = st_h1, .recv_transport_message = false, .send_key = k1, .send_nonce = (uint64_t)0U, .receive_key = k2, .receive_nonce = (uint64_t)0U } } } ); } else st11 = KRML_EABORT(Noise_XK_init_state_t, "unreachable (pattern matches are exhaustive in F*)"); ite = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = st11, .id = dst_id, .info = dst_info, .spriv = dst_spriv, .spub = dst_spub, .pid = dst_pid, .pinfo = dst_pinfo, .dv = dst_dv } } } ); } else ite = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = st1, .id = dst_id, .info = dst_info, .spriv = dst_spriv, .spub = dst_spub, .pid = dst_pid, .pinfo = dst_pinfo, .dv = dst_dv } } } ); res0 = ((result_session_t){ .tag = Res, .val = { .case_Res = ite } }); } else res0 = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } } else if (dst_st.tag == Noise_XK_IMS_Transport) res0 = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } }); else res0 = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } else if (dst.tag == Noise_XK_DS_Responder) { Noise_XK_device_t *dst_dv = dst.val.case_DS_Responder.dv; Noise_XK_noise_string *dst_pinfo = dst.val.case_DS_Responder.pinfo; uint32_t dst_pid = dst.val.case_DS_Responder.pid; uint8_t *dst_spub = dst.val.case_DS_Responder.spub; uint8_t *dst_spriv = dst.val.case_DS_Responder.spriv; Noise_XK_noise_string *dst_info = dst.val.case_DS_Responder.info; uint32_t dst_id = dst.val.case_DS_Responder.id; Noise_XK_resp_state_t dst_st = dst.val.case_DS_Responder.state; if (dst_st.tag == Noise_XK_IMS_Handshake) { uint8_t *st_re = dst_st.val.case_IMS_Handshake.re; uint8_t *st_rs = dst_st.val.case_IMS_Handshake.rs; uint8_t *st_epub = dst_st.val.case_IMS_Handshake.epub; uint8_t *st_epriv = dst_st.val.case_IMS_Handshake.epriv; uint8_t *st_spub = dst_st.val.case_IMS_Handshake.spub; uint8_t *st_spriv = dst_st.val.case_IMS_Handshake.spriv; uint8_t *st_h = dst_st.val.case_IMS_Handshake.h; uint8_t *st_ck = dst_st.val.case_IMS_Handshake.chaining_key; uint8_t *st_cipher = dst_st.val.case_IMS_Handshake.cipher_key; uint32_t st_step = dst_st.val.case_IMS_Handshake.step; if (st_step >= (uint32_t)3U) res0 = ( (result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } } ); else if (!(false == (st_step % (uint32_t)2U == (uint32_t)0U))) res0 = ( (result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } } ); else { result_resp_state_t res; if (!(payload_len <= (uint32_t)4294967215U && outlen == (uint32_t)48U + payload_len)) res = ((result_resp_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CInput_size } }); else { uint32_t pat_outlen = (uint32_t)32U; uint8_t *pat_out = out; uint8_t *payload_out = out + pat_outlen; uint8_t *tk_out = pat_out; Noise_XK_mix_hash(st_h, (uint32_t)32U, st_epub); memcpy(tk_out, st_epub, (uint32_t)32U * sizeof (uint8_t)); Noise_XK_error_code r0 = Noise_XK_mix_dh(st_epriv, st_re, st_cipher, st_ck, st_h); Noise_XK_error_code r2 = r0; Noise_XK_error_code r1 = r2; Noise_XK_error_code r; if (!(r1 == Noise_XK_CSuccess)) r = r1; else { Noise_XK_encrypt_and_hash(payload_len, payload, payload_out, st_cipher, st_h, (uint64_t)0U); r = Noise_XK_CSuccess; } Noise_XK_error_code res0 = r; if (res0 == Noise_XK_CSuccess) res = ( (result_resp_state_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = st_step + (uint32_t)1U, .cipher_key = st_cipher, .chaining_key = st_ck, .h = st_h, .spriv = st_spriv, .spub = st_spub, .epriv = st_epriv, .epub = st_epub, .rs = st_rs, .re = st_re } } } } } ); else switch (res0) { case Noise_XK_CDH_error: { res = ( (result_resp_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CDH_error } } ); break; } default: { KRML_HOST_EPRINTF("KaRaMeL incomplete match at %s:%d\n", __FILE__, __LINE__); KRML_HOST_EXIT(253U); } } } result_resp_state_t res1 = res; result_resp_state_t res2 = res1; if (res2.tag == Fail) { Noise_XK_error_code e = res2.val.case_Fail; res0 = ((result_session_t){ .tag = Fail, .val = { .case_Fail = e } }); } else if (res2.tag == Res) { Noise_XK_resp_state_t st1 = res2.val.case_Res; Noise_XK_session_t ite; if (st_step == (uint32_t)2U) { Noise_XK_resp_state_t st11; if (st1.tag == Noise_XK_IMS_Handshake) { uint8_t *st_re1 = st1.val.case_IMS_Handshake.re; uint8_t *st_rs1 = st1.val.case_IMS_Handshake.rs; uint8_t *st_epub1 = st1.val.case_IMS_Handshake.epub; uint8_t *st_epriv1 = st1.val.case_IMS_Handshake.epriv; uint8_t *st_h1 = st1.val.case_IMS_Handshake.h; uint8_t *st_ck1 = st1.val.case_IMS_Handshake.chaining_key; uint8_t *st_k = st1.val.case_IMS_Handshake.cipher_key; uint8_t *k1 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *k2 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t temp_k1[64U] = { 0U }; uint8_t temp_k2[64U] = { 0U }; Noise_XK_kdf(st_ck1, (uint32_t)0U, NULL, temp_k1, temp_k2, NULL); memcpy(k1, temp_k1, (uint32_t)32U * sizeof (uint8_t)); memcpy(k2, temp_k2, (uint32_t)32U * sizeof (uint8_t)); #ifndef WITH_HACL sodium_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); sodium_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); Lib_Memzero0_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); #endif // WITH_SODIUM KRML_HOST_FREE(st_k); KRML_HOST_FREE(st_ck1); KRML_HOST_FREE(st_epriv1); KRML_HOST_FREE(st_epub1); KRML_HOST_FREE(st_rs1); KRML_HOST_FREE(st_re1); st11 = ( (Noise_XK_resp_state_t){ .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = st_h1, .send_key = k2, .send_nonce = (uint64_t)0U, .receive_key = k1, .receive_nonce = (uint64_t)0U } } } ); } else st11 = KRML_EABORT(Noise_XK_resp_state_t, "unreachable (pattern matches are exhaustive in F*)"); ite = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = st11, .id = dst_id, .info = dst_info, .spriv = dst_spriv, .spub = dst_spub, .pid = dst_pid, .pinfo = dst_pinfo, .dv = dst_dv } } } ); } else ite = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = st1, .id = dst_id, .info = dst_info, .spriv = dst_spriv, .spub = dst_spub, .pid = dst_pid, .pinfo = dst_pinfo, .dv = dst_dv } } } ); res0 = ((result_session_t){ .tag = Res, .val = { .case_Res = ite } }); } else res0 = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } } else if (dst_st.tag == Noise_XK_IMS_Transport) res0 = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } }); else res0 = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } else res0 = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); if (res0.tag == Fail) { Noise_XK_error_code e = res0.val.case_Fail; Noise_XK_session_t dst1 = dst_p1[0U]; if (dst1.tag == Noise_XK_DS_Initiator) { Noise_XK_device_t *dv = dst1.val.case_DS_Initiator.dv; Noise_XK_noise_string *pinfo = dst1.val.case_DS_Initiator.pinfo; uint32_t pid = dst1.val.case_DS_Initiator.pid; uint8_t *spub = dst1.val.case_DS_Initiator.spub; uint8_t *spriv = dst1.val.case_DS_Initiator.spriv; Noise_XK_noise_string *info = dst1.val.case_DS_Initiator.info; uint32_t id = dst1.val.case_DS_Initiator.id; Noise_XK_init_state_t st = dst1.val.case_DS_Initiator.state; Noise_XK_init_state_t ite; if (st.tag == Noise_XK_IMS_Handshake) { uint8_t *re = st.val.case_IMS_Handshake.re; uint8_t *rs = st.val.case_IMS_Handshake.rs; uint8_t *epub = st.val.case_IMS_Handshake.epub; uint8_t *epriv = st.val.case_IMS_Handshake.epriv; uint8_t *spub1 = st.val.case_IMS_Handshake.spub; uint8_t *spriv1 = st.val.case_IMS_Handshake.spriv; uint8_t *h3 = st.val.case_IMS_Handshake.h; uint8_t *ck = st.val.case_IMS_Handshake.chaining_key; uint8_t *k = st.val.case_IMS_Handshake.cipher_key; ite = ( (Noise_XK_init_state_t){ .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = (uint32_t)4U, .cipher_key = k, .chaining_key = ck, .h = h3, .spriv = spriv1, .spub = spub1, .epriv = epriv, .epub = epub, .rs = rs, .re = re } } } ); } else if (st.tag == Noise_XK_IMS_Transport) { uint64_t receive_nonce = st.val.case_IMS_Transport.receive_nonce; uint8_t *receive_key = st.val.case_IMS_Transport.receive_key; uint64_t send_nonce = st.val.case_IMS_Transport.send_nonce; uint8_t *send_key = st.val.case_IMS_Transport.send_key; bool recv_tpt_msg = st.val.case_IMS_Transport.recv_transport_message; uint8_t *h3 = st.val.case_IMS_Transport.h; ite = ( (Noise_XK_init_state_t){ .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = h3, .recv_transport_message = recv_tpt_msg, .send_key = send_key, .send_nonce = send_nonce, .receive_key = receive_key, .receive_nonce = receive_nonce } } } ); } else ite = KRML_EABORT(Noise_XK_init_state_t, "unreachable (pattern matches are exhaustive in F*)"); dst_p1[0U] = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = ite, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid, .pinfo = pinfo, .dv = dv } } } ); } else if (dst1.tag == Noise_XK_DS_Responder) { Noise_XK_device_t *dv = dst1.val.case_DS_Responder.dv; Noise_XK_noise_string *pinfo = dst1.val.case_DS_Responder.pinfo; uint32_t pid = dst1.val.case_DS_Responder.pid; uint8_t *spub = dst1.val.case_DS_Responder.spub; uint8_t *spriv = dst1.val.case_DS_Responder.spriv; Noise_XK_noise_string *info = dst1.val.case_DS_Responder.info; uint32_t id = dst1.val.case_DS_Responder.id; Noise_XK_resp_state_t st = dst1.val.case_DS_Responder.state; Noise_XK_resp_state_t ite; if (st.tag == Noise_XK_IMS_Handshake) { uint8_t *re = st.val.case_IMS_Handshake.re; uint8_t *rs = st.val.case_IMS_Handshake.rs; uint8_t *epub = st.val.case_IMS_Handshake.epub; uint8_t *epriv = st.val.case_IMS_Handshake.epriv; uint8_t *spub1 = st.val.case_IMS_Handshake.spub; uint8_t *spriv1 = st.val.case_IMS_Handshake.spriv; uint8_t *h3 = st.val.case_IMS_Handshake.h; uint8_t *ck = st.val.case_IMS_Handshake.chaining_key; uint8_t *k = st.val.case_IMS_Handshake.cipher_key; ite = ( (Noise_XK_resp_state_t){ .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = (uint32_t)4U, .cipher_key = k, .chaining_key = ck, .h = h3, .spriv = spriv1, .spub = spub1, .epriv = epriv, .epub = epub, .rs = rs, .re = re } } } ); } else if (st.tag == Noise_XK_IMS_Transport) { uint64_t receive_nonce = st.val.case_IMS_Transport.receive_nonce; uint8_t *receive_key = st.val.case_IMS_Transport.receive_key; uint64_t send_nonce = st.val.case_IMS_Transport.send_nonce; uint8_t *send_key = st.val.case_IMS_Transport.send_key; uint8_t *h3 = st.val.case_IMS_Transport.h; ite = ( (Noise_XK_resp_state_t){ .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = h3, .send_key = send_key, .send_nonce = send_nonce, .receive_key = receive_key, .receive_nonce = receive_nonce } } } ); } else ite = KRML_EABORT(Noise_XK_resp_state_t, "unreachable (pattern matches are exhaustive in F*)"); dst_p1[0U] = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = ite, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid, .pinfo = pinfo, .dv = dv } } } ); } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } return e; } else if (res0.tag == Res) { Noise_XK_session_t dst1 = res0.val.case_Res; dst_p1[0U] = dst1; return Noise_XK_CSuccess; } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } #define Res0 0 #define Fail0 1 typedef uint8_t result_unit_error_tags; typedef struct result_unit_error_s { result_unit_error_tags tag; Noise_XK_error_code v; } result_unit_error; static Noise_XK_error_code state_handshake_read( uint32_t payload_outlen, uint8_t *payload_out, Noise_XK_session_t *dst_p, uint32_t inlen, uint8_t *input ) { Noise_XK_session_t dst = dst_p[0U]; uint32_t pid; if (dst.tag == Noise_XK_DS_Initiator) pid = dst.val.case_DS_Initiator.pid; else if (dst.tag == Noise_XK_DS_Responder) pid = dst.val.case_DS_Responder.pid; else pid = KRML_EABORT(uint32_t, "unreachable (pattern matches are exhaustive in F*)"); uint32_t *pid_ptr = KRML_HOST_MALLOC(sizeof (uint32_t)); pid_ptr[0U] = pid; result_session_t res0; if (dst.tag == Noise_XK_DS_Initiator) { Noise_XK_device_t *dst_dv = dst.val.case_DS_Initiator.dv; Noise_XK_noise_string *dst_pinfo = dst.val.case_DS_Initiator.pinfo; uint32_t dst_pid = dst.val.case_DS_Initiator.pid; uint8_t *dst_spub = dst.val.case_DS_Initiator.spub; uint8_t *dst_spriv = dst.val.case_DS_Initiator.spriv; Noise_XK_noise_string *dst_info = dst.val.case_DS_Initiator.info; uint32_t dst_id = dst.val.case_DS_Initiator.id; Noise_XK_init_state_t dst_st = dst.val.case_DS_Initiator.state; if (dst_st.tag == Noise_XK_IMS_Handshake) { uint8_t *st_re = dst_st.val.case_IMS_Handshake.re; uint8_t *st_rs = dst_st.val.case_IMS_Handshake.rs; uint8_t *st_epub = dst_st.val.case_IMS_Handshake.epub; uint8_t *st_epriv = dst_st.val.case_IMS_Handshake.epriv; uint8_t *st_spub = dst_st.val.case_IMS_Handshake.spub; uint8_t *st_spriv = dst_st.val.case_IMS_Handshake.spriv; uint8_t *st_h = dst_st.val.case_IMS_Handshake.h; uint8_t *st_ck = dst_st.val.case_IMS_Handshake.chaining_key; uint8_t *st_cipher = dst_st.val.case_IMS_Handshake.cipher_key; uint32_t st_step = dst_st.val.case_IMS_Handshake.step; if (st_step >= (uint32_t)3U) res0 = ( (result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } } ); else if (!(true == (st_step % (uint32_t)2U == (uint32_t)1U))) res0 = ( (result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } } ); else { Noise_XK_error_code r0; if (!(payload_outlen <= (uint32_t)4294967215U && inlen == (uint32_t)48U + payload_outlen)) r0 = Noise_XK_CInput_size; else { uint8_t *msg_input = input; uint8_t *payload_input = input + (uint32_t)32U; uint8_t *tk_input = msg_input; Noise_XK_mix_hash(st_h, (uint32_t)32U, tk_input); memcpy(st_re, tk_input, (uint32_t)32U * sizeof (uint8_t)); Noise_XK_error_code r20 = Noise_XK_mix_dh(st_epriv, st_re, st_cipher, st_ck, st_h); Noise_XK_error_code r1 = r20; Noise_XK_error_code r; if (!(r1 == Noise_XK_CSuccess)) r = r1; else { Noise_XK_error_code r2 = Noise_XK_decrypt_and_hash(payload_outlen, payload_out, payload_input, st_cipher, st_h, (uint64_t)0U); r = r2; } Noise_XK_error_code r2 = r; Noise_XK_error_code res = r2; if (res == Noise_XK_CSuccess) r0 = Noise_XK_CSuccess; else r0 = res; } Noise_XK_error_code r1 = r0; result_init_state_t r; switch (r1) { case Noise_XK_CSuccess: { r = ( (result_init_state_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = st_step + (uint32_t)1U, .cipher_key = st_cipher, .chaining_key = st_ck, .h = st_h, .spriv = st_spriv, .spub = st_spub, .epriv = st_epriv, .epub = st_epub, .rs = st_rs, .re = st_re } } } } } ); break; } default: { r = ((result_init_state_t){ .tag = Fail, .val = { .case_Fail = r1 } }); } } result_init_state_t res1 = r; result_init_state_t res2 = res1; result_session_t res; if (res2.tag == Fail) { Noise_XK_error_code e = res2.val.case_Fail; res = ((result_session_t){ .tag = Fail, .val = { .case_Fail = e } }); } else if (res2.tag == Res) { Noise_XK_init_state_t st1 = res2.val.case_Res; if (!(st_step == (uint32_t)2U)) res = ( (result_session_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = st1, .id = dst_id, .info = dst_info, .spriv = dst_spriv, .spub = dst_spub, .pid = dst_pid, .pinfo = dst_pinfo, .dv = dst_dv } } } } } ); else { uint32_t pid1 = pid_ptr[0U]; res = ( (result_session_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = st1, .id = dst_id, .info = dst_info, .spriv = dst_spriv, .spub = dst_spub, .pid = pid1, .pinfo = dst_pinfo, .dv = dst_dv } } } } } ); } } else res = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); if (res.tag == Fail) { Noise_XK_error_code e = res.val.case_Fail; res0 = ((result_session_t){ .tag = Fail, .val = { .case_Fail = e } }); } else if (res.tag == Res) { Noise_XK_session_t dst1 = res.val.case_Res; Noise_XK_session_t dst2; if (dst1.tag == Noise_XK_DS_Initiator) { Noise_XK_device_t *dv = dst1.val.case_DS_Initiator.dv; Noise_XK_noise_string *pinfo = dst1.val.case_DS_Initiator.pinfo; uint32_t pid1 = dst1.val.case_DS_Initiator.pid; uint8_t *spub = dst1.val.case_DS_Initiator.spub; uint8_t *spriv = dst1.val.case_DS_Initiator.spriv; Noise_XK_noise_string *info = dst1.val.case_DS_Initiator.info; uint32_t id = dst1.val.case_DS_Initiator.id; Noise_XK_init_state_t st = dst1.val.case_DS_Initiator.state; if (st_step == (uint32_t)2U) { Noise_XK_init_state_t st1; if (st.tag == Noise_XK_IMS_Handshake) { uint8_t *st_re1 = st.val.case_IMS_Handshake.re; uint8_t *st_rs1 = st.val.case_IMS_Handshake.rs; uint8_t *st_epub1 = st.val.case_IMS_Handshake.epub; uint8_t *st_epriv1 = st.val.case_IMS_Handshake.epriv; uint8_t *st_h1 = st.val.case_IMS_Handshake.h; uint8_t *st_ck1 = st.val.case_IMS_Handshake.chaining_key; uint8_t *st_k = st.val.case_IMS_Handshake.cipher_key; uint8_t *k1 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *k2 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t temp_k1[64U] = { 0U }; uint8_t temp_k2[64U] = { 0U }; Noise_XK_kdf(st_ck1, (uint32_t)0U, NULL, temp_k1, temp_k2, NULL); memcpy(k1, temp_k1, (uint32_t)32U * sizeof (uint8_t)); memcpy(k2, temp_k2, (uint32_t)32U * sizeof (uint8_t)); #ifndef WITH_HACL sodium_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); sodium_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); Lib_Memzero0_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); #endif // WITH_SODIUM KRML_HOST_FREE(st_k); KRML_HOST_FREE(st_ck1); KRML_HOST_FREE(st_epriv1); KRML_HOST_FREE(st_epub1); KRML_HOST_FREE(st_rs1); KRML_HOST_FREE(st_re1); st1 = ( (Noise_XK_init_state_t){ .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = st_h1, .recv_transport_message = false, .send_key = k1, .send_nonce = (uint64_t)0U, .receive_key = k2, .receive_nonce = (uint64_t)0U } } } ); } else st1 = KRML_EABORT(Noise_XK_init_state_t, "unreachable (pattern matches are exhaustive in F*)"); dst2 = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = st1, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid1, .pinfo = pinfo, .dv = dv } } } ); } else dst2 = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = st, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid1, .pinfo = pinfo, .dv = dv } } } ); } else dst2 = KRML_EABORT(Noise_XK_session_t, "unreachable (pattern matches are exhaustive in F*)"); res0 = ((result_session_t){ .tag = Res, .val = { .case_Res = dst2 } }); } else res0 = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } } else if (dst_st.tag == Noise_XK_IMS_Transport) res0 = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } }); else res0 = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } else if (dst.tag == Noise_XK_DS_Responder) { Noise_XK_device_t *dst_dv = dst.val.case_DS_Responder.dv; Noise_XK_noise_string *dst_pinfo = dst.val.case_DS_Responder.pinfo; uint32_t dst_pid = dst.val.case_DS_Responder.pid; uint8_t *dst_spub = dst.val.case_DS_Responder.spub; uint8_t *dst_spriv = dst.val.case_DS_Responder.spriv; Noise_XK_noise_string *dst_info = dst.val.case_DS_Responder.info; uint32_t dst_id = dst.val.case_DS_Responder.id; Noise_XK_resp_state_t dst_st = dst.val.case_DS_Responder.state; if (dst_st.tag == Noise_XK_IMS_Handshake) { uint8_t *st_re = dst_st.val.case_IMS_Handshake.re; uint8_t *st_rs = dst_st.val.case_IMS_Handshake.rs; uint8_t *st_epub = dst_st.val.case_IMS_Handshake.epub; uint8_t *st_epriv = dst_st.val.case_IMS_Handshake.epriv; uint8_t *st_spub = dst_st.val.case_IMS_Handshake.spub; uint8_t *st_spriv = dst_st.val.case_IMS_Handshake.spriv; uint8_t *st_h = dst_st.val.case_IMS_Handshake.h; uint8_t *st_ck = dst_st.val.case_IMS_Handshake.chaining_key; uint8_t *st_cipher = dst_st.val.case_IMS_Handshake.cipher_key; uint32_t st_step = dst_st.val.case_IMS_Handshake.step; if (st_step >= (uint32_t)3U) res0 = ( (result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } } ); else if (!(false == (st_step % (uint32_t)2U == (uint32_t)1U))) res0 = ( (result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } } ); else { Noise_XK_device_t dv0 = dst_dv[0U]; result_resp_state_t res1; if (st_step == (uint32_t)0U) { Noise_XK_error_code r0; if (!(payload_outlen <= (uint32_t)4294967215U && inlen == (uint32_t)48U + payload_outlen)) r0 = Noise_XK_CInput_size; else { uint8_t *msg_input = input; uint8_t *payload_input = input + (uint32_t)32U; uint8_t *tk_input = msg_input; Noise_XK_mix_hash(st_h, (uint32_t)32U, tk_input); memcpy(st_re, tk_input, (uint32_t)32U * sizeof (uint8_t)); Noise_XK_error_code r20 = Noise_XK_mix_dh(st_spriv, st_re, st_cipher, st_ck, st_h); Noise_XK_error_code r1 = r20; Noise_XK_error_code r; if (!(r1 == Noise_XK_CSuccess)) r = r1; else { Noise_XK_error_code r2 = Noise_XK_decrypt_and_hash(payload_outlen, payload_out, payload_input, st_cipher, st_h, (uint64_t)0U); r = r2; } Noise_XK_error_code r2 = r; Noise_XK_error_code res = r2; if (res == Noise_XK_CSuccess) r0 = Noise_XK_CSuccess; else r0 = res; } Noise_XK_error_code r1 = r0; result_resp_state_t r; switch (r1) { case Noise_XK_CSuccess: { r = ( (result_resp_state_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = st_step + (uint32_t)1U, .cipher_key = st_cipher, .chaining_key = st_ck, .h = st_h, .spriv = st_spriv, .spub = st_spub, .epriv = st_epriv, .epub = st_epub, .rs = st_rs, .re = st_re } } } } } ); break; } default: { r = ((result_resp_state_t){ .tag = Fail, .val = { .case_Fail = r1 } }); } } result_resp_state_t res = r; res1 = res; } else { result_unit_error r0; if (!(payload_outlen <= (uint32_t)4294967215U && inlen == (uint32_t)64U + payload_outlen)) r0 = ((result_unit_error){ .tag = Fail0, .v = Noise_XK_CInput_size }); else { uint8_t *msg1 = input; uint8_t *msg2 = input + (uint32_t)48U; Noise_XK_error_code r1 = Noise_XK_decrypt_and_hash((uint32_t)32U, st_rs, msg1, st_cipher, st_h, (uint64_t)1U); Noise_XK_error_code r3 = r1; Noise_XK_error_code r10 = r3; if (r10 == Noise_XK_CSuccess) { Noise_XK_cell **peers1 = dv0.dv_peers; Noise_XK_cell *llt = *peers1; Noise_XK_cell *lltp = llt; Noise_XK_cell *llt10 = lltp; bool b0; if (llt10 == NULL) b0 = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b = Noise_XK_lbytes_eq((uint32_t)32U, x.p_s, st_rs); b0 = !b; } bool cond = b0; while (cond) { Noise_XK_cell *llt1 = lltp; Noise_XK_cell c0 = llt1[0U]; lltp = c0.next; Noise_XK_cell *llt10 = lltp; bool b; if (llt10 == NULL) b = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b0 = Noise_XK_lbytes_eq((uint32_t)32U, x.p_s, st_rs); b = !b0; } cond = b; } Noise_XK_cell *llt1 = *&lltp; Noise_XK_peer_t *res; if (llt1 == NULL) res = NULL; else { Noise_XK_cell c = *llt1; res = c.data; } Noise_XK_peer_t *peer_ptr = res; bool b1; if (!(peer_ptr == NULL)) { Noise_XK_peer_t peer = peer_ptr[0U]; uint8_t *input_str = peer.p_info[0U]; bool b = input_str == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = input_str[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = input_str[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = input_str[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } dst_pinfo[0U] = out_str; pid_ptr[0U] = peer.p_id; b1 = true; } else { pid_ptr[0U] = (uint32_t)0U; b1 = false; } bool r1 = b1; if (r1) { uint8_t *payload_input = msg2; Noise_XK_error_code r11 = Noise_XK_mix_dh(st_epriv, st_rs, st_cipher, st_ck, st_h); Noise_XK_error_code r; if (!(r11 == Noise_XK_CSuccess)) r = r11; else { Noise_XK_error_code r2 = Noise_XK_decrypt_and_hash(payload_outlen, payload_out, payload_input, st_cipher, st_h, (uint64_t)0U); r = r2; } Noise_XK_error_code r1 = r; Noise_XK_error_code r2 = r1; if (r2 == Noise_XK_CSuccess) r0 = ((result_unit_error){ .tag = Res0 }); else r0 = ((result_unit_error){ .tag = Fail0, .v = r2 }); } else r0 = ((result_unit_error){ .tag = Fail0, .v = Noise_XK_CRs_rejected_by_policy }); } else r0 = ((result_unit_error){ .tag = Fail0, .v = r10 }); } result_resp_state_t res; if (r0.tag == Res0) res = ( (result_resp_state_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = st_step + (uint32_t)1U, .cipher_key = st_cipher, .chaining_key = st_ck, .h = st_h, .spriv = st_spriv, .spub = st_spub, .epriv = st_epriv, .epub = st_epub, .rs = st_rs, .re = st_re } } } } } ); else if (r0.tag == Fail0) { Noise_XK_error_code e = r0.v; res = ((result_resp_state_t){ .tag = Fail, .val = { .case_Fail = e } }); } else res = KRML_EABORT(result_resp_state_t, "unreachable (pattern matches are exhaustive in F*)"); res1 = res; } result_session_t res; if (res1.tag == Fail) { Noise_XK_error_code e = res1.val.case_Fail; res = ((result_session_t){ .tag = Fail, .val = { .case_Fail = e } }); } else if (res1.tag == Res) { Noise_XK_resp_state_t st1 = res1.val.case_Res; if (!(st_step == (uint32_t)2U)) res = ( (result_session_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = st1, .id = dst_id, .info = dst_info, .spriv = dst_spriv, .spub = dst_spub, .pid = dst_pid, .pinfo = dst_pinfo, .dv = dst_dv } } } } } ); else { uint32_t pid1 = pid_ptr[0U]; res = ( (result_session_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = st1, .id = dst_id, .info = dst_info, .spriv = dst_spriv, .spub = dst_spub, .pid = pid1, .pinfo = dst_pinfo, .dv = dst_dv } } } } } ); } } else res = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); if (res.tag == Fail) { Noise_XK_error_code e = res.val.case_Fail; res0 = ((result_session_t){ .tag = Fail, .val = { .case_Fail = e } }); } else if (res.tag == Res) { Noise_XK_session_t dst1 = res.val.case_Res; Noise_XK_session_t dst2; if (dst1.tag == Noise_XK_DS_Responder) { Noise_XK_device_t *dv = dst1.val.case_DS_Responder.dv; Noise_XK_noise_string *pinfo = dst1.val.case_DS_Responder.pinfo; uint32_t pid1 = dst1.val.case_DS_Responder.pid; uint8_t *spub = dst1.val.case_DS_Responder.spub; uint8_t *spriv = dst1.val.case_DS_Responder.spriv; Noise_XK_noise_string *info = dst1.val.case_DS_Responder.info; uint32_t id = dst1.val.case_DS_Responder.id; Noise_XK_resp_state_t st = dst1.val.case_DS_Responder.state; if (st_step == (uint32_t)2U) { Noise_XK_resp_state_t st1; if (st.tag == Noise_XK_IMS_Handshake) { uint8_t *st_re1 = st.val.case_IMS_Handshake.re; uint8_t *st_rs1 = st.val.case_IMS_Handshake.rs; uint8_t *st_epub1 = st.val.case_IMS_Handshake.epub; uint8_t *st_epriv1 = st.val.case_IMS_Handshake.epriv; uint8_t *st_h1 = st.val.case_IMS_Handshake.h; uint8_t *st_ck1 = st.val.case_IMS_Handshake.chaining_key; uint8_t *st_k = st.val.case_IMS_Handshake.cipher_key; uint8_t *k1 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *k2 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t temp_k1[64U] = { 0U }; uint8_t temp_k2[64U] = { 0U }; Noise_XK_kdf(st_ck1, (uint32_t)0U, NULL, temp_k1, temp_k2, NULL); memcpy(k1, temp_k1, (uint32_t)32U * sizeof (uint8_t)); memcpy(k2, temp_k2, (uint32_t)32U * sizeof (uint8_t)); #ifndef WITH_HACL sodium_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); sodium_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); #else // WITH_SODIUM Lib_Memzero0_memzero(temp_k1, (uint32_t)64U * sizeof (temp_k1[0U])); Lib_Memzero0_memzero(temp_k2, (uint32_t)64U * sizeof (temp_k2[0U])); #endif // WITH_SODIUM KRML_HOST_FREE(st_k); KRML_HOST_FREE(st_ck1); KRML_HOST_FREE(st_epriv1); KRML_HOST_FREE(st_epub1); KRML_HOST_FREE(st_rs1); KRML_HOST_FREE(st_re1); st1 = ( (Noise_XK_resp_state_t){ .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = st_h1, .send_key = k2, .send_nonce = (uint64_t)0U, .receive_key = k1, .receive_nonce = (uint64_t)0U } } } ); } else st1 = KRML_EABORT(Noise_XK_resp_state_t, "unreachable (pattern matches are exhaustive in F*)"); dst2 = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = st1, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid1, .pinfo = pinfo, .dv = dv } } } ); } else dst2 = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = st, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid1, .pinfo = pinfo, .dv = dv } } } ); } else dst2 = KRML_EABORT(Noise_XK_session_t, "unreachable (pattern matches are exhaustive in F*)"); res0 = ((result_session_t){ .tag = Res, .val = { .case_Res = dst2 } }); } else res0 = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } } else if (dst_st.tag == Noise_XK_IMS_Transport) res0 = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } }); else res0 = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } else res0 = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_FREE(pid_ptr); if (res0.tag == Fail) { Noise_XK_error_code e = res0.val.case_Fail; Noise_XK_session_t dst1 = dst_p[0U]; if (dst1.tag == Noise_XK_DS_Initiator) { Noise_XK_device_t *dv = dst1.val.case_DS_Initiator.dv; Noise_XK_noise_string *pinfo = dst1.val.case_DS_Initiator.pinfo; uint32_t pid1 = dst1.val.case_DS_Initiator.pid; uint8_t *spub = dst1.val.case_DS_Initiator.spub; uint8_t *spriv = dst1.val.case_DS_Initiator.spriv; Noise_XK_noise_string *info = dst1.val.case_DS_Initiator.info; uint32_t id = dst1.val.case_DS_Initiator.id; Noise_XK_init_state_t st = dst1.val.case_DS_Initiator.state; Noise_XK_init_state_t ite; if (st.tag == Noise_XK_IMS_Handshake) { uint8_t *re = st.val.case_IMS_Handshake.re; uint8_t *rs = st.val.case_IMS_Handshake.rs; uint8_t *epub = st.val.case_IMS_Handshake.epub; uint8_t *epriv = st.val.case_IMS_Handshake.epriv; uint8_t *spub1 = st.val.case_IMS_Handshake.spub; uint8_t *spriv1 = st.val.case_IMS_Handshake.spriv; uint8_t *h4 = st.val.case_IMS_Handshake.h; uint8_t *ck = st.val.case_IMS_Handshake.chaining_key; uint8_t *k = st.val.case_IMS_Handshake.cipher_key; ite = ( (Noise_XK_init_state_t){ .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = (uint32_t)4U, .cipher_key = k, .chaining_key = ck, .h = h4, .spriv = spriv1, .spub = spub1, .epriv = epriv, .epub = epub, .rs = rs, .re = re } } } ); } else if (st.tag == Noise_XK_IMS_Transport) { uint64_t receive_nonce = st.val.case_IMS_Transport.receive_nonce; uint8_t *receive_key = st.val.case_IMS_Transport.receive_key; uint64_t send_nonce = st.val.case_IMS_Transport.send_nonce; uint8_t *send_key = st.val.case_IMS_Transport.send_key; bool recv_tpt_msg = st.val.case_IMS_Transport.recv_transport_message; uint8_t *h4 = st.val.case_IMS_Transport.h; ite = ( (Noise_XK_init_state_t){ .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = h4, .recv_transport_message = recv_tpt_msg, .send_key = send_key, .send_nonce = send_nonce, .receive_key = receive_key, .receive_nonce = receive_nonce } } } ); } else ite = KRML_EABORT(Noise_XK_init_state_t, "unreachable (pattern matches are exhaustive in F*)"); dst_p[0U] = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = ite, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid1, .pinfo = pinfo, .dv = dv } } } ); } else if (dst1.tag == Noise_XK_DS_Responder) { Noise_XK_device_t *dv = dst1.val.case_DS_Responder.dv; Noise_XK_noise_string *pinfo = dst1.val.case_DS_Responder.pinfo; uint32_t pid1 = dst1.val.case_DS_Responder.pid; uint8_t *spub = dst1.val.case_DS_Responder.spub; uint8_t *spriv = dst1.val.case_DS_Responder.spriv; Noise_XK_noise_string *info = dst1.val.case_DS_Responder.info; uint32_t id = dst1.val.case_DS_Responder.id; Noise_XK_resp_state_t st = dst1.val.case_DS_Responder.state; Noise_XK_resp_state_t ite; if (st.tag == Noise_XK_IMS_Handshake) { uint8_t *re = st.val.case_IMS_Handshake.re; uint8_t *rs = st.val.case_IMS_Handshake.rs; uint8_t *epub = st.val.case_IMS_Handshake.epub; uint8_t *epriv = st.val.case_IMS_Handshake.epriv; uint8_t *spub1 = st.val.case_IMS_Handshake.spub; uint8_t *spriv1 = st.val.case_IMS_Handshake.spriv; uint8_t *h4 = st.val.case_IMS_Handshake.h; uint8_t *ck = st.val.case_IMS_Handshake.chaining_key; uint8_t *k = st.val.case_IMS_Handshake.cipher_key; ite = ( (Noise_XK_resp_state_t){ .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = (uint32_t)4U, .cipher_key = k, .chaining_key = ck, .h = h4, .spriv = spriv1, .spub = spub1, .epriv = epriv, .epub = epub, .rs = rs, .re = re } } } ); } else if (st.tag == Noise_XK_IMS_Transport) { uint64_t receive_nonce = st.val.case_IMS_Transport.receive_nonce; uint8_t *receive_key = st.val.case_IMS_Transport.receive_key; uint64_t send_nonce = st.val.case_IMS_Transport.send_nonce; uint8_t *send_key = st.val.case_IMS_Transport.send_key; uint8_t *h4 = st.val.case_IMS_Transport.h; ite = ( (Noise_XK_resp_state_t){ .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = h4, .send_key = send_key, .send_nonce = send_nonce, .receive_key = receive_key, .receive_nonce = receive_nonce } } } ); } else ite = KRML_EABORT(Noise_XK_resp_state_t, "unreachable (pattern matches are exhaustive in F*)"); dst_p[0U] = ( (Noise_XK_session_t){ .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = ite, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid1, .pinfo = pinfo, .dv = dv } } } ); } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } return e; } else if (res0.tag == Res) { Noise_XK_session_t dst1 = res0.val.case_Res; dst_p[0U] = dst1; return Noise_XK_CSuccess; } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } static Noise_XK_error_code state_transport_write( uint32_t plen, uint8_t *p, uint32_t clen, uint8_t *c, Noise_XK_session_t *dst_p ) { Noise_XK_session_t dst = dst_p[0U]; result_session_t r; if (dst.tag == Noise_XK_DS_Initiator) { Noise_XK_device_t *dv = dst.val.case_DS_Initiator.dv; Noise_XK_noise_string *pinfo = dst.val.case_DS_Initiator.pinfo; uint32_t pid = dst.val.case_DS_Initiator.pid; uint8_t *spub = dst.val.case_DS_Initiator.spub; uint8_t *spriv = dst.val.case_DS_Initiator.spriv; Noise_XK_noise_string *info = dst.val.case_DS_Initiator.info; uint32_t id = dst.val.case_DS_Initiator.id; Noise_XK_init_state_t state = dst.val.case_DS_Initiator.state; bool ite; if (state.tag == Noise_XK_IMS_Handshake) ite = true; else ite = false; if (!ite) { result_init_state_t scrut; if (state.tag == Noise_XK_IMS_Transport) { uint64_t receive_nonce = state.val.case_IMS_Transport.receive_nonce; uint8_t *receive_key = state.val.case_IMS_Transport.receive_key; uint64_t send_nonce = state.val.case_IMS_Transport.send_nonce; uint8_t *send_key = state.val.case_IMS_Transport.send_key; bool recv_tpt_msg = state.val.case_IMS_Transport.recv_transport_message; uint8_t *h = state.val.case_IMS_Transport.h; if (!(plen <= (uint32_t)4294967279U && clen == plen + (uint32_t)16U)) scrut = ((result_init_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CInput_size } }); else if (send_nonce >= (uint64_t)18446744073709551615U) scrut = ( (result_init_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CSaturated_nonce } } ); else { Noise_XK_aead_encrypt(send_key, send_nonce, (uint32_t)0U, NULL, plen, p, c); scrut = ( (result_init_state_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = h, .recv_transport_message = recv_tpt_msg, .send_key = send_key, .send_nonce = send_nonce + (uint64_t)1U, .receive_key = receive_key, .receive_nonce = receive_nonce } } } } } ); } } else scrut = KRML_EABORT(result_init_state_t, "unreachable (pattern matches are exhaustive in F*)"); if (scrut.tag == Fail) { Noise_XK_error_code e = scrut.val.case_Fail; r = ((result_session_t){ .tag = Fail, .val = { .case_Fail = e } }); } else if (scrut.tag == Res) { Noise_XK_init_state_t state_ = scrut.val.case_Res; r = ( (result_session_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = state_, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid, .pinfo = pinfo, .dv = dv } } } } } ); } else r = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } else r = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } }); } else if (dst.tag == Noise_XK_DS_Responder) { Noise_XK_device_t *dv = dst.val.case_DS_Responder.dv; Noise_XK_noise_string *pinfo = dst.val.case_DS_Responder.pinfo; uint32_t pid = dst.val.case_DS_Responder.pid; uint8_t *spub = dst.val.case_DS_Responder.spub; uint8_t *spriv = dst.val.case_DS_Responder.spriv; Noise_XK_noise_string *info = dst.val.case_DS_Responder.info; uint32_t id = dst.val.case_DS_Responder.id; Noise_XK_resp_state_t state = dst.val.case_DS_Responder.state; bool ite; if (state.tag == Noise_XK_IMS_Handshake) ite = true; else ite = false; if (!ite) { result_resp_state_t scrut; if (state.tag == Noise_XK_IMS_Transport) { uint64_t receive_nonce = state.val.case_IMS_Transport.receive_nonce; uint8_t *receive_key = state.val.case_IMS_Transport.receive_key; uint64_t send_nonce = state.val.case_IMS_Transport.send_nonce; uint8_t *send_key = state.val.case_IMS_Transport.send_key; uint8_t *h = state.val.case_IMS_Transport.h; if (!(plen <= (uint32_t)4294967279U && clen == plen + (uint32_t)16U)) scrut = ((result_resp_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CInput_size } }); else if (send_nonce >= (uint64_t)18446744073709551615U) scrut = ( (result_resp_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CSaturated_nonce } } ); else { Noise_XK_aead_encrypt(send_key, send_nonce, (uint32_t)0U, NULL, plen, p, c); scrut = ( (result_resp_state_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = h, .send_key = send_key, .send_nonce = send_nonce + (uint64_t)1U, .receive_key = receive_key, .receive_nonce = receive_nonce } } } } } ); } } else scrut = KRML_EABORT(result_resp_state_t, "unreachable (pattern matches are exhaustive in F*)"); if (scrut.tag == Fail) { Noise_XK_error_code e = scrut.val.case_Fail; r = ((result_session_t){ .tag = Fail, .val = { .case_Fail = e } }); } else if (scrut.tag == Res) { Noise_XK_resp_state_t state_ = scrut.val.case_Res; r = ( (result_session_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = state_, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid, .pinfo = pinfo, .dv = dv } } } } } ); } else r = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } else r = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } }); } else r = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); if (r.tag == Fail) return r.val.case_Fail; else if (r.tag == Res) { Noise_XK_session_t dst_ = r.val.case_Res; dst_p[0U] = dst_; return Noise_XK_CSuccess; } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } static Noise_XK_error_code state_transport_read( uint32_t plen, uint8_t *p, uint32_t clen, uint8_t *c, Noise_XK_session_t *dst_p ) { Noise_XK_session_t dst = dst_p[0U]; result_session_t r; if (dst.tag == Noise_XK_DS_Initiator) { Noise_XK_device_t *dv = dst.val.case_DS_Initiator.dv; Noise_XK_noise_string *pinfo = dst.val.case_DS_Initiator.pinfo; uint32_t pid = dst.val.case_DS_Initiator.pid; uint8_t *spub = dst.val.case_DS_Initiator.spub; uint8_t *spriv = dst.val.case_DS_Initiator.spriv; Noise_XK_noise_string *info = dst.val.case_DS_Initiator.info; uint32_t id = dst.val.case_DS_Initiator.id; Noise_XK_init_state_t state = dst.val.case_DS_Initiator.state; bool ite; if (state.tag == Noise_XK_IMS_Handshake) ite = true; else ite = false; if (!ite) { result_init_state_t scrut; if (state.tag == Noise_XK_IMS_Transport) { uint64_t receive_nonce = state.val.case_IMS_Transport.receive_nonce; uint8_t *receive_key = state.val.case_IMS_Transport.receive_key; uint64_t send_nonce = state.val.case_IMS_Transport.send_nonce; uint8_t *send_key = state.val.case_IMS_Transport.send_key; uint8_t *h = state.val.case_IMS_Transport.h; if (!(plen <= (uint32_t)4294967279U && clen == plen + (uint32_t)16U)) scrut = ((result_init_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CInput_size } }); else if (receive_nonce >= (uint64_t)18446744073709551615U) scrut = ( (result_init_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CSaturated_nonce } } ); else switch (Noise_XK_aead_decrypt(receive_key, receive_nonce, (uint32_t)0U, NULL, plen, p, c)) { case Noise_XK_CDecrypt_error: { scrut = ( (result_init_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CDecrypt_error } } ); break; } case Noise_XK_CSuccess: { scrut = ( (result_init_state_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = h, .recv_transport_message = true, .send_key = send_key, .send_nonce = send_nonce, .receive_key = receive_key, .receive_nonce = receive_nonce + (uint64_t)1U } } } } } ); break; } default: { KRML_HOST_EPRINTF("KaRaMeL incomplete match at %s:%d\n", __FILE__, __LINE__); KRML_HOST_EXIT(253U); } } } else scrut = KRML_EABORT(result_init_state_t, "unreachable (pattern matches are exhaustive in F*)"); if (scrut.tag == Fail) { Noise_XK_error_code e = scrut.val.case_Fail; r = ((result_session_t){ .tag = Fail, .val = { .case_Fail = e } }); } else if (scrut.tag == Res) { Noise_XK_init_state_t state_ = scrut.val.case_Res; r = ( (result_session_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = state_, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid, .pinfo = pinfo, .dv = dv } } } } } ); } else r = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } else r = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } }); } else if (dst.tag == Noise_XK_DS_Responder) { Noise_XK_device_t *dv = dst.val.case_DS_Responder.dv; Noise_XK_noise_string *pinfo = dst.val.case_DS_Responder.pinfo; uint32_t pid = dst.val.case_DS_Responder.pid; uint8_t *spub = dst.val.case_DS_Responder.spub; uint8_t *spriv = dst.val.case_DS_Responder.spriv; Noise_XK_noise_string *info = dst.val.case_DS_Responder.info; uint32_t id = dst.val.case_DS_Responder.id; Noise_XK_resp_state_t state = dst.val.case_DS_Responder.state; bool ite; if (state.tag == Noise_XK_IMS_Handshake) ite = true; else ite = false; if (!ite) { result_resp_state_t scrut; if (state.tag == Noise_XK_IMS_Transport) { uint64_t receive_nonce = state.val.case_IMS_Transport.receive_nonce; uint8_t *receive_key = state.val.case_IMS_Transport.receive_key; uint64_t send_nonce = state.val.case_IMS_Transport.send_nonce; uint8_t *send_key = state.val.case_IMS_Transport.send_key; uint8_t *h = state.val.case_IMS_Transport.h; if (!(plen <= (uint32_t)4294967279U && clen == plen + (uint32_t)16U)) scrut = ((result_resp_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CInput_size } }); else if (receive_nonce >= (uint64_t)18446744073709551615U) scrut = ( (result_resp_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CSaturated_nonce } } ); else switch (Noise_XK_aead_decrypt(receive_key, receive_nonce, (uint32_t)0U, NULL, plen, p, c)) { case Noise_XK_CDecrypt_error: { scrut = ( (result_resp_state_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CDecrypt_error } } ); break; } case Noise_XK_CSuccess: { scrut = ( (result_resp_state_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_IMS_Transport, .val = { .case_IMS_Transport = { .h = h, .send_key = send_key, .send_nonce = send_nonce, .receive_key = receive_key, .receive_nonce = receive_nonce + (uint64_t)1U } } } } } ); break; } default: { KRML_HOST_EPRINTF("KaRaMeL incomplete match at %s:%d\n", __FILE__, __LINE__); KRML_HOST_EXIT(253U); } } } else scrut = KRML_EABORT(result_resp_state_t, "unreachable (pattern matches are exhaustive in F*)"); if (scrut.tag == Fail) { Noise_XK_error_code e = scrut.val.case_Fail; r = ((result_session_t){ .tag = Fail, .val = { .case_Fail = e } }); } else if (scrut.tag == Res) { Noise_XK_resp_state_t state_ = scrut.val.case_Res; r = ( (result_session_t){ .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = state_, .id = id, .info = info, .spriv = spriv, .spub = spub, .pid = pid, .pinfo = pinfo, .dv = dv } } } } } ); } else r = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); } else r = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } }); } else r = KRML_EABORT(result_session_t, "unreachable (pattern matches are exhaustive in F*)"); if (r.tag == Fail) return r.val.case_Fail; else if (r.tag == Res) { Noise_XK_session_t dst_ = r.val.case_Res; dst_p[0U] = dst_; return Noise_XK_CSuccess; } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } #define None 0 #define Some 1 typedef uint8_t option__uint32_t_tags; typedef struct option__uint32_t_s { option__uint32_t_tags tag; uint32_t v; } option__uint32_t; /* Write a message with the current session. If successful, this function will allocate a buffer of the proper length in `*out` and will write the length of this buffer in `*out_len`. Note that using `out` and `out_len` is always safe: if the function fails, it will set `*outlen` to 0 and `*out` to NULL. */ Noise_XK_rcode Noise_XK_session_write( Noise_XK_encap_message_t *payload, Noise_XK_session_t *sn_p, uint32_t *out_len, uint8_t **out ) { Noise_XK_session_t *sn_p1 = sn_p; Noise_XK_session_t *snp = sn_p1; Noise_XK_session_t sn = snp[0U]; if (sn.tag == Noise_XK_DS_Initiator) { Noise_XK_init_state_t sn_state = sn.val.case_DS_Initiator.state; if (sn_state.tag == Noise_XK_IMS_Transport) { bool recv_tpt_msg = sn_state.val.case_IMS_Transport.recv_transport_message; Noise_XK_encap_message_t encap_payload = payload[0U]; bool next_length_ok; if (encap_payload.em_message_len <= (uint32_t)4294967279U) { out_len[0U] = encap_payload.em_message_len + (uint32_t)16U; next_length_ok = true; } else next_length_ok = false; if (next_length_ok) { bool sec_ok; if (encap_payload.em_message_len == (uint32_t)0U) sec_ok = true; else { uint8_t clevel; if (recv_tpt_msg) clevel = (uint8_t)5U; else clevel = (uint8_t)5U; if (encap_payload.em_ac_level.tag == Noise_XK_Conf_level) { uint8_t req_level = encap_payload.em_ac_level.val.case_Conf_level; sec_ok = (req_level >= (uint8_t)2U && clevel >= req_level) || (req_level == (uint8_t)1U && (clevel == req_level || clevel >= (uint8_t)3U)) || req_level == (uint8_t)0U; } else sec_ok = false; } if (sec_ok) { uint32_t outlen = out_len[0U]; KRML_CHECK_SIZE(sizeof (uint8_t), outlen); uint8_t *out1 = KRML_HOST_CALLOC(outlen, sizeof (uint8_t)); Noise_XK_error_code res = state_transport_write(encap_payload.em_message_len, encap_payload.em_message, outlen, out1, sn_p1); if (res == Noise_XK_CSuccess) { out[0U] = out1; return ((Noise_XK_rcode){ .tag = Noise_XK_Success }); } else { Noise_XK_error_code e = res; KRML_HOST_FREE(out1); out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = e } }); } } else { out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CSecurity_level } } ); } } else { out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CInput_size } }); } } else if (sn_state.tag == Noise_XK_IMS_Handshake) { uint32_t st_step = sn_state.val.case_IMS_Handshake.step; if (st_step >= (uint32_t)4U) { out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Stuck, .val = { .case_Stuck = Noise_XK_CIncorrect_transition } } ); } else { Noise_XK_encap_message_t encap_payload = payload[0U]; option__uint32_t scrut; if ((uint32_t)0U == st_step) if (encap_payload.em_message_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = encap_payload.em_message_len + (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)1U == st_step) if (encap_payload.em_message_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = encap_payload.em_message_len + (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)2U == st_step) if (encap_payload.em_message_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = encap_payload.em_message_len + (uint32_t)64U }); else scrut = ((option__uint32_t){ .tag = None }); else scrut = ((option__uint32_t){ .tag = None }); bool next_length_ok; if (scrut.tag == Some) { uint32_t l = scrut.v; out_len[0U] = l; next_length_ok = true; } else next_length_ok = false; if (next_length_ok) { bool sec_ok; if (encap_payload.em_message_len == (uint32_t)0U) sec_ok = true; else { uint8_t clevel; if (st_step == (uint32_t)0U) clevel = (uint8_t)2U; else if (st_step == (uint32_t)1U) clevel = (uint8_t)1U; else clevel = (uint8_t)5U; if (encap_payload.em_ac_level.tag == Noise_XK_Conf_level) { uint8_t req_level = encap_payload.em_ac_level.val.case_Conf_level; sec_ok = (req_level >= (uint8_t)2U && clevel >= req_level) || (req_level == (uint8_t)1U && (clevel == req_level || clevel >= (uint8_t)3U)) || req_level == (uint8_t)0U; } else sec_ok = false; } if (sec_ok) { uint32_t outlen = out_len[0U]; KRML_CHECK_SIZE(sizeof (uint8_t), outlen); uint8_t *out1 = KRML_HOST_CALLOC(outlen, sizeof (uint8_t)); Noise_XK_error_code res = state_handshake_write(encap_payload.em_message_len, encap_payload.em_message, sn_p1, outlen, out1); if (res == Noise_XK_CSuccess) { out[0U] = out1; return ((Noise_XK_rcode){ .tag = Noise_XK_Success }); } else { Noise_XK_error_code e = res; KRML_HOST_FREE(out1); out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Stuck, .val = { .case_Stuck = e } }); } } else { out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CSecurity_level } } ); } } else { out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CInput_size } } ); } } } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } else if (sn.tag == Noise_XK_DS_Responder) { Noise_XK_resp_state_t sn_state = sn.val.case_DS_Responder.state; if (sn_state.tag == Noise_XK_IMS_Transport) { Noise_XK_encap_message_t encap_payload = payload[0U]; bool next_length_ok; if (encap_payload.em_message_len <= (uint32_t)4294967279U) { out_len[0U] = encap_payload.em_message_len + (uint32_t)16U; next_length_ok = true; } else next_length_ok = false; if (next_length_ok) { bool sec_ok; if (encap_payload.em_message_len == (uint32_t)0U) sec_ok = true; else { uint8_t clevel = (uint8_t)5U; if (encap_payload.em_ac_level.tag == Noise_XK_Conf_level) { uint8_t req_level = encap_payload.em_ac_level.val.case_Conf_level; sec_ok = (req_level >= (uint8_t)2U && clevel >= req_level) || (req_level == (uint8_t)1U && (clevel == req_level || clevel >= (uint8_t)3U)) || req_level == (uint8_t)0U; } else sec_ok = false; } if (sec_ok) { uint32_t outlen = out_len[0U]; KRML_CHECK_SIZE(sizeof (uint8_t), outlen); uint8_t *out1 = KRML_HOST_CALLOC(outlen, sizeof (uint8_t)); Noise_XK_error_code res = state_transport_write(encap_payload.em_message_len, encap_payload.em_message, outlen, out1, sn_p1); if (res == Noise_XK_CSuccess) { out[0U] = out1; return ((Noise_XK_rcode){ .tag = Noise_XK_Success }); } else { Noise_XK_error_code e = res; KRML_HOST_FREE(out1); out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = e } }); } } else { out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CSecurity_level } } ); } } else { out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CInput_size } }); } } else if (sn_state.tag == Noise_XK_IMS_Handshake) { uint32_t st_step = sn_state.val.case_IMS_Handshake.step; if (st_step >= (uint32_t)4U) { out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Stuck, .val = { .case_Stuck = Noise_XK_CIncorrect_transition } } ); } else { Noise_XK_encap_message_t encap_payload = payload[0U]; option__uint32_t scrut; if ((uint32_t)0U == st_step) if (encap_payload.em_message_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = encap_payload.em_message_len + (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)1U == st_step) if (encap_payload.em_message_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = encap_payload.em_message_len + (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)2U == st_step) if (encap_payload.em_message_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = encap_payload.em_message_len + (uint32_t)64U }); else scrut = ((option__uint32_t){ .tag = None }); else scrut = ((option__uint32_t){ .tag = None }); bool next_length_ok; if (scrut.tag == Some) { uint32_t l = scrut.v; out_len[0U] = l; next_length_ok = true; } else next_length_ok = false; if (next_length_ok) { bool sec_ok; if (encap_payload.em_message_len == (uint32_t)0U) sec_ok = true; else { uint8_t clevel; if (st_step == (uint32_t)0U) clevel = (uint8_t)2U; else if (st_step == (uint32_t)1U) clevel = (uint8_t)1U; else clevel = (uint8_t)5U; if (encap_payload.em_ac_level.tag == Noise_XK_Conf_level) { uint8_t req_level = encap_payload.em_ac_level.val.case_Conf_level; sec_ok = (req_level >= (uint8_t)2U && clevel >= req_level) || (req_level == (uint8_t)1U && (clevel == req_level || clevel >= (uint8_t)3U)) || req_level == (uint8_t)0U; } else sec_ok = false; } if (sec_ok) { uint32_t outlen = out_len[0U]; KRML_CHECK_SIZE(sizeof (uint8_t), outlen); uint8_t *out1 = KRML_HOST_CALLOC(outlen, sizeof (uint8_t)); Noise_XK_error_code res = state_handshake_write(encap_payload.em_message_len, encap_payload.em_message, sn_p1, outlen, out1); if (res == Noise_XK_CSuccess) { out[0U] = out1; return ((Noise_XK_rcode){ .tag = Noise_XK_Success }); } else { Noise_XK_error_code e = res; KRML_HOST_FREE(out1); out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Stuck, .val = { .case_Stuck = e } }); } } else { out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CSecurity_level } } ); } } else { out_len[0U] = (uint32_t)0U; out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CInput_size } } ); } } } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } /* Read a message with the current session. If successful, this function will allocate a an encapsulated message in `*payload_out`. Note that using `payload_out` is always safe: if the function fails, it will set `*payload_out` to NULL. */ Noise_XK_rcode Noise_XK_session_read( Noise_XK_encap_message_t **payload_out, Noise_XK_session_t *sn_p, uint32_t inlen, uint8_t *input ) { Noise_XK_session_t *sn_p1 = sn_p; Noise_XK_session_t *snp = sn_p1; Noise_XK_session_t sn = snp[0U]; if (sn.tag == Noise_XK_DS_Initiator) { Noise_XK_init_state_t sn_state = sn.val.case_DS_Initiator.state; if (sn_state.tag == Noise_XK_IMS_Transport) { option__uint32_t scrut; if (inlen >= (uint32_t)16U) scrut = ((option__uint32_t){ .tag = Some, .v = inlen - (uint32_t)16U }); else scrut = ((option__uint32_t){ .tag = None }); if (scrut.tag == Some) { uint32_t outlen = scrut.v; uint8_t *out; if (outlen > (uint32_t)0U) { KRML_CHECK_SIZE(sizeof (uint8_t), outlen); uint8_t *buf = KRML_HOST_CALLOC(outlen, sizeof (uint8_t)); out = buf; } else out = NULL; Noise_XK_error_code res = state_transport_read(outlen, out, inlen, input, sn_p1); if (res == Noise_XK_CSuccess) { KRML_CHECK_SIZE(sizeof (Noise_XK_encap_message_t), (uint32_t)1U); Noise_XK_encap_message_t *em_ptr = KRML_HOST_MALLOC(sizeof (Noise_XK_encap_message_t)); em_ptr[0U] = ( (Noise_XK_encap_message_t){ .em_ac_level = { .tag = Noise_XK_Auth_level, .val = { .case_Auth_level = (uint8_t)2U } }, .em_message_len = outlen, .em_message = out } ); Noise_XK_encap_message_t *emp = em_ptr; payload_out[0U] = emp; return ((Noise_XK_rcode){ .tag = Noise_XK_Success }); } else { Noise_XK_error_code e = res; if (!(out == NULL)) KRML_HOST_FREE(out); payload_out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = e } }); } } else { payload_out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CInput_size } }); } } else if (sn_state.tag == Noise_XK_IMS_Handshake) { uint32_t st_step = sn_state.val.case_IMS_Handshake.step; if (st_step >= (uint32_t)4U) { payload_out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Stuck, .val = { .case_Stuck = Noise_XK_CIncorrect_transition } } ); } else if (st_step % (uint32_t)2U == (uint32_t)1U && st_step < (uint32_t)3U) { option__uint32_t scrut; if ((uint32_t)0U == st_step) if (inlen >= (uint32_t)48U) scrut = ((option__uint32_t){ .tag = Some, .v = inlen - (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)1U == st_step) if (inlen >= (uint32_t)48U) scrut = ((option__uint32_t){ .tag = Some, .v = inlen - (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)2U == st_step) if (inlen >= (uint32_t)64U) scrut = ((option__uint32_t){ .tag = Some, .v = inlen - (uint32_t)64U }); else scrut = ((option__uint32_t){ .tag = None }); else scrut = ((option__uint32_t){ .tag = None }); if (scrut.tag == Some) { uint32_t outlen = scrut.v; uint8_t alevel; if (st_step == (uint32_t)0U) alevel = (uint8_t)0U; else if (st_step == (uint32_t)1U) alevel = (uint8_t)2U; else alevel = (uint8_t)2U; uint8_t *out; if (outlen > (uint32_t)0U) { KRML_CHECK_SIZE(sizeof (uint8_t), outlen); uint8_t *buf = KRML_HOST_CALLOC(outlen, sizeof (uint8_t)); out = buf; } else out = NULL; Noise_XK_error_code res = state_handshake_read(outlen, out, sn_p1, inlen, input); if (res == Noise_XK_CSuccess) { KRML_CHECK_SIZE(sizeof (Noise_XK_encap_message_t), (uint32_t)1U); Noise_XK_encap_message_t *em_ptr = KRML_HOST_MALLOC(sizeof (Noise_XK_encap_message_t)); em_ptr[0U] = ( (Noise_XK_encap_message_t){ .em_ac_level = { .tag = Noise_XK_Auth_level, .val = { .case_Auth_level = alevel } }, .em_message_len = outlen, .em_message = out } ); Noise_XK_encap_message_t *emp = em_ptr; payload_out[0U] = emp; return ((Noise_XK_rcode){ .tag = Noise_XK_Success }); } else { Noise_XK_error_code e = res; if (!(out == NULL)) KRML_HOST_FREE(out); payload_out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Stuck, .val = { .case_Stuck = e } }); } } else { payload_out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CInput_size } } ); } } else { payload_out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CIncorrect_transition } } ); } } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } else if (sn.tag == Noise_XK_DS_Responder) { Noise_XK_resp_state_t sn_state = sn.val.case_DS_Responder.state; if (sn_state.tag == Noise_XK_IMS_Transport) { option__uint32_t scrut; if (inlen >= (uint32_t)16U) scrut = ((option__uint32_t){ .tag = Some, .v = inlen - (uint32_t)16U }); else scrut = ((option__uint32_t){ .tag = None }); if (scrut.tag == Some) { uint32_t outlen = scrut.v; uint8_t *out; if (outlen > (uint32_t)0U) { KRML_CHECK_SIZE(sizeof (uint8_t), outlen); uint8_t *buf = KRML_HOST_CALLOC(outlen, sizeof (uint8_t)); out = buf; } else out = NULL; Noise_XK_error_code res = state_transport_read(outlen, out, inlen, input, sn_p1); if (res == Noise_XK_CSuccess) { KRML_CHECK_SIZE(sizeof (Noise_XK_encap_message_t), (uint32_t)1U); Noise_XK_encap_message_t *em_ptr = KRML_HOST_MALLOC(sizeof (Noise_XK_encap_message_t)); em_ptr[0U] = ( (Noise_XK_encap_message_t){ .em_ac_level = { .tag = Noise_XK_Auth_level, .val = { .case_Auth_level = (uint8_t)2U } }, .em_message_len = outlen, .em_message = out } ); Noise_XK_encap_message_t *emp = em_ptr; payload_out[0U] = emp; return ((Noise_XK_rcode){ .tag = Noise_XK_Success }); } else { Noise_XK_error_code e = res; if (!(out == NULL)) KRML_HOST_FREE(out); payload_out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = e } }); } } else { payload_out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CInput_size } }); } } else if (sn_state.tag == Noise_XK_IMS_Handshake) { uint32_t st_step = sn_state.val.case_IMS_Handshake.step; if (st_step >= (uint32_t)4U) { payload_out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Stuck, .val = { .case_Stuck = Noise_XK_CIncorrect_transition } } ); } else if (st_step % (uint32_t)2U == (uint32_t)0U && st_step < (uint32_t)3U) { option__uint32_t scrut; if ((uint32_t)0U == st_step) if (inlen >= (uint32_t)48U) scrut = ((option__uint32_t){ .tag = Some, .v = inlen - (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)1U == st_step) if (inlen >= (uint32_t)48U) scrut = ((option__uint32_t){ .tag = Some, .v = inlen - (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)2U == st_step) if (inlen >= (uint32_t)64U) scrut = ((option__uint32_t){ .tag = Some, .v = inlen - (uint32_t)64U }); else scrut = ((option__uint32_t){ .tag = None }); else scrut = ((option__uint32_t){ .tag = None }); if (scrut.tag == Some) { uint32_t outlen = scrut.v; uint8_t alevel; if (st_step == (uint32_t)0U) alevel = (uint8_t)0U; else if (st_step == (uint32_t)1U) alevel = (uint8_t)2U; else alevel = (uint8_t)2U; uint8_t *out; if (outlen > (uint32_t)0U) { KRML_CHECK_SIZE(sizeof (uint8_t), outlen); uint8_t *buf = KRML_HOST_CALLOC(outlen, sizeof (uint8_t)); out = buf; } else out = NULL; Noise_XK_error_code res = state_handshake_read(outlen, out, sn_p1, inlen, input); if (res == Noise_XK_CSuccess) { KRML_CHECK_SIZE(sizeof (Noise_XK_encap_message_t), (uint32_t)1U); Noise_XK_encap_message_t *em_ptr = KRML_HOST_MALLOC(sizeof (Noise_XK_encap_message_t)); em_ptr[0U] = ( (Noise_XK_encap_message_t){ .em_ac_level = { .tag = Noise_XK_Auth_level, .val = { .case_Auth_level = alevel } }, .em_message_len = outlen, .em_message = out } ); Noise_XK_encap_message_t *emp = em_ptr; payload_out[0U] = emp; return ((Noise_XK_rcode){ .tag = Noise_XK_Success }); } else { Noise_XK_error_code e = res; if (!(out == NULL)) KRML_HOST_FREE(out); payload_out[0U] = NULL; return ((Noise_XK_rcode){ .tag = Noise_XK_Stuck, .val = { .case_Stuck = e } }); } } else { payload_out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CInput_size } } ); } } else { payload_out[0U] = NULL; return ( (Noise_XK_rcode){ .tag = Noise_XK_Error, .val = { .case_Error = Noise_XK_CIncorrect_transition } } ); } } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } /* Compute the length of the next message, given a payload length. Note that the function may fail, if the length of the message is too long for example (though very unlikely). You thus need to check the returned value. Also note that the length of the next message is always equal to: payload length + a value depending only on the current step. */ bool Noise_XK_session_compute_next_message_len( uint32_t *out, Noise_XK_session_t *sn, uint32_t payload_len ) { Noise_XK_session_t dst = sn[0U]; if (dst.tag == Noise_XK_DS_Initiator) { Noise_XK_init_state_t st = dst.val.case_DS_Initiator.state; if (st.tag == Noise_XK_IMS_Handshake) { uint32_t step = st.val.case_IMS_Handshake.step; option__uint32_t scrut; if ((uint32_t)0U == step) if (payload_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = payload_len + (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)1U == step) if (payload_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = payload_len + (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)2U == step) if (payload_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = payload_len + (uint32_t)64U }); else scrut = ((option__uint32_t){ .tag = None }); else scrut = ((option__uint32_t){ .tag = None }); if (scrut.tag == Some) { uint32_t l = scrut.v; out[0U] = l; return true; } else return false; } else if (st.tag == Noise_XK_IMS_Transport) if (payload_len <= (uint32_t)4294967279U) { out[0U] = payload_len + (uint32_t)16U; return true; } else return false; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } else if (dst.tag == Noise_XK_DS_Responder) { Noise_XK_resp_state_t st = dst.val.case_DS_Responder.state; if (st.tag == Noise_XK_IMS_Handshake) { uint32_t step = st.val.case_IMS_Handshake.step; option__uint32_t scrut; if ((uint32_t)0U == step) if (payload_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = payload_len + (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)1U == step) if (payload_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = payload_len + (uint32_t)48U }); else scrut = ((option__uint32_t){ .tag = None }); else if ((uint32_t)2U == step) if (payload_len <= (uint32_t)4294967215U) scrut = ((option__uint32_t){ .tag = Some, .v = payload_len + (uint32_t)64U }); else scrut = ((option__uint32_t){ .tag = None }); else scrut = ((option__uint32_t){ .tag = None }); if (scrut.tag == Some) { uint32_t l = scrut.v; out[0U] = l; return true; } else return false; } else if (st.tag == Noise_XK_IMS_Transport) if (payload_len <= (uint32_t)4294967279U) { out[0U] = payload_len + (uint32_t)16U; return true; } else return false; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } /* Return the current status. */ Noise_XK_status Noise_XK_session_get_status(Noise_XK_session_t *sn) { Noise_XK_session_t dst = sn[0U]; if (dst.tag == Noise_XK_DS_Initiator) { Noise_XK_init_state_t st = dst.val.case_DS_Initiator.state; if (st.tag == Noise_XK_IMS_Handshake) { uint32_t step = st.val.case_IMS_Handshake.step; if (step % (uint32_t)2U == (uint32_t)0U) return Noise_XK_Handshake_write; else return Noise_XK_Handshake_read; } else if (st.tag == Noise_XK_IMS_Transport) return Noise_XK_Transport; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } else if (dst.tag == Noise_XK_DS_Responder) { Noise_XK_resp_state_t st = dst.val.case_DS_Responder.state; if (st.tag == Noise_XK_IMS_Handshake) { uint32_t step = st.val.case_IMS_Handshake.step; if (step % (uint32_t)2U == (uint32_t)0U) return Noise_XK_Handshake_read; else return Noise_XK_Handshake_write; } else if (st.tag == Noise_XK_IMS_Transport) return Noise_XK_Transport; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } /* Copy the session hash to the user provided buffer. Note that the session hash is always public. Using the session hash might be pertinent once the session has reached the transport phase. */ void Noise_XK_session_get_hash(uint8_t *out, Noise_XK_session_t *sn) { Noise_XK_session_t dst = sn[0U]; uint8_t *h; if (dst.tag == Noise_XK_DS_Initiator) { Noise_XK_init_state_t st = dst.val.case_DS_Initiator.state; if (st.tag == Noise_XK_IMS_Handshake) h = st.val.case_IMS_Handshake.h; else if (st.tag == Noise_XK_IMS_Transport) h = st.val.case_IMS_Transport.h; else h = KRML_EABORT(uint8_t *, "unreachable (pattern matches are exhaustive in F*)"); } else if (dst.tag == Noise_XK_DS_Responder) { Noise_XK_resp_state_t st = dst.val.case_DS_Responder.state; if (st.tag == Noise_XK_IMS_Handshake) h = st.val.case_IMS_Handshake.h; else if (st.tag == Noise_XK_IMS_Transport) h = st.val.case_IMS_Transport.h; else h = KRML_EABORT(uint8_t *, "unreachable (pattern matches are exhaustive in F*)"); } else h = KRML_EABORT(uint8_t *, "unreachable (pattern matches are exhaustive in F*)"); memcpy(out, h, (uint32_t)64U * sizeof (uint8_t)); } /* Return the session unique identifier. */ uint32_t Noise_XK_session_get_id(Noise_XK_session_t *sn) { Noise_XK_session_t st = sn[0U]; if (st.tag == Noise_XK_DS_Initiator) return st.val.case_DS_Initiator.id; else if (st.tag == Noise_XK_DS_Responder) return st.val.case_DS_Responder.id; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } /* Copy the session information to the user provided pointer. */ void Noise_XK_session_get_info(Noise_XK_noise_string *out, Noise_XK_session_t *sn) { Noise_XK_session_t st = sn[0U]; if (st.tag == Noise_XK_DS_Initiator) { Noise_XK_noise_string *info = st.val.case_DS_Initiator.info; uint8_t *input_str = info[0U]; bool b = input_str == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = input_str[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = input_str[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = input_str[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } out[0U] = out_str; } else if (st.tag == Noise_XK_DS_Responder) { Noise_XK_noise_string *info = st.val.case_DS_Responder.info; uint8_t *input_str = info[0U]; bool b = input_str == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = input_str[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = input_str[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = input_str[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } out[0U] = out_str; } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } /* Return the session's peer unique identifier. The remote may be unknown, in which case the returned id will be 0. Note that you can safely use the returned peer id without testing it, because all the functions taking peer ids as parameters were written to correctly manipulate 0. In particular, looking up id 0 will return NULL, and trying to create a session with peer id 0 will cleanly fail by also returning NULL. */ uint32_t Noise_XK_session_get_peer_id(Noise_XK_session_t *sn) { Noise_XK_session_t st = sn[0U]; if (st.tag == Noise_XK_DS_Initiator) return st.val.case_DS_Initiator.pid; else if (st.tag == Noise_XK_DS_Responder) return st.val.case_DS_Responder.pid; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } /* Copy the session peer information, if known, to the user provided pointer. The remote may be unknown yet, in which case there is no peer information in the device and the function will return false. */ bool Noise_XK_session_get_peer_info(Noise_XK_noise_string *out, Noise_XK_session_t *sn) { Noise_XK_session_t st = sn[0U]; if (st.tag == Noise_XK_DS_Initiator) { Noise_XK_noise_string *pinfo = st.val.case_DS_Initiator.pinfo; uint32_t pid = st.val.case_DS_Initiator.pid; if (pid != (uint32_t)0U) { uint8_t *input_str = pinfo[0U]; bool b = input_str == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = input_str[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = input_str[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = input_str[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } out[0U] = out_str; return true; } else return false; } else if (st.tag == Noise_XK_DS_Responder) { Noise_XK_noise_string *pinfo = st.val.case_DS_Responder.pinfo; uint32_t pid = st.val.case_DS_Responder.pid; if (pid != (uint32_t)0U) { uint8_t *input_str = pinfo[0U]; bool b = input_str == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = input_str[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = input_str[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = input_str[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = input_str[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } out[0U] = out_str; return true; } else return false; } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } /* Return true if this session has reached the maximum security level for this pattern. Once the maximum security level is reached, it is not possible to have better confidentiality/authentication guarantees for the payloads sent/received with this session. Note that the guarantees provided by the maximum reachable level vary with the pattern, which must thus be carefully chosen. In order to reach the maximum level, the session must have finished the handshake. Moreover, in case the session sends the last handshake message, it must wait for the first transport message from the remote: otherwise, we have no way to know whether the remote was itself able to finish the handshake. */ bool Noise_XK_session_reached_max_security(Noise_XK_session_t *snp) { Noise_XK_session_t sn = snp[0U]; if (sn.tag == Noise_XK_DS_Initiator) { Noise_XK_init_state_t sn_state = sn.val.case_DS_Initiator.state; if (sn_state.tag == Noise_XK_IMS_Transport) return sn_state.val.case_IMS_Transport.recv_transport_message; else if (sn_state.tag == Noise_XK_IMS_Handshake) return false; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } else if (sn.tag == Noise_XK_DS_Responder) { Noise_XK_resp_state_t sn_state = sn.val.case_DS_Responder.state; if (sn_state.tag == Noise_XK_IMS_Transport) return true; else if (sn_state.tag == Noise_XK_IMS_Handshake) return false; else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } /* DO NOT use this: for tests and benchmarks only */ Noise_XK_session_t *Noise_XK__session_create_initiator_with_ephemeral( Noise_XK_device_t *dvp, uint8_t *epriv, uint8_t *epub, uint32_t pid ) { Noise_XK_device_t dv = dvp[0U]; result_session_t res0; if (dv.dv_states_counter == (uint32_t)4294967295U) res0 = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } }); else { Noise_XK_device_t dv1 = dvp[0U]; Noise_XK_peer_t *peer_ptr; if (pid == (uint32_t)0U) peer_ptr = NULL; else { Noise_XK_cell *llt = *dv1.dv_peers; Noise_XK_cell *lltp = llt; Noise_XK_cell *llt10 = lltp; bool b0; if (llt10 == NULL) b0 = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b = x.p_id == pid; b0 = !b; } bool cond = b0; while (cond) { Noise_XK_cell *llt1 = lltp; Noise_XK_cell c0 = llt1[0U]; lltp = c0.next; Noise_XK_cell *llt10 = lltp; bool b; if (llt10 == NULL) b = false; else { Noise_XK_cell c = llt10[0U]; Noise_XK_peer_t x = c.data[0U]; bool b0 = x.p_id == pid; b = !b0; } cond = b; } Noise_XK_cell *llt1 = *&lltp; Noise_XK_peer_t *res; if (llt1 == NULL) res = NULL; else { Noise_XK_cell c = *llt1; res = c.data; } peer_ptr = res; } bool p_is_null = peer_ptr == NULL; if (p_is_null) res0 = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CUnknown_peer_id } }); else { uint8_t *o0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(o0, dv.dv_spriv, (uint32_t)32U * sizeof (uint8_t)); uint8_t *st_spriv = o0; uint8_t *o = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(o, dv.dv_spub, (uint32_t)32U * sizeof (uint8_t)); uint8_t *st_spub = o; uint8_t *str0 = dv.dv_info[0U]; bool b0 = str0 == NULL; uint8_t *out_str0; if (b0) out_str0 = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = str0[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = str0[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str0 = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = str0[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = str0[n]; out_str[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = str0[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str[n] = (uint8_t)0U; uint8_t *out_str1 = out_str; out_str0 = out_str1; } } KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr[0U] = out_str0; Noise_XK_noise_string *st_info = out_ptr; Noise_XK_peer_t peer = peer_ptr[0U]; uint8_t *str = peer.p_info[0U]; bool b = str == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = str[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = str[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = str[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = str[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = str[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr0 = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr0[0U] = out_str; Noise_XK_noise_string *st_pinfo = out_ptr0; uint8_t *rs = peer.p_s; dvp[0U] = ( (Noise_XK_device_t){ .dv_info = dv.dv_info, .dv_sk = dv.dv_sk, .dv_spriv = dv.dv_spriv, .dv_spub = dv.dv_spub, .dv_prologue = dv.dv_prologue, .dv_states_counter = dv.dv_states_counter + (uint32_t)1U, .dv_peers = dv.dv_peers, .dv_peers_counter = dv.dv_peers_counter } ); uint8_t *st_k = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_ck0 = KRML_HOST_CALLOC((uint32_t)64U, sizeof (uint8_t)); uint8_t *st_h0 = KRML_HOST_CALLOC((uint32_t)64U, sizeof (uint8_t)); uint8_t *st_spriv1 = st_spriv; uint8_t *st_spub1 = st_spub; uint8_t *st_epriv0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_epub0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_rs0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_re = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); Noise_XK_init_state_t st = { .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = (uint32_t)0U, .cipher_key = st_k, .chaining_key = st_ck0, .h = st_h0, .spriv = st_spriv1, .spub = st_spub1, .epriv = st_epriv0, .epub = st_epub0, .rs = st_rs0, .re = st_re } } }; uint8_t pname[33U] = { (uint8_t)78U, (uint8_t)111U, (uint8_t)105U, (uint8_t)115U, (uint8_t)101U, (uint8_t)95U, (uint8_t)88U, (uint8_t)75U, (uint8_t)95U, (uint8_t)50U, (uint8_t)53U, (uint8_t)53U, (uint8_t)49U, (uint8_t)57U, (uint8_t)95U, (uint8_t)67U, (uint8_t)104U, (uint8_t)97U, (uint8_t)67U, (uint8_t)104U, (uint8_t)97U, (uint8_t)80U, (uint8_t)111U, (uint8_t)108U, (uint8_t)121U, (uint8_t)95U, (uint8_t)66U, (uint8_t)76U, (uint8_t)65U, (uint8_t)75U, (uint8_t)69U, (uint8_t)50U, (uint8_t)98U }; if (st.tag == Noise_XK_IMS_Handshake) { uint8_t *st_rs = st.val.case_IMS_Handshake.rs; uint8_t *st_epub = st.val.case_IMS_Handshake.epub; uint8_t *st_epriv = st.val.case_IMS_Handshake.epriv; uint8_t *st_h = st.val.case_IMS_Handshake.h; uint8_t *st_ck = st.val.case_IMS_Handshake.chaining_key; if ((uint32_t)33U <= (uint32_t)64U) memcpy(st_h, pname, (uint32_t)33U * sizeof (uint8_t)); else Noise_XK_hash(st_h, (uint32_t)33U, pname); memcpy(st_ck, st_h, (uint32_t)64U * sizeof (uint8_t)); Noise_XK_mix_hash(st_h, dv.dv_prologue.size, dv.dv_prologue.buffer); memcpy(st_epriv, epriv, (uint32_t)32U * sizeof (uint8_t)); memcpy(st_epub, epub, (uint32_t)32U * sizeof (uint8_t)); memcpy(st_rs, rs, (uint32_t)32U * sizeof (uint8_t)); Noise_XK_mix_hash(st_h, (uint32_t)32U, rs); } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } Noise_XK_init_state_t st0 = st; result_session_t res = { .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Initiator, .val = { .case_DS_Initiator = { .state = st0, .id = dv.dv_states_counter, .info = st_info, .spriv = st_spriv, .spub = st_spub, .pid = pid, .pinfo = st_pinfo, .dv = dvp } } } } }; res0 = res; } } if (res0.tag == Fail) return NULL; else if (res0.tag == Res) { Noise_XK_session_t st = res0.val.case_Res; KRML_CHECK_SIZE(sizeof (Noise_XK_session_t), (uint32_t)1U); Noise_XK_session_t *ptr = KRML_HOST_MALLOC(sizeof (Noise_XK_session_t)); ptr[0U] = st; return ptr; } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } /* DO NOT use this: for tests and benchmarks only */ Noise_XK_session_t *Noise_XK__session_create_responder_with_ephemeral( Noise_XK_device_t *dvp, uint8_t *epriv, uint8_t *epub ) { Noise_XK_device_t dv = dvp[0U]; result_session_t res; if (dv.dv_states_counter == (uint32_t)4294967295U) res = ((result_session_t){ .tag = Fail, .val = { .case_Fail = Noise_XK_CIncorrect_transition } }); else { uint8_t *o0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(o0, dv.dv_spriv, (uint32_t)32U * sizeof (uint8_t)); uint8_t *st_spriv = o0; uint8_t *o = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); memcpy(o, dv.dv_spub, (uint32_t)32U * sizeof (uint8_t)); uint8_t *st_spub = o; uint8_t *str = dv.dv_info[0U]; bool b = str == NULL; uint8_t *out_str; if (b) out_str = NULL; else { uint32_t ip = (uint32_t)0U; uint32_t i0 = ip; uint8_t c0 = str[i0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t i = ip; ip = i + (uint32_t)1U; uint32_t i0 = ip; uint8_t c = str[i0]; cond = c != (uint8_t)0U; } uint32_t len = ip; if (len == (uint32_t)0U) out_str = NULL; else { KRML_CHECK_SIZE(sizeof (uint8_t), len + (uint32_t)1U); uint8_t *out_str0 = KRML_HOST_CALLOC(len + (uint32_t)1U, sizeof (uint8_t)); uint32_t np = (uint32_t)0U; uint32_t n0 = np; uint8_t c0 = str[n0]; bool cond = c0 != (uint8_t)0U; while (cond) { uint32_t n = np; uint8_t c = str[n]; out_str0[n] = c; np = n + (uint32_t)1U; uint32_t n0 = np; uint8_t c0 = str[n0]; cond = c0 != (uint8_t)0U; } uint32_t n = np; out_str0[n] = (uint8_t)0U; uint8_t *out_str1 = out_str0; out_str = out_str1; } } KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr0 = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr0[0U] = out_str; Noise_XK_noise_string *st_info = out_ptr0; KRML_CHECK_SIZE(sizeof (uint8_t *), (uint32_t)1U); uint8_t **out_ptr = KRML_HOST_MALLOC(sizeof (uint8_t *)); out_ptr[0U] = NULL; Noise_XK_noise_string *st_pinfo = out_ptr; dvp[0U] = ( (Noise_XK_device_t){ .dv_info = dv.dv_info, .dv_sk = dv.dv_sk, .dv_spriv = dv.dv_spriv, .dv_spub = dv.dv_spub, .dv_prologue = dv.dv_prologue, .dv_states_counter = dv.dv_states_counter + (uint32_t)1U, .dv_peers = dv.dv_peers, .dv_peers_counter = dv.dv_peers_counter } ); uint8_t *st_k = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_ck0 = KRML_HOST_CALLOC((uint32_t)64U, sizeof (uint8_t)); uint8_t *st_h0 = KRML_HOST_CALLOC((uint32_t)64U, sizeof (uint8_t)); uint8_t *st_spriv1 = st_spriv; uint8_t *st_spub10 = st_spub; uint8_t *st_epriv0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_epub0 = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_rs = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); uint8_t *st_re = KRML_HOST_CALLOC((uint32_t)32U, sizeof (uint8_t)); Noise_XK_resp_state_t st = { .tag = Noise_XK_IMS_Handshake, .val = { .case_IMS_Handshake = { .step = (uint32_t)0U, .cipher_key = st_k, .chaining_key = st_ck0, .h = st_h0, .spriv = st_spriv1, .spub = st_spub10, .epriv = st_epriv0, .epub = st_epub0, .rs = st_rs, .re = st_re } } }; uint8_t pname[33U] = { (uint8_t)78U, (uint8_t)111U, (uint8_t)105U, (uint8_t)115U, (uint8_t)101U, (uint8_t)95U, (uint8_t)88U, (uint8_t)75U, (uint8_t)95U, (uint8_t)50U, (uint8_t)53U, (uint8_t)53U, (uint8_t)49U, (uint8_t)57U, (uint8_t)95U, (uint8_t)67U, (uint8_t)104U, (uint8_t)97U, (uint8_t)67U, (uint8_t)104U, (uint8_t)97U, (uint8_t)80U, (uint8_t)111U, (uint8_t)108U, (uint8_t)121U, (uint8_t)95U, (uint8_t)66U, (uint8_t)76U, (uint8_t)65U, (uint8_t)75U, (uint8_t)69U, (uint8_t)50U, (uint8_t)98U }; if (st.tag == Noise_XK_IMS_Handshake) { uint8_t *st_epub = st.val.case_IMS_Handshake.epub; uint8_t *st_epriv = st.val.case_IMS_Handshake.epriv; uint8_t *st_spub1 = st.val.case_IMS_Handshake.spub; uint8_t *st_h = st.val.case_IMS_Handshake.h; uint8_t *st_ck = st.val.case_IMS_Handshake.chaining_key; if ((uint32_t)33U <= (uint32_t)64U) memcpy(st_h, pname, (uint32_t)33U * sizeof (uint8_t)); else Noise_XK_hash(st_h, (uint32_t)33U, pname); memcpy(st_ck, st_h, (uint32_t)64U * sizeof (uint8_t)); Noise_XK_mix_hash(st_h, dv.dv_prologue.size, dv.dv_prologue.buffer); memcpy(st_epriv, epriv, (uint32_t)32U * sizeof (uint8_t)); memcpy(st_epub, epub, (uint32_t)32U * sizeof (uint8_t)); Noise_XK_mix_hash(st_h, (uint32_t)32U, st_spub1); } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } Noise_XK_resp_state_t st0 = st; result_session_t res0 = { .tag = Res, .val = { .case_Res = { .tag = Noise_XK_DS_Responder, .val = { .case_DS_Responder = { .state = st0, .id = dv.dv_states_counter, .info = st_info, .spriv = st_spriv, .spub = st_spub, .pid = (uint32_t)0U, .pinfo = st_pinfo, .dv = dvp } } } } }; res = res0; } if (res.tag == Fail) return NULL; else if (res.tag == Res) { Noise_XK_session_t st = res.val.case_Res; KRML_CHECK_SIZE(sizeof (Noise_XK_session_t), (uint32_t)1U); Noise_XK_session_t *ptr = KRML_HOST_MALLOC(sizeof (Noise_XK_session_t)); ptr[0U] = st; return ptr; } else { KRML_HOST_EPRINTF("KaRaMeL abort at %s:%d\n%s\n", __FILE__, __LINE__, "unreachable (pattern matches are exhaustive in F*)"); KRML_HOST_EXIT(255U); } } liboprf-0.6.1/src/oprf.c000066400000000000000000000343311474121727000150650ustar00rootroot00000000000000/* @copyright 2022, Stefan Marsiske toprf@ctrlc.hu This file is part of liboprf. liboprf is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liboprf is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the License along with liboprf. If not, see . */ #include #include #include #include #include "oprf.h" #include "utils.h" #include "toprf.h" #ifdef CFRG_TEST_VEC #ifdef CFRG_OPRF_TEST_VEC #include "tests/cfrg_oprf_test_vector_decl.h" #else #include "tests/cfrg_test_vector_decl.h" #endif #endif #define VOPRF "OPRFV1" /** * This function generates an OPRF private key. * * This is almost the KeyGen OPRF function defined in the RFC: since * this lib does not implement V oprf, we don't need a pubkey and so * we don't bother with all that is related. * * @param [out] kU - the per-user OPRF private key */ void oprf_KeyGen(uint8_t kU[crypto_core_ristretto255_SCALARBYTES]) { #if (defined CFRG_TEST_VEC && defined oprf_key_len) memcpy(kU,oprf_key,oprf_key_len); #else crypto_core_ristretto255_scalar_random(kU); #endif } /** * This function computes the OPRF output using input x, N, and domain separation * tag info. * * This is the Finalize OPRF function defined in the RFC. * * @param [in] x - a value used to compute OPRF (the same value that * was used as input to be blinded) * @param [in] x_len - the length of param x in bytes * @param [in] N - a serialized OPRF group element, a byte array of fixed length, * an output of oprf_Unblind * @param [in] info - a domain separation tag * @param [in] info_len - the length of param info in bytes * @param [out] y - an OPRF output * @return The function returns 0 if everything is correct. */ int oprf_Finalize(const uint8_t *x, const uint16_t x_len, const uint8_t N[crypto_core_ristretto255_BYTES], uint8_t rwdU[OPRF_BYTES]) { // according to paper: hash(pwd||H0^k) // acccording to voprf IRTF CFRG specification: hash(htons(len(pwd))||pwd|| // htons(len(H0_k))||H0_k||| // htons(len("Finalize-"VOPRF"-\x00-ristretto255-SHA512"))||"Finalize-"VOPRF"-\x00-ristretto255-SHA512") crypto_hash_sha512_state state; if(-1==sodium_mlock(&state,sizeof state)) { return -1; } crypto_hash_sha512_init(&state); // pwd uint16_t size=htons(x_len); crypto_hash_sha512_update(&state, (uint8_t*) &size, 2); crypto_hash_sha512_update(&state, x, x_len); #if (defined TRACE || defined CFRG_TEST_VEC) dump(x,x_len,"finalize input"); #endif // H0_k size=htons(crypto_core_ristretto255_BYTES); crypto_hash_sha512_update(&state, (uint8_t*) &size, 2); crypto_hash_sha512_update(&state, N, crypto_core_ristretto255_BYTES); //const uint8_t DST[]="Finalize-"VOPRF"-\x00\x00\x01"; const uint8_t DST[]="Finalize"; const uint8_t DST_size=sizeof DST -1; //size=htons(DST_size); //crypto_hash_sha512_update(&state, (uint8_t*) &size, 2); crypto_hash_sha512_update(&state, DST, DST_size); crypto_hash_sha512_final(&state, rwdU); sodium_munlock(&state, sizeof state); return 0; } /* expand_loop 10. b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) */ static void expand_loop(const uint8_t *b_0, const uint8_t *b_i, const uint8_t i, const uint8_t *dst_prime, const uint8_t dst_prime_len, uint8_t *b_ii) { uint8_t xored[crypto_hash_sha512_BYTES]; unsigned j; for(j=0;j 255 * 3. DST_prime = DST || I2OSP(len(DST), 1) * 4. Z_pad = I2OSP(0, r_in_bytes) * 5. l_i_b_str = I2OSP(len_in_bytes, 2) * 6. msg_prime = Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime * 7. b_0 = H(msg_prime) * 8. b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) * 9. for i in (2, ..., ell): * 10. b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) * 11. uniform_bytes = b_1 || ... || b_ell * 12. return substr(uniform_bytes, 0, len_in_bytes) */ int expand_message_xmd(const uint8_t *msg, const uint8_t msg_len, const uint8_t *dst, const uint8_t dst_len, const uint8_t len_in_bytes, uint8_t *uniform_bytes) { // 1. ell = ceil(len_in_bytes / b_in_bytes) const unsigned ell = (len_in_bytes + crypto_hash_sha512_BYTES-1) / crypto_hash_sha512_BYTES; #ifdef TRACE fprintf(stderr, "ell %d\n", ell); dump(msg, msg_len, "msg"); dump(dst, dst_len, "dst"); #endif // 2. ABORT if ell > 255 if(ell>255) return -1; // 3. DST_prime = DST || I2OSP(len(DST), 1) if(dst_len==255) return -1; uint8_t dst_prime[dst_len+1]; memcpy(dst_prime, dst, dst_len); dst_prime[dst_len] = dst_len; #ifdef TRACE dump(dst_prime, sizeof dst_prime, "dst_prime"); #endif // 4. Z_pad = I2OSP(0, r_in_bytes) //const uint8_t r_in_bytes = 128; // for sha512 uint8_t z_pad[128 /*r_in_bytes*/] = {0}; // supress gcc error: variable-sized object may not be initialized #ifdef TRACE dump(z_pad, sizeof z_pad, "z_pad"); #endif // 5. l_i_b_str = I2OSP(len_in_bytes, 2) const uint16_t l_i_b = htons(len_in_bytes); const uint8_t *l_i_b_str = (uint8_t*) &l_i_b; // 6. msg_prime = Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime uint8_t msg_prime[sizeof z_pad + msg_len + sizeof l_i_b + 1 + sizeof dst_prime], *ptr = msg_prime; memcpy(ptr, z_pad, sizeof z_pad); ptr += sizeof z_pad; memcpy(ptr, msg, msg_len); ptr += msg_len; memcpy(ptr, l_i_b_str, sizeof l_i_b); ptr += sizeof l_i_b; *ptr = 0; ptr++; memcpy(ptr, dst_prime, sizeof dst_prime); #ifdef TRACE dump(msg_prime, sizeof msg_prime, "msg_prime"); #endif // 7. b_0 = H(msg_prime) uint8_t b_0[crypto_hash_sha512_BYTES]; crypto_hash_sha512(b_0, msg_prime, sizeof msg_prime); #ifdef TRACE dump(b_0, sizeof b_0, "b_0"); #endif // 8. b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) uint8_t b_i[crypto_hash_sha512_BYTES]; crypto_hash_sha512_state state; crypto_hash_sha512_init(&state); crypto_hash_sha512_update(&state, b_0, sizeof b_0); crypto_hash_sha512_update(&state,(uint8_t*) &"\x01", 1); crypto_hash_sha512_update(&state, dst_prime, (long long unsigned int) sizeof dst_prime); crypto_hash_sha512_final(&state, b_i); #ifdef TRACE dump(b_i, sizeof b_i, "b_1"); #endif // 9. for i in (2, ..., ell): unsigned left = len_in_bytes; uint8_t *out = uniform_bytes; unsigned clen = (left>sizeof b_i)?sizeof b_i:left; memcpy(out, b_i, clen); out+=clen; left-=clen; uint8_t i; uint8_t b_ii[crypto_hash_sha512_BYTES]; for(i=2;i<=ell;i+=2) { // 11. uniform_bytes = b_1 || ... || b_ell // 12. return substr(uniform_bytes, 0, len_in_bytes) // 10. b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) expand_loop(b_0, b_i, i, dst_prime, (uint8_t) (sizeof dst_prime), b_ii); clen = (left>sizeof b_ii)?sizeof b_ii:left; memcpy(out, b_ii, clen); out+=clen; left-=clen; // unrolled next iteration so we don't have to swap b_i and b_ii expand_loop(b_0, b_ii, i+1, dst_prime, (uint8_t) (sizeof dst_prime), b_i); clen = (left>sizeof b_i)?sizeof b_i:left; memcpy(out, b_i, clen); out+=clen; left-=clen; } return 0; } /* hash-to-ristretto255 - as defined by https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/blob/master/draft-irtf-cfrg-hash-to-curve.md#hashing-to-ristretto255-appx-ristretto255 * Steps: * -1. context-string = \x0 + htons(1) // contextString = I2OSP(modeBase(==0), 1) || I2OSP(suite.ID(==1), 2) * 0. dst="HashToGroup-OPRFV1-\x00-ristretto255-SHA512") * 1. uniform_bytes = expand_message(msg, DST, 64) * 2. P = ristretto255_map(uniform_bytes) * 3. return P */ int voprf_hash_to_group(const uint8_t *msg, const uint8_t msg_len, uint8_t p[crypto_core_ristretto255_BYTES]) { const uint8_t dst[] = "HashToGroup-"VOPRF"-\x00-ristretto255-SHA512"; const uint8_t dst_len = (sizeof dst) - 1; uint8_t uniform_bytes[crypto_core_ristretto255_HASHBYTES]={0}; if(0!=sodium_mlock(uniform_bytes,sizeof uniform_bytes)) { return -1; } if(0!=expand_message_xmd(msg, msg_len, dst, dst_len, crypto_core_ristretto255_HASHBYTES, uniform_bytes)) { sodium_munlock(uniform_bytes,sizeof uniform_bytes); return -1; } #if (defined TRACE || defined CFRG_TEST_VEC) dump(uniform_bytes, sizeof uniform_bytes, "uniform_bytes"); #endif crypto_core_ristretto255_from_hash(p, uniform_bytes); sodium_munlock(uniform_bytes,sizeof uniform_bytes); #if (defined TRACE || defined CFRG_TEST_VEC) dump(p, crypto_core_ristretto255_BYTES, "hashed-to-curve"); #endif return 0; } /** * This function converts input x into an element of the OPRF group, randomizes it * by some scalar r, producing blinded, and outputs (r, blinded). * * This is the Blind OPRF function defined in the RFC. * * @param [in] x - the value to blind (for OPAQUE, this is pwdU, the user's * password) * @param [in] x_len - the length of param x in bytes * @param [out] r - an OPRF scalar value used for randomization * @param [out] blinded - a serialized OPRF group element, a byte array of fixed length, * the blinded version of x, an input to oprf_Evaluate * @return The function returns 0 if everything is correct. */ int oprf_Blind(const uint8_t *x, const uint8_t x_len, uint8_t r[crypto_core_ristretto255_SCALARBYTES], uint8_t blinded[crypto_core_ristretto255_BYTES]) { #if (defined TRACE || defined CFRG_TEST_VEC) dump(x, x_len, "input"); #endif uint8_t H0[crypto_core_ristretto255_BYTES]; if(0!=sodium_mlock(H0,sizeof H0)) { return -1; } // sets α := (H^0(pw))^r if(0!=voprf_hash_to_group(x, x_len, H0)) return -1; #if (defined TRACE || defined CFRG_TEST_VEC) dump(H0,sizeof H0, "H0"); #endif // U picks r #ifdef CFRG_TEST_VEC static int vecidx=0; const unsigned char *rtest[2] = {blind_registration, blind_login}; const unsigned int rtest_len = 32; memcpy(r,rtest[vecidx++ % 2],rtest_len); #else crypto_core_ristretto255_scalar_random(r); #endif #ifdef TRACE dump(r, crypto_core_ristretto255_SCALARBYTES, "r"); #endif // H^0(pw)^r if (crypto_scalarmult_ristretto255(blinded, r, H0) != 0) { sodium_munlock(H0,sizeof H0); return -1; } sodium_munlock(H0,sizeof H0); #if (defined TRACE || defined CFRG_TEST_VEC) dump(blinded, crypto_core_ristretto255_BYTES, "blinded"); #endif return 0; } /** * This function evaluates input element blinded using private key k, yielding output * element Z. * * This is the Evaluate OPRF function defined in the RFC. * * @param [in] k - a private key (for OPAQUE, this is kU, the user's OPRF private * key) * @param [in] blinded - a serialized OPRF group element, a byte array of fixed length, * an output of oprf_Blind (for OPAQUE, this is the blinded pwdU, the user's * password) * @param [out] Z - a serialized OPRF group element, a byte array of fixed length, * an input to oprf_Unblind * @return The function returns 0 if everything is correct. */ int oprf_Evaluate(const uint8_t k[crypto_core_ristretto255_SCALARBYTES], const uint8_t blinded[crypto_core_ristretto255_BYTES], uint8_t Z[crypto_core_ristretto255_BYTES]) { return crypto_scalarmult_ristretto255(Z, k, blinded); } /** * This function removes random scalar r from Z, yielding output N. * * This is the Unblind OPRF function defined in the RFC. * * @param [in] r - an OPRF scalar value used for randomization in oprf_Blind * @param [in] Z - a serialized OPRF group element, a byte array of fixed length, * an output of oprf_Evaluate * @param [out] N - a serialized OPRF group element with random scalar r removed, * a byte array of fixed length, an input to oprf_Finalize * @return The function returns 0 if everything is correct. */ int oprf_Unblind(const uint8_t r[crypto_core_ristretto255_SCALARBYTES], const uint8_t Z[crypto_core_ristretto255_BYTES], uint8_t N[crypto_core_ristretto255_BYTES]) { #ifdef TRACE dump((uint8_t*) r, crypto_core_ristretto255_SCALARBYTES, "r "); dump((uint8_t*) Z, crypto_core_ristretto255_BYTES, "Z "); #endif // (a) Checks that β ∈ G ∗ . If not, outputs (abort, sid , ssid ) and halts; if(crypto_core_ristretto255_is_valid_point(Z) != 1) return -1; // (b) Computes rw := H(pw, β^1/r ); // invert r = 1/r uint8_t ir[crypto_core_ristretto255_SCALARBYTES]; if(-1==sodium_mlock(ir, sizeof ir)) return -1; if (crypto_core_ristretto255_scalar_invert(ir, r) != 0) { sodium_munlock(ir, sizeof ir); return -1; } #ifdef TRACE dump((uint8_t*) ir, sizeof ir, "r^-1 "); #endif // H0 = β^(1/r) // beta^(1/r) = h(pwd)^k if (crypto_scalarmult_ristretto255(N, ir, Z) != 0) { sodium_munlock(ir, sizeof ir); return -1; } #ifdef TRACE dump((uint8_t*) N, crypto_core_ristretto255_BYTES, "N "); #endif sodium_munlock(ir, sizeof ir); return 0; } liboprf-0.6.1/src/oprf.h000066400000000000000000000116521474121727000150730ustar00rootroot00000000000000#ifndef oprf_h #define oprf_h #include #include #include "toprf.h" #define OPRF_BYTES 64 /** * This function generates an OPRF private key. * * This is almost the KeyGen OPRF function defined in the RFC: since * this lib does not implement V oprf, we don't need a pubkey and so * we don't bother with all that is related. * * @param [out] kU - the per-user OPRF private key */ void oprf_KeyGen(uint8_t kU[crypto_core_ristretto255_SCALARBYTES]); /** * This function computes the OPRF output using input x, N, and domain separation * tag info. * * This is the Finalize OPRF function defined in the RFC. * * @param [in] x - a value used to compute OPRF (the same value that * was used as input to be blinded) * @param [in] x_len - the length of param x in bytes * @param [in] N - a serialized OPRF group element, a byte array of fixed length, * an output of oprf_Unblind * @param [in] info - a domain separation tag * @param [in] info_len - the length of param info in bytes * @param [out] y - an OPRF output * @return The function returns 0 if everything is correct. */ int oprf_Finalize(const uint8_t *x, const uint16_t x_len, const uint8_t N[crypto_core_ristretto255_BYTES], uint8_t rwdU[OPRF_BYTES]); /** * This function converts input x into an element of the OPRF group, randomizes it * by some scalar r, producing blinded, and outputs (r, blinded). * * This is the Blind OPRF function defined in the RFC. * * @param [in] x - the value to blind (for OPAQUE, this is pwdU, the user's * password) * @param [in] x_len - the length of param x in bytes * @param [out] r - an OPRF scalar value used for randomization * @param [out] blinded - a serialized OPRF group element, a byte array of fixed length, * the blinded version of x, an input to oprf_Evaluate * @return The function returns 0 if everything is correct. */ int oprf_Blind(const uint8_t *x, const uint8_t x_len, uint8_t r[crypto_core_ristretto255_SCALARBYTES], uint8_t blinded[crypto_core_ristretto255_BYTES]); /** * This function evaluates input element blinded using private key k, yielding output * element Z. * * This is the Evaluate OPRF function defined in the RFC. * * @param [in] k - a private key (for OPAQUE, this is kU, the user's OPRF private * key) * @param [in] blinded - a serialized OPRF group element, a byte array of fixed length, * an output of oprf_Blind (for OPAQUE, this is the blinded pwdU, the user's * password) * @param [out] Z - a serialized OPRF group element, a byte array of fixed length, * an input to oprf_Unblind * @return The function returns 0 if everything is correct. */ int oprf_Evaluate(const uint8_t k[crypto_core_ristretto255_SCALARBYTES], const uint8_t blinded[crypto_core_ristretto255_BYTES], uint8_t Z[crypto_core_ristretto255_BYTES]); /** * This function removes random scalar r from Z, yielding output N. * * This is the Unblind OPRF function defined in the RFC. * * @param [in] r - an OPRF scalar value used for randomization in oprf_Blind * @param [in] Z - a serialized OPRF group element, a byte array of fixed length, * an output of oprf_Evaluate * @param [out] N - a serialized OPRF group element with random scalar r removed, * a byte array of fixed length, an input to oprf_Finalize * @return The function returns 0 if everything is correct. */ int oprf_Unblind(const uint8_t r[crypto_core_ristretto255_SCALARBYTES], const uint8_t Z[crypto_core_ristretto255_BYTES], uint8_t N[crypto_core_ristretto255_BYTES]); /** * Implements the hash to curve CFRG IRTF https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/ * function needed for the OPRF implementation * * @param [in] msg: the input to hash to a ristretto255 point * @param [in] msg_len: the length of the input * @param [out] p: the resulting ristretto255 point */ int voprf_hash_to_group(const uint8_t *msg, const uint8_t msg_len, uint8_t p[crypto_core_ristretto255_BYTES]); /** * A utility function from the hash to curve CFRG IRTF draft/spec * * uses the input parameters msg/msg_len and dst/dst_len (dst stands * for domain separation tag), and produces a high entropy output in * uniform_bytes of length: len_in_bytes */ int expand_message_xmd(const uint8_t *msg, const uint8_t msg_len, const uint8_t *dst, const uint8_t dst_len, const uint8_t len_in_bytes, uint8_t *uniform_bytes); #ifdef __EMSCRIPTEN__ /** * if compiling to webassembly, there is no sodium_m(un)?lock and thus we suppress that with the following */ // Per // https://emscripten.org/docs/compiling/Building-Projects.html#detecting-emscripten-in-preprocessor, // "The preprocessor define __EMSCRIPTEN__ is always defined when compiling // programs with Emscripten". For why we are replacing sodium_m(un)?lock, see // common.c for more details. #define sodium_mlock(a,l) (0) #define sodium_munlock(a,l) (0) #endif //__EMSCRIPTEN__ #endif liboprf-0.6.1/src/tests/000077500000000000000000000000001474121727000151115ustar00rootroot00000000000000liboprf-0.6.1/src/tests/.gitignore000066400000000000000000000001331474121727000170760ustar00rootroot00000000000000cfrg_oprf_test_vector_decl.h cfrg_oprf_test_vectors.h tv1 tv2 tp-dkg tp-dkg-corrupt mpmult liboprf-0.6.1/src/tests/README.md000066400000000000000000000002641474121727000163720ustar00rootroot00000000000000# IRTF/CFRG testvectors these tests verify the test vectors from the IRTF/CFRG as per: https://github.com/cfrg/draft-irtf-cfrg-voprf/blob/main/draft-irtf-cfrg-voprf.md#oprf-mode liboprf-0.6.1/src/tests/dkg.c000066400000000000000000000107211474121727000160230ustar00rootroot00000000000000#include #include "dkg.h" #include "toprf.h" #include "utils.h" extern int debug; typedef struct { uint8_t index; uint8_t value[crypto_core_ristretto255_BYTES]; } __attribute((packed)) TOPRF_Part; static void topart(TOPRF_Part *r, const TOPRF_Share *s) { r->index=s->index; crypto_scalarmult_ristretto255_base(r->value, s->value); } static int test_dkg_start(const uint8_t n, const uint8_t a[crypto_core_ristretto255_SCALARBYTES], const TOPRF_Share shares[n]) { const size_t response_len = 3; uint8_t responses[response_len][TOPRF_Part_BYTES]; uint8_t result[crypto_scalarmult_ristretto255_BYTES]; uint8_t v[crypto_scalarmult_ristretto255_BYTES]; topart((TOPRF_Part *) responses[0], &shares[4]); topart((TOPRF_Part *) responses[1], &shares[2]); topart((TOPRF_Part *) responses[2], &shares[0]); if(toprf_thresholdmult(response_len, responses, result)) return 1; crypto_scalarmult_ristretto255_base(v, a); if(memcmp(v,result,sizeof v)!=0) { fprintf(stderr,"\e[0;31mmeh!\e[0m\n"); dump(v,sizeof v, "v"); dump(result,sizeof v, "r"); return 1; } return 0; } static int test_dkg_finish(const uint8_t n, const TOPRF_Share shares[n]) { const size_t response_len = 3; uint8_t responses[response_len][TOPRF_Part_BYTES]; uint8_t v0[crypto_scalarmult_ristretto255_BYTES]={0}; uint8_t v1[crypto_scalarmult_ristretto255_BYTES]={0}; //dump((uint8_t*) &shares[4], sizeof(TOPRF_Share), "&shares[4][0] "); topart((TOPRF_Part *) responses[0], &shares[4]); topart((TOPRF_Part *) responses[1], &shares[2]); topart((TOPRF_Part *) responses[2], &shares[0]); //topart((TOPRF_Part *) responses[3], &shares[1][0]); //topart((TOPRF_Part *) responses[4], &shares[3][0]); if(toprf_thresholdmult(response_len, responses, v0)) return 1; dump(v0,sizeof v0, "v0 "); topart((TOPRF_Part *) responses[0], &shares[3]); topart((TOPRF_Part *) responses[1], &shares[1]); topart((TOPRF_Part *) responses[2], &shares[0]); //topart((TOPRF_Part *) responses[3], &shares[2][0]); //topart((TOPRF_Part *) responses[4], &shares[4][0]); if(toprf_thresholdmult(response_len, responses, v1)) return 1; dump(v1,sizeof v1, "v1 "); if(memcmp(v0,v1,sizeof v1)!=0) { fprintf(stderr,"\e[0;31mfailed to verify shares from dkg_finish!\e[0m\n"); return 1; } return 0; } int main(void) { debug = 1; uint8_t n=5, threshold=3; uint8_t commitments[n][threshold][crypto_core_ristretto255_BYTES]; TOPRF_Share shares[n][n]; for(int i=0;iin/msg0 # #msg0: msg0.c # gcc -o msg0 msg0.c -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf # #peer-start: peer-start.c ../../tp-dkg.c # afl-clang-lto -std=c11 -o peer-start peer-start.c ../../tp-dkg.c -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK # #fuzz-ps: peer-star # afl-fuzz -i in -o out ./peer-start in/tc0: fuzz-dump ./fuzz-dump $(N) $(T) $(STEP) in/tc0 in/tc0p: fuzz-dump-peer ./fuzz-dump-peer $(N) $(T) $(STEP) in/tc0p fuzz-dump: ../../tp-dkg.c ../tp-dkg.c gcc -g -o fuzz-dump ../../tp-dkg.c ../tp-dkg.c -DFUZZ_DUMP -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer fuzz-dump-peer: ../../tp-dkg.c ../tp-dkg.c gcc -g -o fuzz-dump-peer ../../tp-dkg.c ../tp-dkg.c -DFUZZ_DUMP -DFUZZ_PEER -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer fuzz-complog: ../../tp-dkg.c ../tp-dkg.c AFL_USE_ASAN=1 AFL_LLVM_CMPLOG=1 afl-clang-lto -o fuzz-complog ../../tp-dkg.c ../tp-dkg.c -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 fuzz-complog-peer: ../../tp-dkg.c ../tp-dkg.c AFL_USE_ASAN=1 AFL_LLVM_CMPLOG=1 afl-clang-lto -o fuzz-complog-peer ../../tp-dkg.c ../tp-dkg.c -DFUZZ_PEER -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 fuzz-bin-asan: ../../tp-dkg.c ../tp-dkg.c AFL_USE_ASAN=1 afl-clang-lto -o fuzz-bin-asan ../../tp-dkg.c ../tp-dkg.c -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 fuzz-bin-asan-peer: ../../tp-dkg.c ../tp-dkg.c AFL_USE_ASAN=1 afl-clang-lto -o fuzz-bin-asan-peer ../../tp-dkg.c ../tp-dkg.c -DFUZZ_PEER -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 fuzz-bin: ../../tp-dkg.c ../tp-dkg.c afl-clang-lto -o fuzz-bin ../../tp-dkg.c ../tp-dkg.c -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 fuzz-bin-peer: ../../tp-dkg.c ../tp-dkg.c afl-clang-lto -o fuzz-bin-peer ../../tp-dkg.c ../tp-dkg.c -DFUZZ_PEER -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 fuzz-asan: in/tc0 fuzz-bin fuzz-bin-asan fuzz-complog afl-fuzz -c ./fuzz-complog -i in -o out -- ./fuzz-bin-asan $(N) $(T) $(STEP) fuzz-asan-peer: in/tc0 fuzz-bin-peer fuzz-bin-asan-peer fuzz-complog-peer afl-fuzz -c ./fuzz-complog-peer -i in -o out -- ./fuzz-bin-asan-peer $(N) $(T) $(STEP) fuzz: in/tc0 fuzz-bin fuzz-bin-asan fuzz-complog afl-fuzz -c ./fuzz-complog -i in -o out -- ./fuzz-bin $(N) $(T) $(STEP) fuzz-peer: in/tc0p fuzz-bin-peer fuzz-bin-asan-peer fuzz-complog-peer afl-fuzz -c ./fuzz-complog-peer -i in -o out -- ./fuzz-bin-peer $(N) $(T) $(STEP) clean: rm -rf fuzz-complog fuzz-bin fuzz-dump in/* out liboprf-0.6.1/src/tests/fuzz/msg0.c000066400000000000000000000014341474121727000171230ustar00rootroot00000000000000#include "tp-dkg.h" #include #include #include #include // gcc -o tpdkg-msg0 msg0.c -I.. -I../noise_xk/include -I../noise_xk/include/karmel -I../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf #define tpdkg_freshness_TIMEOUT 10 int main(void) { uint8_t n=3, t=2; uint8_t peer_lt_pks[crypto_sign_PUBLICKEYBYTES]; // only known by corresponding peer uint8_t peer_lt_sks[crypto_sign_SECRETKEYBYTES]; crypto_sign_keypair(peer_lt_pks, peer_lt_sks); TP_DKG_TPState tp; uint8_t msg0[tpdkg_msg0_SIZE]; int ret = tpdkg_start_tp(&tp, tpdkg_freshness_TIMEOUT, n, t, "proto test", 10, sizeof msg0, (TP_DKG_Message*) &msg0); if(0!=ret) return ret; write(1, msg0, tpdkg_msg0_SIZE); return 0; } liboprf-0.6.1/src/tests/fuzz/peer-start.c000066400000000000000000000022201474121727000203350ustar00rootroot00000000000000#include #include #include "tp-dkg.h" // afl-clang-fast -o peer-start peer-start.c -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf __AFL_FUZZ_INIT(); int main() { // anything else here, e.g. command line arguments, initialization, etc. uint8_t peer_lt_sks[32]={250}; TP_DKG_PeerState peer; #ifdef __AFL_HAVE_MANUAL_CONTROL __AFL_INIT(); #endif unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; // must be after __AFL_INIT // and before __AFL_LOOP! while (__AFL_LOOP(10000)) { int len = __AFL_FUZZ_TESTCASE_LEN; // don't use the macro directly in a // call! if (len < sizeof(TP_DKG_Message)) continue; // check for a required/useful minimum input length /* Setup function call, e.g. struct target *tmp = libtarget_init() */ /* Call function to be fuzzed, e.g.: */ tpdkg_start_peer(&peer, 10, peer_lt_sks, (TP_DKG_Message*) buf); /* Reset state. e.g. libtarget_free(tmp) */ } return 0; } liboprf-0.6.1/src/tests/fuzz/tpdkg_msg_parser.py000077500000000000000000000012771474121727000220260ustar00rootroot00000000000000#!/usr/bin/env python import sys from construct import * tpdkg_msg = Struct( "signature" / Array(64, Byte), "msgno" / Int8ub, "size" / Int32ub, "sender" / Int8ub, "to" / Int8ub, "ts" / Timestamp(Int64ub, 1., 1970), "data" / Array(this.size - 79, Byte), ) messages = GreedyRange(tpdkg_msg) with open(sys.argv[1], 'rb') as fd: raw = fd.read() while len(raw) > 0: print(raw[:83].hex()) try: msg = tpdkg_msg.parse(raw) print(f"{str(msg.ts)[:-6]} msgno: {msg.msgno}, len: {msg.size}, from: {msg.sender}, to: {msg.to:x}, data {bytes(msg.data).hex()}") raw = raw[msg.size:] except: print(raw[65:69].hex()) raw = raw[83:] liboprf-0.6.1/src/tests/makefile000066400000000000000000000046021474121727000166130ustar00rootroot00000000000000CFLAGS?= -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \ -fstack-protector-strong -fasynchronous-unwind-tables -fpic \ -ftrapv -D_GLIBCXX_ASSERTIONS \ -Wl,-z,defs -Wl,-z,relro \ -Wl,-z,noexecstack -Wl,-z,now -fsanitize=signed-integer-overflow \ -fsanitize-undefined-trap-on-error CC?=gcc ARCH := $(shell uname -m) ifeq ($(ARCH),x86_64) CFLAGS+=-fcf-protection=full endif ifeq ($(ARCH),parisc64) else ifeq ($(ARCH),parisc64) else CFLAGS+=-fstack-clash-protection endif all: tv1 tv2 dkg toprf tp-dkg tp-dkg-corrupt mpmult tv1: test.c cfrg_oprf_test_vectors.h cfrg_oprf_test_vector_decl.h ../oprf.c ../utils.c $(CC) -Wall -g -o tv1 -DCFRG_TEST_VEC=1 -DCFRG_OPRF_TEST_VEC=1 -DTC=0 test.c ../oprf.c ../utils.c -lsodium tv2: test.c cfrg_oprf_test_vectors.h cfrg_oprf_test_vector_decl.h ../oprf.c ../utils.c $(CC) -Wall -g -o tv2 -DCFRG_TEST_VEC=1 -DCFRG_OPRF_TEST_VEC=1 -DTC=1 test.c ../oprf.c ../utils.c -lsodium toprf: toprf.c ../liboprf.a $(CC) -g -o toprf toprf.c ../liboprf.a $(EXTRA_SOURCES) -lsodium dkg: ../dkg.c ../utils.c dkg.c ../dkg.c ../liboprf.a ../utils.c $(CC) $(CFLAGS) -g -I.. -DUNIT_TEST -o dkg dkg.c ../dkg.c ../utils.c ../liboprf.a -lsodium tp-dkg: ../tp-dkg.c tp-dkg.c ../liboprf.a ../tp-dkg.c $(CC) $(CFLAGS) -D_DEFAULT_SOURCE -g -std=c11 -I.. -I../noise_xk/include -I../noise_xk/include/karmel/ -I../noise_xk/include/karmel/minimal/ -DWITH_SODIUM -DUNITTEST -o tp-dkg tp-dkg.c ../tp-dkg.c ../liboprf.a ../noise_xk/liboprf-noiseXK.a -lsodium tp-dkg-corrupt: ../tp-dkg.c tp-dkg.c ../liboprf.a ../tp-dkg.c $(CC) $(CFLAGS) -D_DEFAULT_SOURCE -g -std=c11 -I.. -I../noise_xk/include -I../noise_xk/include/karmel/ -I../noise_xk/include/karmel/minimal/ -DWITH_SODIUM -DUNITTEST -DUNITTEST_CORRUPT -o tp-dkg-corrupt tp-dkg.c ../tp-dkg.c ../liboprf.a ../noise_xk/liboprf-noiseXK.a -lsodium mpmult: ../mpmult.c ../liboprf.a mpmult.c ../liboprf.a ../utils.c ../toprf.c $(CC) $(CFLAGS) -Wall -g -I.. -DUNIT_TEST -o mpmult mpmult.c ../mpmult.c ../utils.c ../toprf.c ../liboprf.a -lsodium ../liboprf.a: make -C .. liboprf.a cfrg_oprf_test_vectors.h: testvecs2h.py ./testvecs2h.py $@ >$@ cfrg_oprf_test_vector_decl.h: testvecs2h.py ./testvecs2h.py $@ >$@ tests: all ./dkg ./tv1 ./tv2 ./toprf (ulimit -s 66000; ./tp-dkg 3 2) (ulimit -s 66000; ./tp-dkg-corrupt 3 2 || exit 0) ./mpmult clean: rm -f cfrg_oprf_test_vector_decl.h cfrg_oprf_test_vectors.h tv1 tv2 tp-dkg dkg toprf mpmult liboprf-0.6.1/src/tests/mpmult.c000066400000000000000000000156301474121727000166000ustar00rootroot00000000000000#include #include "../oprf.h" #include "../mpmult.h" #include "../dkg.h" #include "../utils.h" #include #include int test_mpmul(void) { const unsigned threshold = 2, dealers = (threshold*2) + 1, peers = dealers * 2; // share value k0 uint8_t k0[crypto_core_ristretto255_SCALARBYTES]; crypto_core_ristretto255_scalar_random(k0); //debian_rng(k0); dump(k0, sizeof k0, "k0"); // split k into shares uint8_t shares0[peers][TOPRF_Share_BYTES]; toprf_create_shares(k0, peers, threshold, shares0); if(debug) { for(unsigned j=0;j #include #include #include "cfrg_oprf_test_vectors.h" #include "../oprf.h" #include "../utils.h" extern int debug; int main(void) { debug = 1; int res; uint8_t r[crypto_core_ristretto255_SCALARBYTES]; uint8_t blinded[crypto_core_ristretto255_BYTES]; res = oprf_Blind(input, input_len, r, blinded); if(res) return 1; if(memcmp(blinded, blinded_element, blindedelement_len)!=0) { fail("calulated Blinded Element is not expected value:"); dump(blinded, sizeof(blinded), "calculated: "); dump(blinded_element, blindedelement_len, "expected: "); return 1; } uint8_t Z[crypto_core_ristretto255_BYTES]; res = oprf_Evaluate(sks, blinded, Z); if(res) { fprintf(stderr,"oprf_Evaluate returned error\n"); return 1; } if(memcmp(Z, evaluationelement, evaluationelement_len)!=0) { fail("calulated Evaluation Element is not expected value:"); dump(Z, sizeof(Z), "calculated: "); dump(evaluationelement, evaluationelement_len, "expected: "); return 1; } uint8_t N[crypto_core_ristretto255_BYTES]; res = oprf_Unblind(r, Z, N); if(res) { fprintf(stderr,"oprf_Unblind returned error\n"); return 1; } uint8_t rwd[OPRF_BYTES]; res = oprf_Finalize(input, input_len, N, rwd); if(res) { fprintf(stderr,"oprf_Finalize returned error\n"); return 1; } if(memcmp(rwd, output, output_len)!=0) { fail("calulated output is not expected value:"); dump(rwd, sizeof(rwd), "calculated: "); dump(output, output_len, "expected: "); return 1; } printf("all ok\n"); return 0; } liboprf-0.6.1/src/tests/testvecs2h.py000077500000000000000000000105171474121727000175640ustar00rootroot00000000000000#!/usr/bin/env python3 import json, sys from itertools import zip_longest # for Python 3.x def split_by_n(iterable, n): return zip_longest(*[iter(iterable)]*n, fillvalue='') # src: ht vectors = """ { "groupDST": "48617368546f47726f75702d4f50524656312d002d72697374726574746f3235352d534841353132", "hash": "SHA512", "identifier": "ristretto255-SHA512", "keyInfo": "74657374206b6579", "mode": 0, "seed": "a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3", "skSm": "5ebcea5ee37023ccb9fc2d2019f9d7737be85591ae8652ffa9ef0f4d37063b0e", "vectors": [ { "Batch": 1, "Blind": "64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f6706", "BlindedElement": "609a0ae68c15a3cf6903766461307e5c8bb2f95e7e6550e1ffa2dc99e412803c", "EvaluationElement": "7ec6578ae5120958eb2db1745758ff379e77cb64fe77b0b2d8cc917ea0869c7e", "Input": "00", "Output": "527759c3d9366f277d8c6020418d96bb393ba2afb20ff90df23fb7708264e2f3ab9135e3bd69955851de4b1f9fe8a0973396719b7912ba9ee8aa7d0b5e24bcf6" }, { "Batch": 1, "Blind": "64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f6706", "BlindedElement": "da27ef466870f5f15296299850aa088629945a17d1f5b7f5ff043f76b3c06418", "EvaluationElement": "b4cbf5a4f1eeda5a63ce7b77c7d23f461db3fcab0dd28e4e17cecb5c90d02c25", "Input": "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a", "Output": "f4a74c9c592497375e796aa837e907b1a045d34306a749db9f34221f7e750cb4f2a6413a6bf6fa5e19ba6348eb673934a722a7ede2e7621306d18951e7cf2c73" } ] } """ def toC(k, v): print(f"#define {k.lower()}_len {len(v)//2}") print( f"const uint8_t {k.lower()}[{k.lower()}_len] = {{\n %s}};\n" % ",\n ".join( (", ".join((c for c in line if c)) for line in split_by_n( (f"0x{x[0]}{x[1]}" for x in split_by_n(v,2)) ,8)) )) vex = json.loads(vectors) print("// this file has been automatically generated using testvecs2h.py") if sys.argv[1] == 'cfrg_oprf_test_vectors.h': # run this if there is a change in the values of the test vectors # ./testvecs2h.py >cfrg_oprf_test_vectors.h print("#ifndef cfrg_test_vectors_h\n#define cfrg_test_vectors_h\n") print("#include \n") toC("sks", vex['skSm']) for tc in range(2): for k, v in vex['vectors'][tc].items(): if k == "Batch": continue print(f"#define tc{tc}_{k.lower()}_len {len(v)//2}") print( f"const uint8_t tc{tc}_{k.lower()}[tc{tc}_{k.lower()}_len] = {{\n %s}};\n" % ",\n ".join( (", ".join((c for c in line if c)) for line in split_by_n( (f"0x{x[0]}{x[1]}" for x in split_by_n(v,2)) ,8)) )) elif sys.argv[1] == 'cfrg_oprf_test_vector_decl.h': # only run this code below if there is a change in the keys of the test vectors # ./testvecs2h.py >cfrg_oprf_test_vector_decl.h print("#ifndef cfrg_test_vector_decl_h\n#define cfrg_test_vector_decl_h\n") print("#include \n") for tc in range(2): for k, v in vex['vectors'][tc].items(): if k == "Batch": continue print(f"#define tc{tc}_{k.lower()}_len {len(v)//2}") print(f"extern const uint8_t tc{tc}_{k.lower()}[tc{tc}_{k.lower()}_len];\n") else: sys.exit(-1) print(""" #if(TC==0) #define input tc0_input #define input_len tc0_input_len #define blind_registration tc0_blind #define blind_login tc0_blind #define blind_len tc0_blind_len #define blinded_element tc0_blindedelement #define blindedelement_len tc0_blindedelement_len #define evaluationelement tc0_evaluationelement #define evaluationelement_len tc0_evaluationelement_len #define output tc0_output #define output_len tc0_output_len #else #define input tc1_input #define input_len tc1_input_len #define blind_registration tc1_blind #define blind_login tc1_blind #define blind_len tc1_blind_len #define blinded_element tc1_blindedelement #define blindedelement_len tc1_blindedelement_len #define evaluationelement tc1_evaluationelement #define evaluationelement_len tc1_evaluationelement_len #define output tc1_output #define output_len tc1_output_len #endif""") print("#endif") liboprf-0.6.1/src/tests/toprf.c000066400000000000000000000066271474121727000164220ustar00rootroot00000000000000#include #include #include "../oprf.h" #include "../toprf.h" int main(void) { // setup // todo use dkg const unsigned peers = 3, threshold = 2; uint8_t k[crypto_core_ristretto255_SCALARBYTES]; crypto_core_ristretto255_scalar_random(k); // split k into shares uint8_t shares[peers][TOPRF_Share_BYTES]; toprf_create_shares(k, peers, threshold, shares); // start the OPRF const uint8_t password[8]="password"; uint8_t r[crypto_core_ristretto255_SCALARBYTES]; uint8_t alpha[crypto_core_ristretto255_BYTES]; // we blind once if(oprf_Blind(password, sizeof password, r, alpha)) return 1; // until here all is like with the non-threshold version // calculate points of shares // this really happens at each peer separately uint8_t xresps[peers][TOPRF_Part_BYTES]; for(size_t i=0;i #include #include #include "utils.h" #include "toprf.h" #include "tp-dkg.h" #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION #include #endif #define tpdkg_freshness_TIMEOUT 120000 extern FILE* log_file; extern int debug; #ifdef __AFL_FUZZ_INIT __AFL_FUZZ_INIT(); #endif typedef struct { uint8_t index; uint8_t value[crypto_core_ristretto255_BYTES]; } __attribute((packed)) TOPRF_Part; static void topart(TOPRF_Part *r, const TOPRF_Share *s) { r->index=s->index; crypto_scalarmult_ristretto255_base(r->value, s->value); } static void shuffle(uint8_t *array, const size_t n) { if (n < 2) return; srand(time(NULL)); for(int i=0; i= NETWORK_BUF_SIZE || msg_len==0 || msg == NULL) { return;// 0; } memcpy(net+*pkt_len, msg, msg_len); *pkt_len+=msg_len; //return msg_len; } //static size_t _recv(const uint8_t *net, size_t *pkt_len, uint8_t *buf, const size_t msg_len) { static void _recv(const uint8_t *net, size_t *pkt_len, uint8_t *buf, const size_t msg_len) { if(*pkt_len < msg_len || msg_len == 0) { return; // 0; } memcpy(buf, net, msg_len); *pkt_len-=msg_len; //return msg_len; } #ifdef FUZZ_DUMP #if !defined(FUZZ_PEER) static void fuzz_dump(const uint8_t step, TP_DKG_TPState *ctx, const uint8_t *buf_in, const size_t buf_in_size, const char **argv, const int argc) { #else static void fuzz_dump(const uint8_t step, TP_DKG_PeerState *ctx, const uint8_t *buf_in, const size_t buf_in_size, const char **argv, const int argc) { #endif //!defined(FUZZ_PEER) if(argc<5) { fprintf(stderr, "error incorrect number of params, run as: %% %s \n", argv[0]); exit(1); } if(ctx->step==step) { FILE *tc = fopen(argv[4], "wb"); fwrite(buf_in, 1, buf_in_size, tc); fclose(tc); exit(0); } } #endif #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) #if !defined(FUZZ_PEER) static int fuzz_loop(const uint8_t step, TP_DKG_TPState *tp, TP_DKG_PeerState *peers, uint8_t network_buf[][NETWORK_BUF_SIZE],size_t pkt_len[]) { if(tp->step!=step) return 0; TP_DKG_TPState checkpoint; memcpy(&checkpoint, tp, sizeof(checkpoint)); TP_DKG_PeerState pcheckpoints[tp->n]; memcpy(&pcheckpoints, peers, sizeof(pcheckpoints)); #ifdef __AFL_HAVE_MANUAL_CONTROL __AFL_INIT(); #endif unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; // must be after __AFL_INIT // and before __AFL_LOOP! while (__AFL_LOOP(10000)) { int len = __AFL_FUZZ_TESTCASE_LEN; // don't use the macro directly in a call! if (len < sizeof(TP_DKG_Message)) continue; // check for a required/useful minimum input length // doing vla - but avoiding 0 sized ones is ugly const size_t tp_out_size = tpdkg_tp_output_size(tp); uint8_t tp_out_buf[tp_out_size==0?1:tp_out_size], *tp_out; if(tp_out_size==0) tp_out = NULL; else tp_out = tp_out_buf; /* Setup function call, e.g. struct target *tmp = libtarget_init() */ /* Call function to be fuzzed, e.g.: */ int ret = tpdkg_tp_next(tp, buf, len, tp_out, tp_out_size); if(0!=ret) { // clean up peers for(uint8_t i=0;in;i++) tpdkg_peer_free(&peers[i]); if(tp->cheater_len > 0) return 125; return ret; } while(tpdkg_tp_not_done(tp)) { for(uint8_t i=0;in;i++) { const uint8_t *msg; size_t len; if(0!=tpdkg_tp_peer_msg(tp, tp_out, tp_out_size, i, &msg, &len)) { return 1; } _send(network_buf[i+1], &pkt_len[i+1], msg, len); } while(pkt_len[0]==0 && tpdkg_peer_not_done(&peers[1])) { for(uint8_t i=0;in;i++) { // 0sized vla meh const size_t peer_out_size = tpdkg_peer_output_size(&peers[i]); uint8_t peers_out_buf[peer_out_size==0?1:peer_out_size], *peers_out; if(peer_out_size==0) peers_out = NULL; else peers_out = peers_out_buf; // 0sized vla meh for the last time.. const size_t peer_in_size = tpdkg_peer_input_size(&peers[i]); uint8_t peer_in_buf[peer_in_size==0?1:peer_in_size], *peer_in; if(peer_in_size==0) peer_in = NULL; else peer_in = peer_in_buf; _recv(network_buf[i+1], &pkt_len[i+1], peer_in, peer_in_size); ret = tpdkg_peer_next(&peers[i], peer_in, peer_in_size, peers_out, peer_out_size); if(0!=ret) { // clean up peers for(uint8_t i=0;in;i++) tpdkg_peer_free(&peers[i]); return ret; } _send(network_buf[0], &pkt_len[0], peers_out, peer_out_size); } } // doing vla - but avoiding 0 sized ones is ugly const size_t tp_out_size = tpdkg_tp_output_size(tp); uint8_t tp_out_buf[tp_out_size==0?1:tp_out_size], *tp_out; if(tp_out_size==0) tp_out = NULL; else tp_out = tp_out_buf; // avoiding zero-sized vla is still ugly const size_t tp_in_size = tpdkg_tp_input_size(tp); uint8_t tp_in_buf[tp_in_size==0?1:tp_in_size], *tp_in; if(tp_in_size==0) tp_in = NULL; else tp_in = tp_in_buf; _recv(network_buf[0], &pkt_len[0], tp_in, tp_in_size); ret = tpdkg_tp_next(tp, tp_in, tp_in_size, tp_out, tp_out_size); if(0!=ret) { // clean up peers for(uint8_t i=0;in;i++) tpdkg_peer_free(&peers[i]); if(tp->cheater_len > 0) return 55; return ret; } } /* Reset state. e.g. libtarget_free(tmp) */ memcpy(tp, &checkpoint, sizeof(TP_DKG_TPState)); memcpy(peers, &pcheckpoints, sizeof(pcheckpoints)); } return 0; } #else // !defined(FUZZ_PEER) static int fuzz_loop(const uint8_t step, TP_DKG_TPState *tp, TP_DKG_PeerState *peers, uint8_t network_buf[][NETWORK_BUF_SIZE],size_t pkt_len[]) { if(peers[0].step!=step) return 0; TP_DKG_TPState checkpoint; memcpy(&checkpoint, tp, sizeof(checkpoint)); TP_DKG_PeerState pcheckpoints[tp->n]; memcpy(&pcheckpoints, peers, sizeof(pcheckpoints)); #ifdef __AFL_HAVE_MANUAL_CONTROL __AFL_INIT(); #endif unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; // must be after __AFL_INIT // and before __AFL_LOOP! int ret; while (__AFL_LOOP(10000)) { int len = __AFL_FUZZ_TESTCASE_LEN; // don't use the macro directly in a call! if (len < sizeof(TP_DKG_Message)) continue; // check for a required/useful minimum input length // doing vla - but avoiding 0 sized ones is ugly const size_t peer_out_size = tpdkg_peer_output_size(&peers[0]); uint8_t peer_out_buf[peer_out_size==0?1:peer_out_size], *peer_out; if(peer_out_size==0) peer_out = NULL; else peer_out = peer_out_buf; ret = tpdkg_peer_next(&peers[0], buf, len, peer_out, peer_out_size); if(ret!=0) { //for(uint8_t i=0;in;i++) tpdkg_peer_free(&peers[i]); return ret; } _send(network_buf[0], &pkt_len[0], peer_out, peer_out_size); for(uint8_t i=1;in;i++) { // 0sized vla meh const size_t peer_out_size = tpdkg_peer_output_size(&peers[i]); uint8_t peers_out_buf[peer_out_size==0?1:peer_out_size], *peers_out; if(peer_out_size==0) peers_out = NULL; else peers_out = peers_out_buf; // 0sized vla meh for the last time.. const size_t peer_in_size = tpdkg_peer_input_size(&peers[i]); uint8_t peer_in_buf[peer_in_size==0?1:peer_in_size], *peer_in; if(peer_in_size==0) peer_in = NULL; else peer_in = peer_in_buf; _recv(network_buf[i+1], &pkt_len[i+1], peer_in, peer_in_size); ret = tpdkg_peer_next(&peers[i], peer_in, peer_in_size, peers_out, peer_out_size); if(0!=ret) { // clean up peers //for(uint8_t i=0;in;i++) tpdkg_peer_free(&peers[i]); return ret; } _send(network_buf[0], &pkt_len[0], peers_out, peer_out_size); } while(tpdkg_tp_not_done(tp)) { while(pkt_len[0]==0 && tpdkg_peer_not_done(&peers[1])) { for(uint8_t i=0;in;i++) { // 0sized vla meh const size_t peer_out_size = tpdkg_peer_output_size(&peers[i]); uint8_t peers_out_buf[peer_out_size==0?1:peer_out_size], *peers_out; if(peer_out_size==0) peers_out = NULL; else peers_out = peers_out_buf; // 0sized vla meh for the last time.. const size_t peer_in_size = tpdkg_peer_input_size(&peers[i]); uint8_t peer_in_buf[peer_in_size==0?1:peer_in_size], *peer_in; if(peer_in_size==0) peer_in = NULL; else peer_in = peer_in_buf; _recv(network_buf[i+1], &pkt_len[i+1], peer_in, peer_in_size); ret = tpdkg_peer_next(&peers[i], peer_in, peer_in_size, peers_out, peer_out_size); if(0!=ret) { // clean up peers //for(uint8_t i=0;in;i++) tpdkg_peer_free(&peers[i]); return ret; } _send(network_buf[0], &pkt_len[0], peers_out, peer_out_size); } } // doing vla - but avoiding 0 sized ones is ugly const size_t tp_out_size = tpdkg_tp_output_size(tp); uint8_t tp_out_buf[tp_out_size==0?1:tp_out_size], *tp_out; if(tp_out_size==0) tp_out = NULL; else tp_out = tp_out_buf; // avoiding zero-sized vla is still ugly const size_t tp_in_size = tpdkg_tp_input_size(tp); uint8_t tp_in_buf[tp_in_size==0?1:tp_in_size], *tp_in; if(tp_in_size==0) tp_in = NULL; else tp_in = tp_in_buf; _recv(network_buf[0], &pkt_len[0], tp_in, tp_in_size); ret = tpdkg_tp_next(tp, tp_in, tp_in_size, tp_out, tp_out_size); if(0!=ret) { // clean up peers for(uint8_t i=0;in;i++) tpdkg_peer_free(&peers[i]); if(tp->cheater_len > 0) return 55; return ret; } for(uint8_t i=0;in;i++) { const uint8_t *msg; size_t len; if(0!=tpdkg_tp_peer_msg(tp, tp_out, tp_out_size, i, &msg, &len)) { return 1; } _send(network_buf[i+1], &pkt_len[i+1], msg, len); } } /* Reset state. e.g. libtarget_free(tmp) */ memcpy(tp, &checkpoint, sizeof(TP_DKG_TPState)); memcpy(peers, &pcheckpoints, sizeof(pcheckpoints)); } return 0; } #endif #endif int main(const int argc, const char **argv) { int ret; // enable logging log_file = stderr; debug = 1; if(argc<3) { #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(FUZZ_DUMP) fprintf(stderr, "error incorrect numbers of parameters, run as: %% %s [ []]\n", argv[0]); #else fprintf(stderr, "error incorrect numbers of parameters, run as: %% %s \n", argv[0]); #endif // defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(FUZZ_DUMP) exit(1); } uint8_t n=atoi(argv[1]),t=atoi(argv[2]); #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || defined(FUZZ_DUMP) uint8_t step=atoi(argv[3]); #ifdef FUZZ_PEER if(step<1 || step > 9 || step==7 || step==8) { #else if(step<1 || step > 9) { #endif fprintf(stderr, "error incorrect value for step must be 1-9 (but not 7 or 8), run as: %% %s <1-7> \n", argv[0]); exit(1); } #endif // mock long-term peer keys // all known by TP uint8_t peer_lt_pks[n][crypto_sign_PUBLICKEYBYTES]; // only known by corresponding peer uint8_t peer_lt_sks[n][crypto_sign_SECRETKEYBYTES]; for(uint8_t i=0;i 0) break; return ret; } for(uint8_t i=0;i n) return 1; if(tmp[p]==0) total_cheaters++; tmp[p]++; } fprintf(stderr, "\e[0;31m:/ dkg failed, total cheaters %d, list of cheaters:", total_cheaters); for(int i=1;i<=n;i++) { if(tmp[i]==0) continue; fprintf(stderr," %d(%d)", i, tmp[i]); } fprintf(stderr, "\e[0m\n"); return 1; } // clean up peers for(uint8_t i=0;i #include "oprf.h" #include "toprf.h" #include #ifdef UNIT_TEST #include "utils.h" #endif /* @copyright 2023, Stefan Marsiske toprf@ctrlc.hu This file is part of liboprf. liboprf is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liboprf is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the License along with liboprf. If not, see . */ // implements TOPRF from https://eprint.iacr.org/2017/363 // quote from page 9 (first line is last on page 8) // The underlying PRF, fk(x) = H2(x, (H1(x))k), remains unchanged, but the // key k is shared using Shamir secret-sharing across n servers, where server Si // stores the key share ki. The initialization of such secret-sharing can be done via // a Distributed Key Generation (DKG) for discrete-log-based systems, e.g. [16], // and in Figure 2 we assume it is done with a UC functionality FDKG which we // discuss further below. For evaluation, given any subset SE of t + 1 servers, the // user U sends to each of them the same message a = (H′(x))r for random r, // exactly as in the single-server OPRF protocol 2HashDH. If each server Si in SE // returned bi = aki then U could reconstruct the value ak using standard Lagrange // interpolation in the exponent, i.e. ak = � i∈SE bλi i with the Lagrange coefficients // λi computed using the indexes of servers in SE. After computing ak, the value // of fk(x) is computed by U by deblinding ak exactly as in the case of protocol // 2HashDH. Note that this takes a single exponentiation for each server and two // exponentiations for the user (to compute a and to deblind ak) plus one multi- // exponentiation by U to compute the Lagrange interpolation on the bi values. // run with // gcc -o toprf -g -Wall toprf.c -lsodium liboprf.a typedef struct { uint8_t index; uint8_t value[crypto_core_ristretto255_SCALARBYTES]; } __attribute((packed)) TOPRF_Share; typedef struct { uint8_t index; uint8_t value[crypto_core_ristretto255_BYTES]; } __attribute((packed)) TOPRF_Part; void coeff(const uint8_t index, const size_t peers_len, const uint8_t peers[peers_len], uint8_t result[crypto_scalarmult_ristretto255_SCALARBYTES]) { uint8_t iscalar[crypto_scalarmult_ristretto255_SCALARBYTES]={0}; iscalar[0]=index; uint8_t divident[crypto_scalarmult_ristretto255_SCALARBYTES]={0}; divident[0]=1; uint8_t divisor[crypto_scalarmult_ristretto255_SCALARBYTES]={0}; divisor[0]=1; for(size_t j=0;j 0 && arr[d] < arr[d-1]) { t = arr[d]; t1 = indexes[d]; arr[d] = arr[d-1]; indexes[d] = indexes[d-1]; arr[d-1] = t; indexes[d-1] = t1; d--; } } } int toprf_thresholdmult(const size_t response_len, const uint8_t _responses[response_len][TOPRF_Part_BYTES], uint8_t result[crypto_scalarmult_ristretto255_BYTES]) { const TOPRF_Part *responses=(TOPRF_Part*) _responses; uint8_t lpoly[crypto_scalarmult_ristretto255_SCALARBYTES]; uint8_t gki[crypto_scalarmult_ristretto255_BYTES]; memset(result,0,crypto_scalarmult_ristretto255_BYTES); // sort the responses by their indexes uint8_t indexed_indexes[response_len]; if(response_len>255) return 1; sort_parts((uint8_t) response_len, (TOPRF_Part*) responses, indexed_indexes); uint8_t indexes[response_len]; for(size_t i=0;ivalue, lpoly); TOPRF_Part *Z=(TOPRF_Part*) _Z; if(oprf_Evaluate(kl,blinded, Z->value)) return 1; return 0; } int toprf_thresholdcombine(const size_t response_len, const uint8_t _responses[response_len][TOPRF_Part_BYTES], uint8_t result[crypto_scalarmult_ristretto255_BYTES]) { if(response_len>255) return 1; const TOPRF_Part *responses=(TOPRF_Part*) _responses; memset(result,0,crypto_scalarmult_ristretto255_BYTES); uint8_t indexed_indexes[response_len]; sort_parts((uint8_t) response_len, (TOPRF_Part*) responses, indexed_indexes); for(size_t i=0;iindex=k->index; if(oprf_Evaluate(k->value, alpha, beta->value)) return 1; // hash (ssid_S + alpha, outlen=64) crypto_generichash_state h_state; crypto_generichash_init(&h_state, NULL, 0, crypto_core_ristretto255_HASHBYTES); uint16_t len=htons((uint16_t) ssid_S_len); // we have a guard above restricting to 1KB the proto_name_len crypto_generichash_update(&h_state, (uint8_t*) &len, 2); crypto_generichash_update(&h_state, ssid_S, ssid_S_len); crypto_generichash_update(&h_state, alpha, crypto_core_ristretto255_BYTES); uint8_t hash[crypto_core_ristretto255_HASHBYTES]; crypto_generichash_final(&h_state,hash,sizeof hash); // hash-to-curve uint8_t point[crypto_scalarmult_ristretto255_BYTES]; if(0!=voprf_hash_to_group(hash, sizeof hash, point)) return -1; TOPRF_Part h2; const TOPRF_Share *z=(TOPRF_Share*) _z; if(oprf_Evaluate(z->value, point, h2.value)) return 1; crypto_core_ristretto255_add(beta->value, beta->value, h2.value); return 0; } liboprf-0.6.1/src/toprf.h000066400000000000000000000143031474121727000152530ustar00rootroot00000000000000/* @copyright 2023, Stefan Marsiske toprf@ctrlc.hu This file is part of liboprf. liboprf is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liboprf is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the License along with liboprf. If not, see . */ #ifndef TOPRF_H #define TOPRF_H #include #include #define TOPRF_Share_BYTES (crypto_core_ristretto255_SCALARBYTES+1UL) #define TOPRF_Part_BYTES (crypto_core_ristretto255_BYTES+1UL) /** * This function calculates a lagrange coefficient based on the index * and the indexes of the other contributing shareholders. * * @param [in] index - the index of the shareholder whose lagrange * coefficient we're calculating * * @param [in] peers_len - the number of shares in peers * * @param [in] peers - the shares that contribute to the reconstruction * * @param [out] result - the lagrange coefficient */ void coeff(const uint8_t index, const size_t peers_len, const uint8_t peers[peers_len], uint8_t result[crypto_scalarmult_ristretto255_SCALARBYTES]); /** * This function creates shares of secret in a (threshold, n) scheme * over the curve ristretto255 * * @param [in] secret - the scalar value to be secretly shared * * @param [in] n - the number of shares created * * @param [in] threshold - the threshold needed to reconstruct the secret * * @param [out] shares - n shares * * @return The function returns 0 if everything is correct. */ void toprf_create_shares(const uint8_t secret[crypto_core_ristretto255_SCALARBYTES], const uint8_t n, const uint8_t threshold, uint8_t shares[n][TOPRF_Share_BYTES]); /** * This function recovers the secret in the exponent using lagrange interpolation * over the curve ristretto255 * * The shareholders are not aware if they are contributing to a * threshold or non-threshold oprf evaluation, from their perspective * nothing changes in this approach. * * @param [in] responses_len - the number of elements in the response array * * @param [in] responses - is an array of shares (k_i) multiplied by a * point (P) on the r255 curve * * @param [out] result - the reconstructed value of P multipled by k * * @return The function returns 0 if everything is correct. */ int toprf_thresholdmult(const size_t response_len, const uint8_t responses[response_len][TOPRF_Part_BYTES], uint8_t result[crypto_scalarmult_ristretto255_BYTES]); /** * This function is the efficient threshold version of oprf_Evaluate. * * This function needs to know in advance the indexes of all the * shares that will be combined later in the toprf_thresholdcombine() function. * by doing so this reduces the total costs and distributes them to the shareholders. * * @param [in] k - a private key (for OPAQUE, this is kU, the user's * OPRF private key) * * @param [in] blinded - a serialized OPRF group element, a byte array * of fixed length, an output of oprf_Blind (for OPAQUE, this * is the blinded pwdU, the user's password) * * @param [in] self - the index of the current shareholder * * @param [in] indexes - the indexes of the all the shareholders * contributing to this oprf evaluation, * * @param [in] index_len - the length of the indexes array, * * @param [out] Z - a serialized OPRF group element, a byte array of fixed length, * an input to oprf_Unblind * * @return The function returns 0 if everything is correct. */ int toprf_Evaluate(const uint8_t k[TOPRF_Share_BYTES], const uint8_t blinded[crypto_core_ristretto255_BYTES], const uint8_t self, const uint8_t *indexes, const uint16_t index_len, uint8_t Z[TOPRF_Part_BYTES]); /** * This function is combines the results of the toprf_Evaluate() * function to recover the shared secret in the exponent. * * @param [in] responses - is an array of shares (k_i) multiplied by a point (P) on the r255 curve * * @param [in] responses_len - the number of elements in the response array * * @param [out] result - the reconstructed value of P multipled by k * * @return The function returns 0 if everything is correct. */ int toprf_thresholdcombine(const size_t response_len, const uint8_t _responses[response_len][TOPRF_Part_BYTES], uint8_t result[crypto_scalarmult_ristretto255_BYTES]); typedef int (*toprf_evalcb)(void* ctx, const uint8_t k[crypto_core_ristretto255_SCALARBYTES], const uint8_t alpha[crypto_core_ristretto255_BYTES], uint8_t beta[crypto_core_ristretto255_BYTES]); typedef int (*toprf_keygencb)(void* ctx, uint8_t k[crypto_core_ristretto255_SCALARBYTES]); /** Implements 3hashtdh from the paper Threshold PAKE with Security against Compromise of all Servers see: https://eprint.iacr.org/2024/1455 Use this function if you implement a threshold OPRF. @param [in] k - the share of k @param [in] z - the share of zero @param [in] alpha - the blinded element from the client @param [in] ssid_S - a sub-session identifier that all participants to the threshold evaluation must agree on (it must be the same for all of them). @param [in] ssid_S_len - the length of the ssid_S identifier @param [out] beta - the result of the evaluation, to be returned to the client. */ int toprf_3hashtdh(const uint8_t k[TOPRF_Share_BYTES], const uint8_t z[TOPRF_Share_BYTES], const uint8_t alpha[crypto_core_ristretto255_BYTES], const uint8_t *ssid_S, const uint16_t ssid_S_len, uint8_t beta[TOPRF_Part_BYTES]); #endif // TOPRF_H liboprf-0.6.1/src/tp-dkg.c000066400000000000000000002106061474121727000153060ustar00rootroot00000000000000#include #include #include #include //htons #include // time #include // __BYTE_ORDER __BIG_ENDIAN #include // memcpy #include // va_{start|end} #include // free, rand #include "XK.h" #include "dkg.h" #include "tp-dkg.h" #include "noise_private.h" /* @copyright 2024, Stefan Marsiske toprf@ctrlc.hu This file is part of liboprf. SPDX-FileCopyrightText: 2024, Marsiske Stefan SPDX-License-Identifier: LGPL-3.0-or-later liboprf is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liboprf is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the License along with liboprf. If not, see . */ /* This file implements a high-level DKG protocol facilitated by a trusted orchestrator which connects to all participating peers in a star topology. The underlying algorithm is based on the JF-DKG (fig 1.) a variant on Pedersens DKG from the paper "Secure Distributed Key Generation for Discrete-Log Based Cryptosystems" by R. Gennaro, S. Jarecki, H. Krawczyk, and T. Rabin. */ FILE* log_file=NULL; #define tpdkg_freshness_TIMEOUT 120000 #define tpdkg_msg1_SIZE (sizeof(TP_DKG_Message)) #define tpdkg_msg2_SIZE (sizeof(TP_DKG_Message) + crypto_sign_PUBLICKEYBYTES + crypto_scalarmult_BYTES) #define noise_xk_handshake1_SIZE 48UL #define tpdkg_msg4_SIZE (sizeof(TP_DKG_Message) + noise_xk_handshake1_SIZE) #define noise_xk_handshake2_SIZE 48UL #define tpdkg_msg5_SIZE (sizeof(TP_DKG_Message) + noise_xk_handshake2_SIZE) #define tpdkg_msg6_SIZE(ctx) (sizeof(TP_DKG_Message) + (size_t)(crypto_core_ristretto255_BYTES * ctx->t) ) #define tpdkg_msg9_SIZE(ctx) (sizeof(TP_DKG_Message) + (size_t)(ctx->n + 1) ) #define tpdkg_msg10_SIZE(ctx) (sizeof(TP_DKG_Message) + (size_t)(ctx->n * tpdkg_msg9_SIZE(ctx)) ) #define tpdkg_msg19_SIZE (sizeof(TP_DKG_Message) + crypto_generichash_BYTES) #define tpdkg_msg20_SIZE (sizeof(TP_DKG_Message) + 2) #define tpdkg_msg21_SIZE (sizeof(TP_DKG_Message) + 2) #define tpdkg_noise_key_SIZE (32UL) // todo merge with dump from utils.c static void dump(const uint8_t *p, const size_t len, const char* msg, ...) { if(log_file==NULL) return; va_list args; va_start(args, msg); vfprintf(log_file, msg, args); va_end(args); fprintf(log_file," "); for(size_t i=0;i> 32)); #endif } #endif // htonll #ifndef ntohll static uint64_t ntohll(uint64_t n) { #if __BYTE_ORDER == __BIG_ENDIAN return n; #else return (((uint64_t)ntohl((uint32_t)n)) << 32) + ntohl((uint32_t)(n >> 32)); #endif } #endif // ntohll static int check_ts(const uint64_t ts_epsilon, uint64_t *last_ts, const uint64_t ts) { if(*last_ts == 0) { uint64_t now = (uint64_t)time(NULL); if(ts < now - ts_epsilon) return 3; if(ts > now + ts_epsilon) return 4; } else { if(*last_ts > ts) return 1; if(ts > *last_ts + ts_epsilon) return 2; } *last_ts = ts; return 0; } static int send_msg(uint8_t* msg_buf, const size_t msg_buf_len, const uint8_t msgno, const uint8_t from, const uint8_t to, const uint8_t *sig_sk, const uint8_t sessionid[tpdkg_sessionid_SIZE]) { if(msg_buf==NULL) return 1; TP_DKG_Message* msg = (TP_DKG_Message*) msg_buf; msg->len = htonl((uint32_t)msg_buf_len); msg->msgno = msgno; msg->from = from; msg->to = to; msg->ts = htonll((uint64_t)time(NULL)); memcpy(msg->sessionid, sessionid, tpdkg_sessionid_SIZE); crypto_sign_detached(msg->sig, NULL, &msg->msgno, sizeof(TP_DKG_Message) - crypto_sign_BYTES, sig_sk); return 0; } static int recv_msg(const uint8_t *msg_buf, const size_t msg_buf_len, const uint8_t msgno, const uint8_t from, const uint8_t to, const uint8_t *sig_pk, const uint8_t sessionid[tpdkg_sessionid_SIZE], const uint64_t ts_epsilon, uint64_t *last_ts ) { if(msg_buf==NULL) return 7; TP_DKG_Message* msg = (TP_DKG_Message*) msg_buf; if(ntohl(msg->len) != msg_buf_len) return 1; if(msg->msgno != msgno) return 2; if(msg->from != from) return 3; if(msg->to != to) return 4; if(sodium_memcmp(msg->sessionid, sessionid, tpdkg_sessionid_SIZE)!=0) return 7; #if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) int ret = check_ts(ts_epsilon, last_ts, ntohll(msg->ts)); if(0!=ret) { if(log_file!=NULL) { fprintf(log_file, "checkts fail: %d, last_ts: %ld, ts: %ld, lt+e: %ld\n", ret, *last_ts, ntohll(msg->ts),*last_ts + ts_epsilon); } return 5; } #endif const size_t unsigned_buf_len = msg_buf_len - crypto_sign_BYTES; uint8_t with_sessionid[unsigned_buf_len + tpdkg_sessionid_SIZE]; memcpy(with_sessionid, msg_buf + crypto_sign_BYTES, unsigned_buf_len); memcpy(with_sessionid + unsigned_buf_len, sessionid, tpdkg_sessionid_SIZE); #if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) if(0!=crypto_sign_verify_detached(msg->sig, &msg->msgno, sizeof(TP_DKG_Message) - crypto_sign_BYTES, sig_pk)) return 6; #endif return 0; } static int tpdkg_init_noise_handshake(TP_DKG_PeerState *ctx, uint8_t rpk[crypto_scalarmult_BYTES], uint8_t *rname, Noise_XK_session_t** session, uint8_t msg[noise_xk_handshake1_SIZE]) { if(log_file != NULL) fprintf(log_file, "[%d] creating noise session -> %s\n", ctx->index, rname); // fixme: damnit this allocates stuff on the heap... Noise_XK_peer_t *peer = Noise_XK_device_add_peer(ctx->dev, rname, rpk); if(!peer) return 1; uint32_t peer_id = Noise_XK_peer_get_id(peer); *session = Noise_XK_session_create_initiator(ctx->dev, peer_id); if(!*session) return 2; Noise_XK_encap_message_t *encap_msg = Noise_XK_pack_message_with_conf_level(NOISE_XK_CONF_ZERO, 0, NULL); uint32_t cipher_msg_len; uint8_t *cipher_msg; Noise_XK_rcode ret = Noise_XK_session_write(encap_msg, *session, &cipher_msg_len, &cipher_msg); Noise_XK_encap_message_p_free(encap_msg); if(!Noise_XK_rcode_is_success(ret)) { Noise_XK_session_free(*session); return 3; } if(cipher_msg_len!=noise_xk_handshake1_SIZE) { Noise_XK_session_free(*session); free(cipher_msg); return 4; } if(msg==NULL) return 5; memcpy(msg,cipher_msg,cipher_msg_len); free(cipher_msg); return 0; } static int tpdkg_respond_noise_handshake(TP_DKG_PeerState *ctx, uint8_t rpk[crypto_scalarmult_BYTES], uint8_t *rname, Noise_XK_session_t** session, uint8_t inmsg[noise_xk_handshake1_SIZE], uint8_t outmsg[noise_xk_handshake2_SIZE]) { if(log_file != NULL) fprintf(log_file, "[%d] responding noise session -> %s\n", ctx->index, rname); // fixme: damnit this allocates stuff on the heap... *session = Noise_XK_session_create_responder(ctx->dev); if(!*session) return 1; Noise_XK_encap_message_t *encap_msg; Noise_XK_rcode ret = Noise_XK_session_read(&encap_msg, *session, noise_xk_handshake1_SIZE, inmsg); if(!Noise_XK_rcode_is_success(ret)) { Noise_XK_session_free(*session); return 2; } uint32_t plain_msg_len; uint8_t *plain_msg; if(!Noise_XK_unpack_message_with_auth_level(&plain_msg_len, &plain_msg, NOISE_XK_AUTH_ZERO, encap_msg)) { Noise_XK_session_free(*session); return 3; } Noise_XK_encap_message_p_free(encap_msg); encap_msg = Noise_XK_pack_message_with_conf_level(NOISE_XK_CONF_ZERO, 0, NULL); uint32_t cipher_msg_len; uint8_t *cipher_msg; ret = Noise_XK_session_write(encap_msg, *session, &cipher_msg_len, &cipher_msg); Noise_XK_encap_message_p_free(encap_msg); if(!Noise_XK_rcode_is_success(ret)) { Noise_XK_session_free(*session); return 4; } if(cipher_msg_len!=noise_xk_handshake2_SIZE) { Noise_XK_session_free(*session); free(cipher_msg); return 4; } if(outmsg==NULL) return 5; memcpy(outmsg,cipher_msg,cipher_msg_len); free(cipher_msg); return 0; } static int tpdkg_finish_noise_handshake(TP_DKG_PeerState *ctx, Noise_XK_session_t** session, uint8_t msg[noise_xk_handshake2_SIZE]) { if(!*session) { return 1; } if(log_file!=NULL) { // get peer name uint32_t peer_id = Noise_XK_session_get_peer_id(*session); Noise_XK_peer_t *peer = Noise_XK_device_lookup_peer_by_id(ctx->dev, peer_id); if(peer==NULL) { Noise_XK_session_free(*session); return 2; } uint8_t *pinfo; Noise_XK_peer_get_info((Noise_XK_noise_string*) &pinfo, peer); if(pinfo==NULL) { Noise_XK_session_free(*session); return 3; } fprintf(log_file, "[%d] finishing noise session -> %s\n", ctx->index, pinfo); free(pinfo); } Noise_XK_encap_message_t *encap_msg; Noise_XK_rcode ret = Noise_XK_session_read(&encap_msg, *session, noise_xk_handshake2_SIZE, msg); if(!Noise_XK_rcode_is_success(ret)) { if(log_file!=NULL) fprintf(log_file, "session read fail: %d\n", ret.val.case_Error); Noise_XK_session_free(*session); return 4; } uint32_t plain_msg_len; uint8_t *plain_msg; if(!Noise_XK_unpack_message_with_auth_level(&plain_msg_len, &plain_msg, NOISE_XK_AUTH_ZERO, encap_msg)) { Noise_XK_session_free(*session); return 5; } Noise_XK_encap_message_p_free(encap_msg); return 0; } static int tpdkg_noise_encrypt(uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len, Noise_XK_session_t** session) { if(!*session) { return 1; } if(input_len > 1024) { return 2; } Noise_XK_encap_message_t *encap_msg = Noise_XK_pack_message_with_conf_level(NOISE_XK_CONF_STRONG_FORWARD_SECRECY, (uint32_t) input_len, input); uint32_t cipher_msg_len; uint8_t *cipher_msg; Noise_XK_rcode ret = Noise_XK_session_write(encap_msg, *session, &cipher_msg_len, &cipher_msg); Noise_XK_encap_message_p_free(encap_msg); if(!Noise_XK_rcode_is_success(ret)) { return 3; } if(cipher_msg_len!=output_len) { if(cipher_msg!=NULL) free(cipher_msg); return 4; } if(output == NULL) return 5; if(cipher_msg==NULL) return 6; memcpy(output,cipher_msg,cipher_msg_len); free(cipher_msg); return 0; } static int tpdkg_noise_decrypt(uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len, Noise_XK_session_t** session) { if(*session==NULL) { return 1; } if(input_len > 1024) { return 2; } Noise_XK_encap_message_t *encap_msg; Noise_XK_rcode ret = Noise_XK_session_read(&encap_msg, *session, (uint32_t) input_len, input); if(!Noise_XK_rcode_is_success(ret)) { if(log_file!=NULL) fprintf(log_file, "session read fail: %d\n", ret.val.case_Error); return 3; } uint32_t plain_msg_len; uint8_t *plain_msg=NULL; if(!Noise_XK_unpack_message_with_auth_level(&plain_msg_len, &plain_msg, NOISE_XK_AUTH_KNOWN_SENDER_NO_KCI, encap_msg)) { return 4; } Noise_XK_encap_message_p_free(encap_msg); if(plain_msg_len!=output_len) { if(plain_msg!=NULL) free(plain_msg); return 5; } if(plain_msg!=NULL) { if(output == NULL) return 6; memcpy(output,plain_msg,plain_msg_len); free(plain_msg); } return 0; } /** Return the session unique send key, needed for tp-dkg reveal share. */ static uint8_t* Noise_XK_session_get_key(Noise_XK_session_t *sn) { Noise_XK_session_t st = sn[0U]; if (st.tag == Noise_XK_DS_Initiator && st.val.case_DS_Initiator.state.tag == Noise_XK_IMS_Transport) return st.val.case_DS_Initiator.state.val.case_IMS_Transport.send_key; if (st.tag == Noise_XK_DS_Responder && st.val.case_DS_Responder.state.tag == Noise_XK_IMS_Transport) return st.val.case_DS_Responder.state.val.case_IMS_Transport.receive_key; return NULL; } size_t tpdkg_peerstate_size(void) { return sizeof(TP_DKG_PeerState); } uint8_t tpdkg_peerstate_n(TP_DKG_PeerState *ctx) { return ctx->n; } uint8_t tpdkg_peerstate_t(TP_DKG_PeerState *ctx) { return ctx->t; } uint8_t* tpdkg_peerstate_sessionid(TP_DKG_PeerState *ctx) { return ctx->sessionid; } uint8_t* tpdkg_peerstate_lt_sk(TP_DKG_PeerState *ctx) { return ctx->lt_sk; } uint8_t* tpdkg_peerstate_share(TP_DKG_PeerState *ctx) { return (uint8_t*) &ctx->share; } int tpdkg_peerstate_step(TP_DKG_PeerState *ctx) { return ctx->step; } size_t tpdkg_tpstate_size(void) { return sizeof(TP_DKG_TPState); } uint8_t tpdkg_tpstate_n(TP_DKG_TPState *ctx) { return ctx->n; } uint8_t tpdkg_tpstate_t(TP_DKG_TPState *ctx) { return ctx->t; } size_t tpdkg_tpstate_cheater_len(TP_DKG_TPState *ctx) { return ctx->cheater_len; } uint8_t* tpdkg_tpstate_sessionid(TP_DKG_TPState *ctx) { return ctx->sessionid; } int tpdkg_tpstate_step(TP_DKG_TPState *ctx) { return ctx->step; } static TP_DKG_Cheater* add_cheater(TP_DKG_TPState *ctx, const int step, const int error, const uint8_t peer, const uint8_t other_peer) { if(ctx->cheater_len >= ctx->cheater_max) return NULL; TP_DKG_Cheater *cheater = &(*ctx->cheaters)[ctx->cheater_len++]; cheater->step = step; cheater->error = error; cheater->peer = peer; cheater->other_peer=other_peer; return cheater; } static void update_transcript(crypto_generichash_state *transcript, const uint8_t *msg, const size_t msg_len) { uint32_t msg_size_32b = htonl((uint32_t)msg_len); crypto_generichash_update(transcript, (uint8_t*) &msg_size_32b, sizeof(msg_size_32b)); crypto_generichash_update(transcript, (uint8_t*) msg, msg_len); } size_t tpdkg_tp_input_size(const TP_DKG_TPState *ctx) { size_t sizes[ctx->n]; //memset(sizes,0,sizeof sizes); if(tpdkg_tp_input_sizes(ctx, sizes) == 1) { return sizes[0] * ctx->n; } else { size_t result=0; for(int i=0;in;i++) result+=sizes[i]; return result; } } int tpdkg_tp_input_sizes(const TP_DKG_TPState *ctx, size_t *sizes) { size_t item=0; switch(ctx->step) { case 0: { item=0; break; } case 1: { item=(tpdkg_msg2_SIZE + crypto_sign_BYTES); break; } case 2: { item=tpdkg_msg4_SIZE * ctx->n; break; } case 3: { item=tpdkg_msg4_SIZE * ctx->n; break; } case 4: { item=tpdkg_msg6_SIZE(ctx); break; } case 5: { item=ctx->n * tpdkg_msg8_SIZE; break; } case 6: { item=tpdkg_msg9_SIZE(ctx); break; } case 7: { uint8_t ctr[ctx->n]; memset(ctr,0,ctx->n); for(int i=0;icomplaints_len;i++) ctr[((*ctx->complaints)[i] & 0xff) - 1]++; for(int i=0;in;i++) { if(ctr[i]>0) { sizes[i]=sizeof(TP_DKG_Message) + (1+tpdkg_noise_key_SIZE) * ctr[i]; } else { sizes[i]=0; } } return 0; } case 8: { item=tpdkg_msg19_SIZE; break; } case 9: { item=tpdkg_msg21_SIZE; break; } default: { if(log_file!=NULL) fprintf(log_file, "[!] invalid tp step\n"); } } for(uint8_t i=0;in;i++) { sizes[i] = item; } return 1; } size_t tpdkg_tp_output_size(const TP_DKG_TPState *ctx) { switch(ctx->step) { case 0: return ctx->n*tpdkg_msg1_SIZE; case 1: return tpdkg_msg2_SIZE * ctx->n + sizeof(TP_DKG_Message); case 2: return tpdkg_msg4_SIZE * ctx->n * ctx->n; case 3: return tpdkg_msg5_SIZE * ctx->n * ctx->n; case 4: return sizeof(TP_DKG_Message) + (tpdkg_msg6_SIZE(ctx) * ctx->n); case 5: return ctx->n * ctx->n * tpdkg_msg8_SIZE; case 6: return tpdkg_msg10_SIZE(ctx); case 7: return 0; case 8: return tpdkg_msg20_SIZE; case 9: return 0; default: if(log_file!=NULL) fprintf(log_file, "[!] invalid tp step\n"); } return 0; } int tpdkg_tp_peer_msg(const TP_DKG_TPState *ctx, const uint8_t *base, const size_t base_size, const uint8_t peer, const uint8_t **msg, size_t *len) { if(peer>=ctx->n || peer < 0) return -1; switch(ctx->prev) { case 0: { *msg = base + peer*tpdkg_msg1_SIZE; *len = tpdkg_msg1_SIZE; break; } case 1: { *msg = base; *len = tpdkg_msg2_SIZE * ctx->n + sizeof(TP_DKG_Message); break; } case 2: { *msg = base + peer * tpdkg_msg4_SIZE * ctx->n; *len = tpdkg_msg4_SIZE * ctx->n; break; } case 3: { *msg = base + peer * tpdkg_msg5_SIZE * ctx->n; *len = tpdkg_msg5_SIZE * ctx->n; break; } case 4: { *msg = base; *len = sizeof(TP_DKG_Message) + (tpdkg_msg6_SIZE(ctx) * ctx->n); break; } case 5: { *msg = base + peer * ctx->n * tpdkg_msg8_SIZE; *len = ctx->n * tpdkg_msg8_SIZE; break; } case 6: { *msg = base; *len = tpdkg_msg10_SIZE(ctx); break; } case 7: { *len = 0; *msg = NULL; break; } case 8: { *msg = base; *len = tpdkg_msg20_SIZE; break; } case 9: { *len = 0; *msg = NULL; break; } default: { if(log_file!=NULL) fprintf(log_file, "[!] invalid tp step in tpdkg_tp_peer_msg\n"); return 1; } } if(base+base_size < *msg + *len) { if(log_file!=NULL) fprintf(log_file, "buffer overread detected in tpdkg_tp_peer_msg %ld\n", (base+base_size) - (*msg + *len)); return 2; } return 0; } size_t tpdkg_peer_input_size(const TP_DKG_PeerState *ctx) { switch(ctx->step) { case 0: return tpdkg_msg1_SIZE; case 1: return tpdkg_msg2_SIZE * ctx->n + sizeof(TP_DKG_Message); case 2: return tpdkg_msg4_SIZE * ctx->n; case 3: return tpdkg_msg5_SIZE * ctx->n; case 4: return sizeof(TP_DKG_Message) + (tpdkg_msg6_SIZE(ctx) * ctx->n); case 5: return ctx->n * tpdkg_msg8_SIZE; case 6: return tpdkg_msg10_SIZE(ctx); case 7: return 0; case 8: return 0; case 9: return tpdkg_msg20_SIZE; case 10: return 0; default: { if(log_file!=NULL) fprintf(log_file, "[%d] invalid step\n", ctx->index); } } return 1; } size_t tpdkg_peer_output_size(const TP_DKG_PeerState *ctx) { switch(ctx->step) { case 0: return tpdkg_msg2_SIZE+crypto_sign_BYTES; case 1: return tpdkg_msg4_SIZE * ctx->n; case 2: return tpdkg_msg5_SIZE * ctx->n; case 3: return tpdkg_msg6_SIZE(ctx); case 4: return ctx->n * tpdkg_msg8_SIZE; case 5: return tpdkg_msg9_SIZE(ctx); case 6: return 0; case 7: { if(ctx->complaints_len > 0) { if(ctx->my_complaints_len > 0) { return sizeof(TP_DKG_Message) + ctx->my_complaints_len * (1+tpdkg_noise_key_SIZE); } return 0; } return tpdkg_msg19_SIZE; } case 8: return tpdkg_msg19_SIZE; case 9: return tpdkg_msg21_SIZE; case 10: return 0; default: { if(log_file!=NULL) fprintf(log_file, "[%d] invalid step\n", ctx->index); } } return 1; } void tpdkg_peer_set_bufs(TP_DKG_PeerState *ctx, uint8_t (*peers_sig_pks)[][crypto_sign_PUBLICKEYBYTES], uint8_t (*peers_noise_pks)[][crypto_scalarmult_BYTES], Noise_XK_session_t *(*noise_outs)[], Noise_XK_session_t *(*noise_ins)[], TOPRF_Share (*shares)[], TOPRF_Share (*xshares)[], uint8_t (*commitments)[][crypto_core_ristretto255_BYTES], uint16_t *complaints, uint8_t *my_complaints, uint64_t *last_ts) { ctx->peer_sig_pks = peers_sig_pks; ctx->peer_noise_pks = peers_noise_pks; ctx->noise_outs = noise_outs; ctx->noise_ins = noise_ins; ctx->shares = shares; ctx->xshares = xshares; ctx->commitments = commitments; ctx->complaints = complaints; ctx->my_complaints = my_complaints; ctx->last_ts = last_ts; for(uint8_t i=0;in;i++) ctx->last_ts[i]=0; } int tpdkg_tp_not_done(const TP_DKG_TPState *tp) { return tp->step<10; } int tpdkg_peer_not_done(const TP_DKG_PeerState *peer) { return peer->step<11; } void tpdkg_peer_free(TP_DKG_PeerState *ctx) { for(int i=0;in;i++) { if((*ctx->noise_ins)[i]!=NULL) Noise_XK_session_free((*ctx->noise_ins)[i]); if((*ctx->noise_outs)[i]!=NULL) Noise_XK_session_free((*ctx->noise_outs)[i]); } if(ctx->dev!=NULL) Noise_XK_device_free(ctx->dev); } void tpdkg_tp_set_bufs(TP_DKG_TPState *ctx, uint8_t (*commitments)[][crypto_core_ristretto255_BYTES], uint16_t (*complaints)[], uint8_t (*encrypted_shares)[][tpdkg_msg8_SIZE], TP_DKG_Cheater (*cheaters)[], const size_t cheater_max, uint8_t (*tp_peers_sig_pks)[][crypto_sign_PUBLICKEYBYTES], uint8_t (*peer_lt_pks)[][crypto_sign_PUBLICKEYBYTES], uint64_t *last_ts) { ctx->commitments = (uint8_t (*)[][crypto_core_ristretto255_BYTES]) commitments; ctx->complaints = complaints; ctx->encrypted_shares = encrypted_shares; ctx->cheaters = cheaters; memset(*cheaters, 0, cheater_max*sizeof(TP_DKG_Cheater)); ctx->cheater_max = cheater_max; ctx->peer_sig_pks = tp_peers_sig_pks; ctx->peer_lt_pks = peer_lt_pks; ctx->last_ts = last_ts; uint64_t now = (uint64_t)time(NULL); for(uint8_t i=0;in;i++) ctx->last_ts[i]=now; } int tpdkg_start_tp(TP_DKG_TPState *ctx, const uint64_t ts_epsilon, const uint8_t n, const uint8_t t, const char *proto_name, const size_t proto_name_len, const size_t msg0_len, TP_DKG_Message *msg0) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[!] step 0. start protocol\e[0m\n"); if(2>n || t>=n || n>128) return 1; if(proto_name_len<1) return 2; if(proto_name_len>1024) return 3; if(msg0_len != tpdkg_msg0_SIZE) return 4; ctx->ts_epsilon = ts_epsilon; ctx->step = 0; ctx->n = n; ctx->t = t; ctx->complaints_len = 0; ctx->cheater_len = 0; // dst hash(len(protoname) | "DKG for protocol " | protoname) crypto_generichash_state dst_state; crypto_generichash_init(&dst_state, NULL, 0, crypto_generichash_BYTES); uint16_t len=htons((uint16_t) proto_name_len+20); // we have a guard above restricting to 1KB the proto_name_len crypto_generichash_update(&dst_state, (uint8_t*) &len, 2); crypto_generichash_update(&dst_state, (uint8_t*) "TP DKG for protocol ", 20); crypto_generichash_update(&dst_state, (uint8_t*) proto_name, proto_name_len); uint8_t dst[crypto_generichash_BYTES]; crypto_generichash_final(&dst_state,dst,sizeof dst); // set session id randombytes_buf(&ctx->sessionid, sizeof ctx->sessionid); // generate signing key for this session crypto_sign_keypair(ctx->sig_pk, ctx->sig_sk); // data = {tp_sign_pk, dst, sessionid, n, t} uint8_t *ptr = msg0->data; memcpy(ptr, ctx->sig_pk, sizeof ctx->sig_pk); ptr+=sizeof ctx->sig_pk; memcpy(ptr, dst, sizeof dst); ptr+=sizeof dst; *ptr++ = n; *ptr++ = t; if(0!=send_msg((uint8_t*) msg0, tpdkg_msg0_SIZE, 0, 0, 0xff, ctx->sig_sk, ctx->sessionid)) return 5; // init transcript crypto_generichash_init(&ctx->transcript, NULL, 0, crypto_generichash_BYTES); crypto_generichash_update(&ctx->transcript, (uint8_t*) "tp dkg session transcript", 25); // feed msg0 into transcript update_transcript(&ctx->transcript, (uint8_t*) msg0, msg0_len); if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: 0x%x ", msg0->msgno, msg0->from, msg0->to); dump((uint8_t*) msg0, tpdkg_msg0_SIZE, "msg"); } return 0; } int tpdkg_start_peer(TP_DKG_PeerState *ctx, const uint64_t ts_epsilon, const uint8_t peer_lt_sk[crypto_sign_SECRETKEYBYTES], const TP_DKG_Message *msg0) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[?] step 0.5 start peer\e[0m\n"); if(log_file!=NULL) { fprintf(log_file,"[?] msgno: %d, from: %d to: 0x%x ", msg0->msgno, msg0->from, msg0->to); dump((uint8_t*) msg0, tpdkg_msg0_SIZE, "msg"); } ctx->ts_epsilon = ts_epsilon; ctx->tp_last_ts = 0; int ret = recv_msg((uint8_t*) msg0, tpdkg_msg0_SIZE, 0, 0, 0xff, msg0->data, msg0->sessionid, ts_epsilon, &ctx->tp_last_ts); if(0!=ret) return 64 + ret; // extract data from message memcpy(ctx->sessionid, msg0->sessionid, sizeof ctx->sessionid); const uint8_t *ptr=msg0->data; memcpy(ctx->tp_sig_pk,ptr,sizeof ctx->tp_sig_pk); ptr+=sizeof ctx->tp_sig_pk + crypto_generichash_BYTES; // also skip DST ctx->n = *ptr++; ctx->t = *ptr++; if(ctx->t < 2) return 1; if(ctx->t >= ctx->n) return 2; if(ctx->n > 128) return 3; ctx->complaints_len = 0; ctx->my_complaints_len = 0; memcpy(ctx->lt_sk, peer_lt_sk, crypto_sign_SECRETKEYBYTES); crypto_generichash_init(&ctx->transcript, NULL, 0, crypto_generichash_BYTES); crypto_generichash_update(&ctx->transcript, (uint8_t*) "tp dkg session transcript", 25); // feed msg0 into transcript update_transcript(&ctx->transcript, (uint8_t*) msg0, tpdkg_msg0_SIZE); ctx->dev = NULL; ctx->step = 0; return 0; } static int tp_step1_handler(TP_DKG_TPState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[!] step 1. assign peer indices\e[0m\n"); if(input_len!=0) return 1; if(output_len!=ctx->n * tpdkg_msg1_SIZE) return 2; uint8_t* ptr = output; for(uint8_t i=1;i<=ctx->n;i++,ptr+=tpdkg_msg1_SIZE) { if(0!=send_msg(ptr, sizeof(TP_DKG_Message), 1, 0, i, ctx->sig_sk, ctx->sessionid)) return 3; if(log_file!=NULL) { TP_DKG_Message *msg1 = (TP_DKG_Message*) ptr; fprintf(log_file,"[!] msgno: %d, len: %d, from: %d to: %x ", msg1->msgno, htonl(msg1->len), msg1->from, msg1->to); dump(ptr, tpdkg_msg1_SIZE, "msg"); } } return 0; } static int peer_step23_handler(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[?] step 2. receive peers index\e[0m\n"); if(input_len != tpdkg_msg1_SIZE) return 1; if(output_len != tpdkg_msg2_SIZE+crypto_sign_BYTES) return 2; TP_DKG_Message *msg1=(TP_DKG_Message*) input; if(log_file!=NULL) { fprintf(log_file,"[?] msgno: %d, len: %d, from: %d to: %x ", msg1->msgno, ntohl(msg1->len), msg1->from, msg1->to); dump(input, tpdkg_msg1_SIZE, "msg"); } int ret = recv_msg(input, tpdkg_msg1_SIZE, 1, 0, msg1->to, ctx->tp_sig_pk, ctx->sessionid, ctx->ts_epsilon, &ctx->tp_last_ts); if(0!=ret) return 4 + ret; if(msg1->to > 128 || msg1->to < 1) return 3; ctx->index=msg1->to; if(log_file!=NULL) fprintf(log_file, "\e[0;33m[%d] step 3. send msg2 containing ephemeral pubkey\e[0m\n", ctx->index); crypto_sign_keypair(ctx->sig_pk, ctx->sig_sk); randombytes_buf(ctx->noise_sk, sizeof ctx->noise_sk); crypto_scalarmult_base(ctx->noise_pk, ctx->noise_sk); uint8_t *wptr = ((TP_DKG_Message *) output)->data; memcpy(wptr, ctx->sig_pk, sizeof ctx->sig_pk); wptr+=sizeof ctx->sig_pk; memcpy(wptr, ctx->noise_pk, sizeof ctx->noise_pk); if(0!=send_msg(output, tpdkg_msg2_SIZE, 2, ctx->index, 0xff, ctx->sig_sk, ctx->sessionid)) return 4; // sign message with long-term key crypto_sign_detached(output+tpdkg_msg2_SIZE,NULL,output,tpdkg_msg2_SIZE,ctx->lt_sk); sodium_memzero(ctx->lt_sk,crypto_sign_SECRETKEYBYTES); if(log_file!=NULL) { TP_DKG_Message *msg2 = (TP_DKG_Message *) output; fprintf(log_file,"[%d] msgno: %d, len: %d, from: %d to: %x ", ctx->index, msg2->msgno, ntohl(msg2->len), msg2->from, msg2->to); dump(output, tpdkg_msg2_SIZE+crypto_sign_BYTES, "msg"); } return 0; } static int tp_step4_handler(TP_DKG_TPState *ctx, const uint8_t *msg2s, const size_t msg2s_len, uint8_t *msg3_buf, const size_t msg3_buf_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[!] step 4. broadcast msg2 containing ephemeral pubkeys of peers\e[0m\n"); if(((tpdkg_msg2_SIZE + crypto_sign_BYTES) * ctx->n) != msg2s_len) return 1; if(msg3_buf_len != (tpdkg_msg2_SIZE * ctx->n) + sizeof(TP_DKG_Message)) return 2; const uint8_t *ptr = msg2s; uint8_t *wptr = ((TP_DKG_Message *) msg3_buf)->data; for(uint8_t i=0;in;i++,ptr+=tpdkg_msg2_SIZE+crypto_sign_BYTES) { const TP_DKG_Message* msg = (const TP_DKG_Message*) ptr; // verify long-term pk sig on initial message if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: %x ", msg->msgno, msg->from, msg->to); dump(ptr, tpdkg_msg2_SIZE, "msg"); } #if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) if(0!=crypto_sign_verify_detached(ptr+tpdkg_msg2_SIZE,ptr,tpdkg_msg2_SIZE,(*ctx->peer_lt_pks)[i])) return 3; #endif int ret = recv_msg(ptr, tpdkg_msg2_SIZE, 2, i+1, 0xff, msg->data, ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i]); if(0!=ret) { if(add_cheater(ctx, 4, 64+ret, i+1,0xff) == NULL) return 7; continue; } // keep copy of ephemeral signing key memcpy((*ctx->peer_sig_pks)[i], msg->data, crypto_sign_PUBLICKEYBYTES); // strip away long-term signature memcpy(wptr, ptr, tpdkg_msg2_SIZE); wptr+=tpdkg_msg2_SIZE; } if(ctx->cheater_len>0) return 6; if(0!=send_msg(msg3_buf, msg3_buf_len, 3, 0, 0xff, ctx->sig_sk, ctx->sessionid)) return 5; update_transcript(&ctx->transcript, (uint8_t*) msg3_buf, msg3_buf_len); return 0; } static int peer_step5_handler(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[%d] step 5. receive peers ephemeral pubkeys, start noise sessions\e[0m\n", ctx->index); if(input_len != tpdkg_msg2_SIZE * ctx->n + sizeof(TP_DKG_Message)) return 1; if(output_len != tpdkg_msg4_SIZE * ctx->n) return 2; int ret = recv_msg(input, input_len, 3, 0, 0xff, ctx->tp_sig_pk, ctx->sessionid, ctx->ts_epsilon, &ctx->tp_last_ts); if(0!=ret) return 32+ret; update_transcript(&ctx->transcript, input, input_len); // create noise device uint8_t iname[13]; snprintf((char*) iname, sizeof iname, "dkg peer %02x", ctx->index); uint8_t dummy[32]={0}; // the following function needs a deserialization key, which we never use. ctx->dev = Noise_XK_device_create(13, (uint8_t*) "dpkg p2p v0.1", iname, dummy, ctx->noise_sk); TP_DKG_Message* msg3 = (TP_DKG_Message*) input; const uint8_t *ptr = msg3->data; uint8_t *wptr = output; for(uint8_t i=0;in;i++) { TP_DKG_Message* msg2 = (TP_DKG_Message*) ptr; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %x ", ctx->index, msg2->msgno, msg2->from, msg2->to); dump(ptr, tpdkg_msg2_SIZE, "msg"); } ret = recv_msg(ptr, tpdkg_msg2_SIZE, 2, i+1, 0xff, msg2->data, ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i]); if(0!=ret) return 64+ret; // extract peer sig and noise pk memcpy((*ctx->peer_sig_pks)[i], msg2->data, crypto_sign_PUBLICKEYBYTES); memcpy((*ctx->peer_noise_pks)[i], msg2->data + crypto_sign_PUBLICKEYBYTES, crypto_scalarmult_BYTES); ptr+=tpdkg_msg2_SIZE; TP_DKG_Message *msg4 = (TP_DKG_Message *) wptr; uint8_t rname[13]; snprintf((char*) rname, sizeof rname, "dkg peer %02x", i+1); tpdkg_init_noise_handshake(ctx, (*ctx->peer_noise_pks)[i], rname, &(*ctx->noise_outs)[i], msg4->data); if(0!=send_msg(wptr, tpdkg_msg4_SIZE, 4, ctx->index, i+1, ctx->sig_sk, ctx->sessionid)) return 5; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %d ", ctx->index, msg4->msgno, msg4->from, msg4->to); dump(wptr, tpdkg_msg4_SIZE, "msg"); } wptr+=tpdkg_msg4_SIZE; } return 0; } static int tp_step68_handler(TP_DKG_TPState *ctx, const uint8_t *msg4s, const size_t msg4s_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[!] step %d. route p2p noise handshakes to peers\e[0m\n", 6 + (ctx->step - 1) * 2); if(msg4s_len != tpdkg_msg4_SIZE * ctx->n * ctx->n) return 1; if(msg4s_len != output_len) return 2; uint8_t (*inputs)[ctx->n][ctx->n][tpdkg_msg4_SIZE] = (uint8_t (*)[ctx->n][ctx->n][tpdkg_msg4_SIZE]) msg4s; uint8_t *wptr = output; for(uint8_t i=0;in;i++) { for(uint8_t j=0;jn;j++) { if(tpdkg_msg4_SIZE != tpdkg_msg5_SIZE) { if(log_file!=NULL) fprintf(log_file, "tpdkg_msg4_SIZE must be equal tpdkg_msg5_SIZE for the check to be correct in tp_step68_handler\n"); return 3; } int ret = recv_msg((*inputs)[j][i], tpdkg_msg4_SIZE, (uint8_t) (2+ctx->step), j+1, i+1, (*ctx->peer_sig_pks)[j], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[j]); if(0!=ret) { if(add_cheater(ctx, 6 + (ctx->step - 1) * 2, 64+ret, j+1, i+1) == NULL) return 7; TP_DKG_Message *msg = (TP_DKG_Message*) (*inputs)[j][i]; fprintf(log_file,"[x] msgno: %d, from: %d to: %d ", msg->msgno, msg->from, msg->to); dump((*inputs)[j][i], tpdkg_msg4_SIZE, "msg"); continue; } memcpy(wptr, (*inputs)[j][i], tpdkg_msg4_SIZE); wptr+=tpdkg_msg4_SIZE; } } if(ctx->cheater_len>0) return 6; return 0; } static int peer_step7_handler(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[%d] step 7. receive session requests\e[0m\n", ctx->index); if(input_len != tpdkg_msg4_SIZE * ctx->n) return 1; if(output_len != tpdkg_msg5_SIZE * ctx->n) return 2; const uint8_t *ptr = input; uint8_t *wptr = output; for(uint8_t i=0;in;i++) { TP_DKG_Message* msg4 = (TP_DKG_Message*) ptr; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %d ", ctx->index, msg4->msgno, msg4->from, msg4->to); dump(ptr, tpdkg_msg4_SIZE, "msg"); } int ret = recv_msg(ptr, tpdkg_msg4_SIZE, 4, i+1, ctx->index, (*ctx->peer_sig_pks)[i], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i]); if(0!=ret) return 64+ret; ptr+=tpdkg_msg4_SIZE; // respond to noise handshake request TP_DKG_Message *msg5 = (TP_DKG_Message *) wptr; uint8_t rname[13]; snprintf((char*) rname, sizeof rname, "dkg peer %02x", i+1); tpdkg_respond_noise_handshake(ctx, (*ctx->peer_noise_pks)[i], rname, &(*ctx->noise_ins)[i], msg4->data, msg5->data); if(0!=send_msg(wptr, tpdkg_msg5_SIZE, 5, ctx->index, i+1, ctx->sig_sk, ctx->sessionid)) return 4; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %d ", ctx->index, msg5->msgno, msg5->from, msg5->to); dump(wptr, tpdkg_msg5_SIZE, "msg"); } wptr+=tpdkg_msg5_SIZE; } return 0; } static int peer_step911_handler(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[%d] step 9-11 finish session handshake, broadcast commitments\e[0m\n", ctx->index); if(input_len != tpdkg_msg5_SIZE * ctx->n) return 1; if(output_len != tpdkg_msg6_SIZE(ctx)) return 2; const uint8_t *ptr = input; for(uint8_t i=0;in;i++) { TP_DKG_Message* msg5 = (TP_DKG_Message*) ptr; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %d ", ctx->index, msg5->msgno, msg5->from, msg5->to); dump(ptr, tpdkg_msg5_SIZE, "msg"); } int ret = recv_msg(ptr, tpdkg_msg5_SIZE, 5, i+1, ctx->index, (*ctx->peer_sig_pks)[i], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i]); if(0!=ret) return 64+ret; ptr+=tpdkg_msg5_SIZE; // process final step of noise handshake tpdkg_finish_noise_handshake(ctx, &(*ctx->noise_outs)[i], msg5->data); } TP_DKG_Message* msg6 = (TP_DKG_Message*) output; if(0!=dkg_start(ctx->n, ctx->t, (uint8_t (*)[32]) msg6->data, *ctx->shares)) return 4; if(0!=send_msg(output, tpdkg_msg6_SIZE(ctx), 6, ctx->index, 0xff, ctx->sig_sk, ctx->sessionid)) return 4; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: 0x%x ", ctx->index, msg6->msgno, msg6->from, msg6->to); dump(output, tpdkg_msg6_SIZE(ctx), "msg"); dump(msg6->data, ctx->t*crypto_core_ristretto255_BYTES, "[%d] commitments", ctx->index); } return 0; } static int tp_step12_handler(TP_DKG_TPState *ctx, const uint8_t *msg6s, const size_t msg6s_len, uint8_t *msg7_buf, const size_t msg7_buf_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[!] step 12. broadcast commitments of peers\e[0m\n"); if((tpdkg_msg6_SIZE(ctx) * ctx->n) != msg6s_len) return 1; if(msg7_buf_len != sizeof(TP_DKG_Message) + msg6s_len) return 2; const uint8_t *ptr = msg6s; uint8_t *wptr = ((TP_DKG_Message *) msg7_buf)->data; for(uint8_t i=0;in;i++,ptr+=tpdkg_msg6_SIZE(ctx)) { const TP_DKG_Message* msg = (const TP_DKG_Message*) ptr; if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: 0x%x ", msg->msgno, msg->from, msg->to); dump(ptr, tpdkg_msg6_SIZE(ctx), "msg"); } int ret = recv_msg(ptr, tpdkg_msg6_SIZE(ctx), 6, i+1, 0xff, (*ctx->peer_sig_pks)[i], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i]); if(0!=ret) { if(add_cheater(ctx, 12, 64+ret, i+1,0xff) == NULL) return 7; continue; } memcpy((*ctx->commitments)[i*ctx->t], msg->data, crypto_core_ristretto255_BYTES * ctx->t); if(log_file!=NULL) { dump((*ctx->commitments)[i*ctx->t], crypto_core_ristretto255_BYTES * ctx->t, "[!] commitments[%d]", i+1); } memcpy(wptr, ptr, tpdkg_msg6_SIZE(ctx)); wptr+=tpdkg_msg6_SIZE(ctx); } if(ctx->cheater_len>0) return 6; if(0!=send_msg(msg7_buf, msg7_buf_len, 7, 0, 0xff, ctx->sig_sk, ctx->sessionid)) return 4; TP_DKG_Message* msg7 = (TP_DKG_Message*) msg7_buf; if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: %x ", msg7->msgno, msg7->from, msg7->to); dump(msg7_buf, msg7_buf_len, "msg"); } // add broadcast msg to transcript update_transcript(&ctx->transcript, (uint8_t*) msg7_buf, msg7_buf_len); return 0; } static int peer_step13_handler(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[%d] step 13. receive commitments, distribute shares via noise chans\e[0m\n", ctx->index); if(input_len != sizeof(TP_DKG_Message) + (tpdkg_msg6_SIZE(ctx) * ctx->n)) return 1; if(output_len != ctx->n * tpdkg_msg8_SIZE) return 2; // verify TP message envelope TP_DKG_Message* msg7 = (TP_DKG_Message*) input; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %x ", ctx->index, msg7->msgno, msg7->from, msg7->to); dump(input, input_len, "msg"); } int ret = recv_msg(input, input_len, 7, 0, 0xff, ctx->tp_sig_pk, ctx->sessionid, ctx->ts_epsilon, &ctx->tp_last_ts); if(0!=ret) return 32+ret; // add broadcast msg to transcript update_transcript(&ctx->transcript, input, input_len); const uint8_t *ptr = msg7->data; uint8_t *wptr = output; for(uint8_t i=0;in;i++, wptr+=tpdkg_msg8_SIZE,ptr+=tpdkg_msg6_SIZE(ctx)) { TP_DKG_Message* msg6 = (TP_DKG_Message*) ptr; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: 0x%x ", ctx->index, msg6->msgno, msg6->from, msg6->to); dump(ptr, tpdkg_msg6_SIZE(ctx), "msg"); } if(0!=recv_msg(ptr, tpdkg_msg6_SIZE(ctx), 6, i+1, 0xff, (*ctx->peer_sig_pks)[i], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i])) return 64+ret; // extract peer commitments memcpy((*ctx->commitments)[i*ctx->t], msg6->data, crypto_core_ristretto255_BYTES * ctx->t); TP_DKG_Message *msg8 = (TP_DKG_Message *) wptr; // we need to send an empty packet, so that the handshake completes // and we have a final symetric key, the key during the handshake changes, only // when the handshake completes does the key become static. // this is important, so that when there are complaints, we can disclose the key. uint8_t empty[0]; if(0!=tpdkg_noise_encrypt(empty, 0, msg8->data, noise_xk_handshake3_SIZE, &(*ctx->noise_outs)[i])) return 5; #ifdef UNITTEST_CORRUPT // corrupt all shares static int corrupted_shares = 0; uint8_t corrupted_share[sizeof(TOPRF_Share)]; memcpy(corrupted_share, &(*ctx->shares)[i], sizeof(TOPRF_Share)); if(i+1 != ctx->index && corrupted_shares++ < ctx->t-1) { dump(corrupted_share, sizeof(TOPRF_Share), "[%d] corrupting share_%d", ctx->index, i+1); corrupted_share[2]^=0xff; // flip some bits dump(corrupted_share, sizeof(TOPRF_Share), "[%d] corrupted share_%d ", ctx->index, i+1); } if(0!=tpdkg_noise_encrypt((uint8_t*) corrupted_share, sizeof(TOPRF_Share), #else if(0!=tpdkg_noise_encrypt((uint8_t*) &(*ctx->shares)[i], sizeof(TOPRF_Share), #endif // UNITTEST_CORRUPT msg8->data + noise_xk_handshake3_SIZE, sizeof(TOPRF_Share) + crypto_secretbox_xchacha20poly1305_MACBYTES, &(*ctx->noise_outs)[i])) return 6; // we also need to use a key-commiting mac over the encrypted share, since poly1305 is not... crypto_auth(msg8->data + noise_xk_handshake3_SIZE + sizeof(TOPRF_Share) + crypto_secretbox_xchacha20poly1305_MACBYTES, msg8->data + noise_xk_handshake3_SIZE, sizeof(TOPRF_Share) + crypto_secretbox_xchacha20poly1305_MACBYTES, Noise_XK_session_get_key((*ctx->noise_outs)[i])); if(0!=send_msg(wptr, tpdkg_msg8_SIZE, 8, ctx->index, i+1, ctx->sig_sk, ctx->sessionid)) return 7; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %d ", ctx->index, msg8->msgno, msg8->from, msg8->to); dump(wptr, tpdkg_msg8_SIZE, "msg"); } } return 0; } static int tp_step14_handler(TP_DKG_TPState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[!] step 14. route shares from all peers to all peers\e[0m\n"); if(input_len != tpdkg_msg8_SIZE * ctx->n * ctx->n) return 1; if(input_len != output_len) return 2; uint8_t (*inputs)[ctx->n][ctx->n][tpdkg_msg8_SIZE] = (uint8_t (*)[ctx->n][ctx->n][tpdkg_msg8_SIZE]) input; uint8_t *wptr = output; for(uint8_t i=0;in;i++) { for(uint8_t j=0;jn;j++) { TP_DKG_Message *msg8 = (TP_DKG_Message *) (*inputs)[j][i]; if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: %d ", msg8->msgno, msg8->from, msg8->to); dump((*inputs)[j][i], tpdkg_msg8_SIZE, "msg"); } int ret = recv_msg((*inputs)[j][i], tpdkg_msg8_SIZE, 8, j+1, i+1, (*ctx->peer_sig_pks)[j], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[j]); if(0!=ret) { if(add_cheater(ctx, 14, 64+ret, j+1, i+1) == NULL) return 7; continue; } memcpy(wptr, (*inputs)[j][i], tpdkg_msg8_SIZE); wptr+=tpdkg_msg8_SIZE; } } if(ctx->cheater_len>0) return 6; // keep a copy for complaint resolution. memcpy((*ctx->encrypted_shares), input, input_len); return 0; } static int peer_step15_handler(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[%d] step 15. DKG step 2 - receive shares, verify commitments\e[0m\n", ctx->index); if(input_len != ctx->n * tpdkg_msg8_SIZE) return 1; if(output_len != tpdkg_msg9_SIZE(ctx)) return 2; const uint8_t *ptr = input; for(uint8_t i=0;in;i++) { TP_DKG_Message* msg8 = (TP_DKG_Message*) ptr; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %d ", ctx->index, msg8->msgno, msg8->from, msg8->to); dump(ptr, tpdkg_msg8_SIZE, "msg"); } int ret = recv_msg(ptr, tpdkg_msg8_SIZE, 8, i+1, ctx->index, (*ctx->peer_sig_pks)[i], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i]); if(0!=ret) return 64+ret; // decrypt final empty handshake packet if(0!=tpdkg_noise_decrypt(msg8->data, noise_xk_handshake3_SIZE, NULL, 0, &(*ctx->noise_ins)[i])) return 4; if(0!=crypto_auth_verify(msg8->data + noise_xk_handshake3_SIZE + sizeof(TOPRF_Share) + crypto_secretbox_xchacha20poly1305_MACBYTES, msg8->data + noise_xk_handshake3_SIZE, sizeof(TOPRF_Share) + crypto_secretbox_xchacha20poly1305_MACBYTES, Noise_XK_session_get_key((*ctx->noise_ins)[i]))) { return 5; } if(0!=tpdkg_noise_decrypt(msg8->data + noise_xk_handshake3_SIZE, sizeof(TOPRF_Share) + crypto_secretbox_xchacha20poly1305_MACBYTES, (uint8_t*) &(*ctx->xshares)[i], sizeof(TOPRF_Share), &(*ctx->noise_ins)[i])) return 6; ptr+=tpdkg_msg8_SIZE; } TP_DKG_Message* msg9 = (TP_DKG_Message*) output; uint8_t *fails_len = msg9->data; uint8_t *fails = msg9->data+1; memset(fails, 0, ctx->n); dkg_verify_commitments(ctx->n, ctx->t, ctx->index, ctx->commitments, *ctx->xshares, fails, fails_len); #ifdef UNITTEST_CORRUPT static int totalfails = 0; for(uint8_t i=1;i<=ctx->n;i++) { if(totalfails < ctx->t - ctx->index && *fails_len < ctx->t-1 && i != ctx->index) { // avoid duplicates int j; for(j=1;j<=msg9->data[0];j++) if(msg9->data[j]==i) break; if(j<=msg9->data[0]) continue; fails[msg9->data[0]++]=i; totalfails++; } } #endif //UNITTEST_CORRUPT if(log_file!=NULL) { for(int j=0;j<*fails_len;j++) { fprintf(log_file,"\e[0;31m[%d] failed to verify commitments from %d!\e[0m\n", ctx->index, fails[j]); } } if(0!=send_msg(output, tpdkg_msg9_SIZE(ctx), 9, ctx->index, 0xff, ctx->sig_sk, ctx->sessionid)) return 7; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %x ", ctx->index, msg9->msgno, msg9->from, msg9->to); dump(output, tpdkg_msg9_SIZE(ctx), "msg"); } return 0; } static int tp_step16_handler(TP_DKG_TPState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[!] step 16. broadcast complaints of peers\e[0m\n"); if((tpdkg_msg9_SIZE(ctx) * ctx->n) != input_len) return 1; if(output_len != tpdkg_msg10_SIZE(ctx)) return 2; ctx->complaints_len = 0; const uint8_t *ptr = input; uint8_t *wptr = ((TP_DKG_Message *) output)->data; for(uint8_t i=0;in;i++, ptr+=tpdkg_msg9_SIZE(ctx)) { const TP_DKG_Message* msg = (const TP_DKG_Message*) ptr; if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: 0x%x ", msg->msgno, msg->from, msg->to); dump(ptr, tpdkg_msg9_SIZE(ctx), "msg"); } int ret = recv_msg(ptr, tpdkg_msg9_SIZE(ctx), 9, i+1, 0xff, (*ctx->peer_sig_pks)[i], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i]); if(0!=ret) { if(add_cheater(ctx, 16, 64+ret, i+1, 0xff) == NULL) return 6; continue; } if(msg->len - sizeof(TP_DKG_Message) < msg->data[0]) return 4; // keep a copy all complaint pairs (complainer, complained) for(int k=0;kdata[0] && (k+1)len-sizeof(TP_DKG_Message);k++) { if(msg->data[k+1] > ctx->n || msg->data[k+1] < 1) { if(add_cheater(ctx, 16, 7, i+1, msg->data[k+1]) == NULL) return 6; continue; } uint16_t pair=(uint16_t) (((i+1)<<8) | msg->data[k+1]); int j=0; for(j=0;jcomplaints_len;j++) if((*ctx->complaints)[j]==pair) break; if(jcomplaints_len) { if(add_cheater(ctx, 16, 8, i+1, msg->data[k+1]) == NULL) return 6; continue; } (*ctx->complaints)[ctx->complaints_len++] = pair; if(log_file!=NULL) { fprintf(log_file,"\e[0;31m[!] peer %d failed to verify commitments from peer %d!\e[0m\n", i+1, msg->data[1+k]); } } memcpy(wptr, ptr, tpdkg_msg9_SIZE(ctx)); wptr+=tpdkg_msg9_SIZE(ctx); } dump((uint8_t*) (*ctx->complaints), ctx->complaints_len*sizeof(uint16_t), "[!] complaints"); // if more than t^2 complaints are received the protocol also fails if(ctx->complaints_len >= ctx->t * ctx->t) { if(add_cheater(ctx, 16, 6, 0xfe, 0xfe) == NULL) return 6; return 5; } if(ctx->cheater_len>0) return 5; if(0!=send_msg(output, output_len, 10, 0, 0xff, ctx->sig_sk, ctx->sessionid)) return 7; TP_DKG_Message* msg10 = (TP_DKG_Message*) output; if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: %x ", msg10->msgno, msg10->from, msg10->to); dump(output, output_len, "msg"); } // add broadcast msg to transcript update_transcript(&ctx->transcript, (uint8_t*) output, output_len); return 0; } static int peer_step17_handler(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[%d] step 17. receive complaints broadcast\e[0m\n", ctx->index); if(input_len != tpdkg_msg10_SIZE(ctx)) return 1; if(output_len !=0) return 2; // verify TP message envelope TP_DKG_Message* msg10 = (TP_DKG_Message*) input; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %x ", ctx->index, msg10->msgno, msg10->from, msg10->to); dump(input, input_len, "msg"); } int ret = recv_msg(input, input_len, 10, 0, 0xff, ctx->tp_sig_pk, ctx->sessionid, ctx->ts_epsilon, &ctx->tp_last_ts); if(0!=ret) return 16+ret; // add broadcast msg to transcript update_transcript(&ctx->transcript, input, input_len); const uint8_t *ptr = msg10->data; for(uint8_t i=0;in;i++) { TP_DKG_Message* msg9 = (TP_DKG_Message*) ptr; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: 0x%x ", ctx->index, msg9->msgno, msg9->from, msg9->to); dump(ptr, tpdkg_msg9_SIZE(ctx), "msg"); } ret = recv_msg(ptr, tpdkg_msg9_SIZE(ctx), 9, i+1, 0xff, (*ctx->peer_sig_pks)[i], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i]); if(0!=ret) return 32+ret; if(msg9->len - sizeof(TP_DKG_Message) < msg9->data[0]) return 5; // keep a copy all complaint pairs (complainer, complained) for(int k=0;kdata[0] && (k+1)len-sizeof(TP_DKG_Message);k++) { uint16_t pair=(uint16_t) (((i+1)<<8) | msg9->data[k+1]); int j=0; for(j=0;jcomplaints_len;j++) if(ctx->complaints[j]==pair) break; if(jcomplaints_len) continue; ctx->complaints[ctx->complaints_len++] = pair; if(msg9->data[k+1] == ctx->index) { ctx->my_complaints[ctx->my_complaints_len++] = i+1; if(log_file!=NULL) fprintf(log_file,"\e[0;31m[%d] peer %d failed to verify commitments from peer %d!\e[0m\n", ctx->index, i+1, msg9->data[1+k]); } } ptr+=tpdkg_msg9_SIZE(ctx); } if(ctx->complaints_len == 0) { ctx->prev = ctx->step; ctx->step+=1; // skip to step 19 } return 0; } static int peer_step17a_handler(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[%d] step 17a. potentially broadcast contested shares\e[0m\n", ctx->index); if(input_len != 0) return 1; if(output_len != tpdkg_peer_output_size(ctx)) return 2; if(output_len == 0) { if(log_file!=NULL) { fprintf(log_file,"[%d] nothing to defend against, no message to send\n", ctx->index); } return 0; } // send out all shares that belong to peers that complained. TP_DKG_Message* msg11 = (TP_DKG_Message*) output; uint8_t *wptr = msg11->data; for(int i=0;imy_complaints_len;i++) { if(log_file!=NULL) fprintf(log_file, "\e[0;36m[%d] defending against complaint from %d\e[0m\n", ctx->index, ctx->my_complaints[i]); *wptr++ = ctx->my_complaints[i]; // reveal key for noise wrapped share sent previously memcpy(wptr, Noise_XK_session_get_key((*ctx->noise_outs)[ctx->my_complaints[i]-1]), tpdkg_noise_key_SIZE); wptr+=tpdkg_noise_key_SIZE; } if(0!=send_msg(output, tpdkg_peer_output_size(ctx), 11, ctx->index, 0x0, ctx->sig_sk, ctx->sessionid)) return 3; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %x ", ctx->index, msg11->msgno, msg11->from, msg11->to); dump(output, tpdkg_peer_output_size(ctx), "msg"); } // we skip to the end... ctx->step=99; return 0; } static int tp_step18_handler(TP_DKG_TPState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[!] step 18. collect keys of contested shares and verify the commitments\e[0m\n"); if(input_len != tpdkg_tp_input_size(ctx)) return 1; if(output_len != 0) return 2; unsigned int ctr[ctx->n]; uint16_t complaints[ctx->complaints_len]; memset(ctr,0,sizeof(ctr)); for(int i=0;icomplaints_len;i++) { ctr[((*ctx->complaints)[i] & 0xff)-1]++; complaints[i] = (*ctx->complaints)[i]; } uint8_t (*noisy_shares)[ctx->n][ctx->n][tpdkg_msg8_SIZE] = (uint8_t (*)[ctx->n][ctx->n][tpdkg_msg8_SIZE]) ctx->encrypted_shares; const uint8_t *ptr = input; size_t msg_len; for(uint8_t i=0;in;i++,ptr += msg_len) { if(ctr[i]==0) { msg_len = 0; continue; // no complaints against this peer } msg_len = sizeof(TP_DKG_Message) + (1+tpdkg_noise_key_SIZE) * ctr[i]; const TP_DKG_Message* msg = (const TP_DKG_Message*) ptr; if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: 0x%x ", msg->msgno, msg->from, msg->to); dump(ptr, msg_len, "msg"); } int ret = recv_msg(ptr, msg_len, 11, i+1, 0, (*ctx->peer_sig_pks)[i], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i]); if(0!=ret) { if(add_cheater(ctx, 18, 32+ret, i+1, 0xfe) == NULL) return 4; continue; } // verify proofs const uint8_t *keyptr = msg->data; for(int k=0;kfrom; int j; for(j=0;jcomplaints_len;j++) { if(complaints[j] == (((complainer)<<8) | accused)) { complaints[j]=0xffff; break; } } if(j==ctx->complaints_len) { // accused revealed a key that was not complained about if(add_cheater(ctx, 18, 6, accused, complainer) == NULL) return 4; continue; } uint8_t *msg8_ptr = (*noisy_shares)[accused-1][complainer-1]; const TP_DKG_Message *msg8 = (const TP_DKG_Message *) msg8_ptr; if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: %d ", msg8->msgno, msg8->from, msg8->to); dump(msg8_ptr, tpdkg_msg8_SIZE, "msg"); } uint64_t last_ts = ntohll(msg8->ts); ret = recv_msg(msg8_ptr, tpdkg_msg8_SIZE, 8, accused, complainer, (*ctx->peer_sig_pks)[accused-1], ctx->sessionid, ctx->ts_epsilon, &last_ts); if(0!=ret) { // key reveal msg_recv failure if(add_cheater(ctx, 18, 16+ret, accused, complainer) == NULL) return 4; continue; } #ifdef UNITTEST dump(keyptr, tpdkg_noise_key_SIZE, "[!] key_%d,%d", accused, complainer); #endif //UNITTEST // verify key committing hmac first! #if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) if(0!=crypto_auth_verify(msg8->data + noise_xk_handshake3_SIZE + sizeof(TOPRF_Share) + crypto_secretbox_xchacha20poly1305_MACBYTES, msg8->data + noise_xk_handshake3_SIZE, sizeof(TOPRF_Share) + crypto_secretbox_xchacha20poly1305_MACBYTES, keyptr)) { // failed to verify KC MAC on message if(add_cheater(ctx, 18, 3, accused, complainer) == NULL) return 4; continue; } #endif Noise_XK_error_code res0 = Noise_XK_aead_decrypt((uint8_t*)keyptr, 0, (uint32_t)0U, NULL, sizeof(share), (uint8_t*) &share, (uint8_t*) msg8->data + noise_xk_handshake3_SIZE); if (!(res0 == Noise_XK_CSuccess)) { // share decryption failure if(add_cheater(ctx, 18, 4, accused, complainer) == NULL) return 4; continue; } if(share.index != complainer) { // invalid share index TP_DKG_Cheater *cheater = add_cheater(ctx, 18, 5, accused, complainer); if(cheater == NULL) return 4; cheater->invalid_index = share.index; continue; } if(log_file!=NULL) { fprintf(log_file, "[!] checking proof of peer %d for complaint by peer %d\n", msg->from, share.index); dump((void*) &share, sizeof(TOPRF_Share), "[!] share_%d,%d", msg->from, share.index); dump((*ctx->commitments)[(msg->from-1) * ctx->t], ctx->t * crypto_core_ristretto255_BYTES, "[!] commitments_%d", msg->from); } ret = dkg_verify_commitment(ctx->n, ctx->t, share.index, msg->from, (const uint8_t (*)[crypto_core_ristretto255_BYTES]) (*ctx->commitments)[(msg->from-1) * ctx->t], share); switch(ret) { case 0: { // verified correctly if(log_file!=NULL) fprintf(log_file, "\e[0;32m[!] complaint against %d by %d invalid, proof correct\e[0m\n", msg->from, share.index); if(add_cheater(ctx, 18, 128+ret, accused, complainer) == NULL) return 4; break; } case 1: { // confirmed corrupt if(log_file!=NULL) fprintf(log_file, "\e[0;31m[!] complaint against %d by %d valid, proof incorrect\e[0m\n", msg->from, share.index); if(add_cheater(ctx, 18, 128+ret, accused, complainer) == NULL) return 4; break; } case -1: { // invalid input if(log_file!=NULL) fprintf(log_file, "\e[0;31m[!] complaint against %d by %d, cannot be verified, invalid input\e[0m\n", msg->from, share.index); if(add_cheater(ctx, 18, 128+ret, accused, complainer) == NULL) return 4; break; } } } } for(int i=0;icomplaints_len;i++) { if(complaints[i] != 0xffff) { if(add_cheater(ctx, 18, 7, (uint8_t) (complaints[i] >> 8), (uint8_t) (complaints[i] & 0xff)) == NULL) return 4; } } ctx->step=99; // we skip to the end return 3; } static int peer_step19_handler(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[%d] step 19. send final transcript\e[0m\n", ctx->index); if(input_len != 0) return 1; if(output_len != tpdkg_msg19_SIZE) return 2; TP_DKG_Message* msg20 = (TP_DKG_Message*) output; crypto_generichash_final(&ctx->transcript, msg20->data, crypto_generichash_BYTES); if(0!=send_msg(output, tpdkg_msg19_SIZE, 20, ctx->index, 0, ctx->sig_sk, ctx->sessionid)) return 3; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %d ", ctx->index, msg20->msgno, msg20->from, msg20->to); dump(output, tpdkg_msg19_SIZE, "msg"); } return 0; } static int tp_step20_handler(TP_DKG_TPState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[!] step 20. collect and verify transcripts\e[0m\n"); if((tpdkg_msg19_SIZE * ctx->n) != input_len) return 1; if(output_len != tpdkg_msg20_SIZE) return 2; uint8_t transcript_hash[crypto_generichash_BYTES]; crypto_generichash_final(&ctx->transcript, transcript_hash, crypto_generichash_BYTES); uint8_t *wptr = ((TP_DKG_Message *) output)->data; memcpy(wptr, "OK", 2); const uint8_t *ptr = input; for(uint8_t i=0;in;i++, ptr+=tpdkg_msg19_SIZE) { const TP_DKG_Message* msg = (const TP_DKG_Message*) ptr; if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: %d ", msg->msgno, msg->from, msg->to); dump(ptr, tpdkg_msg19_SIZE, "msg"); } int ret = recv_msg(ptr, tpdkg_msg19_SIZE, 20, i+1, 0, (*ctx->peer_sig_pks)[i], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i]); if(0!=ret) { if(add_cheater(ctx, 20, 1+ret, i+1, 0) == NULL) return 4; memcpy(wptr,"NO",2); continue; } if(sodium_memcmp(transcript_hash, msg->data, sizeof(transcript_hash))!=0) { if(log_file!=NULL) { fprintf(log_file,"\e[0;31m[!] failed to verify transcript from %d!\e[0m\n", i); } if(add_cheater(ctx, 20, 1, i+1, 0) == NULL) return 4; memcpy(wptr,"NO",2); } } if(0!=send_msg(output, output_len, 21, 0, 0xff, ctx->sig_sk, ctx->sessionid)) return 5; TP_DKG_Message* msg21 = (TP_DKG_Message*) output; if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: %x ", msg21->msgno, msg21->from, msg21->to); dump(output, output_len, "msg"); } if(ctx->cheater_len == 0) return 0; ctx->step = 99; // we finish here return 3; } static int peer_step21_handler(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[%d] step 21. get final approval\e[0m\n", ctx->index); if(input_len != tpdkg_msg20_SIZE) return 1; if(output_len != tpdkg_msg21_SIZE) return 2; // verify TP message envelope TP_DKG_Message* msg21 = (TP_DKG_Message*) input; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: 0x%x ", ctx->index, msg21->msgno, msg21->from, msg21->to); dump(input, input_len, "msg"); } int ret = recv_msg(input, input_len, 21, 0, 0xff, ctx->tp_sig_pk, ctx->sessionid, ctx->ts_epsilon, &ctx->tp_last_ts); if(0!=ret) return 4+ret; int fail = (memcmp(msg21->data, "OK", 2) != 0); if(!fail) { ctx->share.index=ctx->index; dkg_finish(ctx->n,*ctx->xshares,ctx->index,&ctx->share); TP_DKG_Message* msg22 = (TP_DKG_Message*) output; memcpy(msg22->data, msg21->data, 2); if(0!=send_msg(output, tpdkg_msg21_SIZE, 22, ctx->index, 0, ctx->sig_sk, ctx->sessionid)) return 3; if(log_file!=NULL) { fprintf(log_file,"[%d] msgno: %d, from: %d to: %d ", ctx->index, msg22->msgno, msg22->from, msg22->to); dump(output, tpdkg_msg21_SIZE, "msg"); } return 0; } return 4; } static int tp_step22_handler(TP_DKG_TPState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { if(log_file!=NULL) fprintf(log_file, "\e[0;33m[!] step 22. collect acks from peers\e[0m\n"); if((tpdkg_msg21_SIZE * ctx->n) != input_len) return 1; if(output_len != 0) return 2; const uint8_t *ptr = input; for(uint8_t i=0;in;i++, ptr+=tpdkg_msg21_SIZE) { const TP_DKG_Message* msg = (const TP_DKG_Message*) ptr; if(log_file!=NULL) { fprintf(log_file,"[!] msgno: %d, from: %d to: %d ", msg->msgno, msg->from, msg->to); dump(ptr, tpdkg_msg21_SIZE, "msg"); } int ret = recv_msg(ptr, tpdkg_msg21_SIZE, 22, i+1, 0, (*ctx->peer_sig_pks)[i], ctx->sessionid, ctx->ts_epsilon, &ctx->last_ts[i]); if(0!=ret) { if(add_cheater(ctx, 22, 64+ret, i+1, 0) == NULL) return 6; continue; } if(memcmp("OK", msg->data, 2)!=0) { if(log_file!=NULL) { fprintf(log_file,"\e[0;31m[!] failed to get ack from %d!\e[0m\n", i); } } } if(ctx->cheater_len>0) return 5; return 0; } int tpdkg_tp_next(TP_DKG_TPState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { int ret = 0; switch(ctx->step) { case 0: {ret = tp_step1_handler(ctx, input, input_len, output, output_len); break;} case 1: {ret = tp_step4_handler(ctx, input, input_len, output, output_len); break;} case 2: {ret = tp_step68_handler(ctx, input, input_len, output, output_len); break;} case 3: {ret = tp_step68_handler(ctx, input, input_len, output, output_len); break;} case 4: {ret = tp_step12_handler(ctx, input, input_len, output, output_len); break;} case 5: {ret = tp_step14_handler(ctx, input, input_len, output, output_len); break;} case 6: { ret = tp_step16_handler(ctx, input, input_len, output, output_len); ctx->prev = ctx->step; if(ctx->complaints_len == 0) { // we skip over to step 21 ctx->step++; } ctx->step++; return ret; } case 7: {ret = tp_step18_handler(ctx, input, input_len, output, output_len); break;} case 8: {ret = tp_step20_handler(ctx, input, input_len, output, output_len); break;} case 9: {ret = tp_step22_handler(ctx, input, input_len, output, output_len); break;} default: { if(log_file!=NULL) fprintf(log_file, "[!] invalid step\n"); return 99; } } ctx->prev=ctx->step++; if(ret!=0) ctx->step=99; // so that not_done reports done return ret; } int tpdkg_peer_next(TP_DKG_PeerState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len) { int ret=0; switch(ctx->step) { case 0: {ret = peer_step23_handler(ctx, input, input_len, output, output_len); break;} case 1: {ret = peer_step5_handler(ctx, input, input_len, output, output_len); break;} case 2: {ret = peer_step7_handler(ctx, input, input_len, output, output_len); break;} case 3: {ret = peer_step911_handler(ctx, input, input_len, output, output_len); break;} case 4: {ret = peer_step13_handler(ctx, input, input_len, output, output_len); break;} case 5: {ret = peer_step15_handler(ctx, input, input_len, output, output_len); break;} case 6: {ret = peer_step17_handler(ctx, input, input_len, output, output_len); break;} case 7: {ret = peer_step17a_handler(ctx, input, input_len, output, output_len); break;} case 8: {ret = peer_step19_handler(ctx, input, input_len, output, output_len); break;} case 9: {ret = peer_step21_handler(ctx, input, input_len, output, output_len); break;} case 10: { // we are done ret = 0; break; } default: { if(log_file!=NULL) fprintf(log_file, "[%d] invalid step\n", ctx->index); ret = 99; } } ctx->prev=ctx->step++; if(ret!=0) ctx->step=99; // so that not_done reports done return ret; } char* tpdkg_recv_err(const int code) { switch(code) { case 0: return "no error"; case 1: return "invalid message len"; case 2: return "invalid message number"; case 3: return "invalid sender"; case 4: return "invalid recipient"; case 5: return "expired message"; case 6: return "invalid signature"; case 7: return "invalid sessionid"; } return "invalid recv_msg error code"; } uint8_t tpdkg_cheater_msg(const TP_DKG_Cheater *c, char *out, const size_t outlen) { if(c->error>65 && c->error<=70) { snprintf(out, outlen, "step %d message from peer %d for peer %d could not be validated: %s", c->step, c->peer, c->other_peer, tpdkg_recv_err(c->error & 0x3f)); return c->peer; } if(c->step==16) { if(c->error == 6) { snprintf(out, outlen, "more than t^2 complaints, most peers are cheating."); return 0; } else if(c->error == 7) { snprintf(out, outlen, "peer %d sent complaint about invalid peer %d.", c->peer, c->other_peer); return c->peer; } else if(c->error == 8) { snprintf(out, outlen, "peer %d sent a duplicate complaint about peer %d.", c->peer, c->other_peer); return c->peer; } snprintf(out,outlen, "invalid error code for step 16: %d", c->error); return 0; } else if(c->step==18) { if(c->error & 16) { snprintf(out, outlen, "message containing encrypted share from peer %d for peer %d could not be validated: %s", c->peer, c->other_peer, tpdkg_recv_err(c->error & 0xf)); return c->peer; } else if (c->error & 32) { snprintf(out, outlen, "message revealing key encrypting share from peer %d for peer %d could not be validated: %s", c->peer, c->other_peer, tpdkg_recv_err(c->error & 0x1f)); return c->peer; } switch(c->error) { case 3: { snprintf(out,outlen, "accused peer %d revealed a key (for peer %d) that was not complained about", c->peer, c->other_peer); return c->peer; } case 4: { snprintf(out,outlen, "verification of hmac of message from accused peer %d to complaining peer %d failed", c->peer, c->other_peer); return c->peer; } case 5: { snprintf(out,outlen, "accused peer %d sent an invalid share with index %d to complaining peer %d", c->peer, c->other_peer, c->invalid_index); return c->peer; } case 6: { snprintf(out,outlen, "accused peer %d revealed a key for happy peer %d", c->peer, c->other_peer); return c->peer; } case 7: { snprintf(out,outlen, "accused peer %d complained by peer %d was not verified", c->peer, c->other_peer); return c->peer; } case 127: { snprintf(out,outlen, "accused peer %d provided invalid parameters to complaint from peer %d", c->peer, c->other_peer); return c->peer; } case 128: { snprintf(out,outlen, "peer %d was falsely accused by peer %d", c->peer, c->other_peer); return c->other_peer; } case 129: { snprintf(out,outlen, "accused peer %d was caught cheating by peer %d", c->peer, c->other_peer); return c->peer; } default: { snprintf(out,outlen, "invalid error code for step 18: %d", c->error); return 0; } } } else if(c->step==20) { if(c->error == 1) { snprintf(out,outlen, "transcript mismatch peer %d", c->peer); return c->peer; } snprintf(out,outlen, "invalid error code for step 20: %d", c->error); return 0; } snprintf(out,outlen, "invalid step %d", c->step); return 0; } liboprf-0.6.1/src/tp-dkg.h000066400000000000000000000551161474121727000153160ustar00rootroot00000000000000#ifndef tp_dkg_h #define tp_dkg_h /** * @file tp-dkg.h SPDX-FileCopyrightText: 2024, Marsiske Stefan SPDX-License-Identifier: LGPL-3.0-or-later API for the Trusted Party Distributed Key Generation Protocol In this protocol there is two roles, the trusted party (TP) and the peers. The trusted party connects to all peers and orchestrates the protocol which commuicate only via the TP with each other. This way the TP acts also as a broadcast medium which is an essential part of all DKG protocols. In this protocol the trusted party is - as the name implies - trusted, but does not learn the result of the DKG. If the trusted party is so trusted that it can learn the result of the DKG, then it is much simpler to just randomly generate a secret and then share it using Shamir's Secret Sharing. The peers only identify themselves towards the TP using long-term keys, but use ephemeral keys when communicating with each other, this makes them unaware of the identities of the others. However peers might be using the ephemeral public keys, or any of the generated random values to use as a side-channel to leak their identity to the other peers. The protocol consists of more than 20 steps, but the API hides this and provides a state-engine loop, which any user can call iteratively while implementing the networking communication themselves. This makes it possible to support different communication channels like TCP/IP, Bluetooth, UART, etc. A peer needs only to support the medium they use, the TP however must of course be able to support all the media that the peers require. Both the peers and the TP share a similar API schema: (0. msg0 = read()) // only for peers 1. start_{tp|peer}(state, ...) (1.5 send(msg0)) // only for TP 2. {tp|peer}_set_bufs() 3. while {tp|peer}_not_done(state): - input = allocate_memory( dkg_{tp|peer}_input_size(state) ) - output = allocate_memory( dkg_{tp|peer}_output_size(state) ) - input = read() - res = {tp|peer}_next_step(state, input, output) - if res!=0: fail&abort (- dkg_tp_peer_msg(state, output, peer_index, msg) // for TP (- msg = output) // for peers - send(msg) // only for peers (4. store share) (5. peer_free(state)) */ #include #include #include "XK.h" #include "dkg.h" #define tpdkg_sessionid_SIZE 32 #define tpdkg_msg0_SIZE ( sizeof(TP_DKG_Message) \ + crypto_generichash_BYTES/*dst*/ \ + 2 /*n,t*/ \ + crypto_sign_PUBLICKEYBYTES /* tp_sign_pk */ ) #define noise_xk_handshake3_SIZE 64UL #define tpdkg_msg8_SIZE (sizeof(TP_DKG_Message) /* header */ \ + noise_xk_handshake3_SIZE /* 4th&final noise handshake */ \ + sizeof(TOPRF_Share) /* msg: the noise_xk wrapped share */ \ + crypto_secretbox_xchacha20poly1305_MACBYTES /* mac of msg */ \ + crypto_auth_hmacsha256_BYTES /* key-committing mac over msg*/ ) #define tpdkg_max_err_SIZE 128 /** @struct TP_DKG_Message This is the header for each message sent in this protocol. @var TP_DKG_Message::sig This field contains a signature over the message header, the message body and the sessionid which is normally not included in the message @var TP_DKG_Message::msgno This field contains the "type" of this message, which is strictly tied to the current step of the protocol @var TP_DKG_Message::len This field contains the length of the complete message including the header. @var TP_DKG_Message::from This field contains the id of the sender, the TP is 0, otherwise its the index of the peer. @var TP_DKG_Message::to This field contains the recipient of the message, value 0 represents the TP, value 0xff represents a broadcast message, all other values (<=N) are the indexes of the peers. @var TP_DKG_Message::ts This field contains a timestamp proving the freshness of the message, the timestamp is a 64 bit value counting seconds since 1970-01-01. @var TP_DKG_Message::data This field contains the payload of the message. */ typedef struct { uint8_t sig[crypto_sign_BYTES]; uint8_t msgno; uint32_t len; uint8_t from; uint8_t to; uint64_t ts; uint8_t sessionid[tpdkg_sessionid_SIZE]; uint8_t data[]; } __attribute((packed)) TP_DKG_Message; /** @struct TP_DKG_PeerState This struct contains the state of a peer during the execution of the TP DKG protocol. Most values of this struct are internal variables and should not be used. The following variables are useful and can be used by users of this API: @var TP_DKG_PeerState:n This field contains the value N, specifying the total number of peers participating in this protocol. @var TP_DKG_PeerState:t This field contains the value T, specifying the threshold necessary to use shared secret generated by this DKG. @var TP_DKG_PeerState:index This field contains the index of the peer, it is a value between 1 and and N inclusive. @var TP_DKG_PeerState:share This field contains the resulting share at the end of the DKG and should most probably be persisted for later usage. This is the output of the DKG for a peer. */ typedef struct { int step; int prev; uint8_t sessionid[tpdkg_sessionid_SIZE]; uint8_t n; uint8_t t; uint8_t index; uint8_t lt_sk[crypto_sign_SECRETKEYBYTES]; uint8_t sig_pk[crypto_sign_PUBLICKEYBYTES]; uint8_t sig_sk[crypto_sign_SECRETKEYBYTES]; uint8_t noise_pk[crypto_scalarmult_BYTES]; uint8_t noise_sk[crypto_scalarmult_SCALARBYTES]; uint8_t tp_sig_pk[crypto_sign_PUBLICKEYBYTES]; uint64_t tp_last_ts; uint64_t *last_ts; uint64_t ts_epsilon; uint8_t (*peer_sig_pks)[][crypto_sign_PUBLICKEYBYTES]; uint8_t (*peer_noise_pks)[][crypto_scalarmult_BYTES]; Noise_XK_device_t *dev; Noise_XK_session_t *(*noise_outs)[]; Noise_XK_session_t *(*noise_ins)[]; uint8_t (*commitments)[][crypto_core_ristretto255_BYTES]; TOPRF_Share (*shares)[]; TOPRF_Share (*xshares)[]; uint16_t complaints_len; uint16_t *complaints; uint8_t my_complaints_len; uint8_t *my_complaints; crypto_generichash_state transcript; TOPRF_Share share; } TP_DKG_PeerState; size_t tpdkg_peerstate_size(void); uint8_t tpdkg_peerstate_n(TP_DKG_PeerState *ctx); uint8_t tpdkg_peerstate_t(TP_DKG_PeerState *ctx); uint8_t* tpdkg_peerstate_sessionid(TP_DKG_PeerState *ctx); uint8_t* tpdkg_peerstate_lt_sk(TP_DKG_PeerState *ctx); uint8_t* tpdkg_peerstate_share(TP_DKG_PeerState *ctx); int tpdkg_peerstate_step(TP_DKG_PeerState *ctx); /** @struct TP_DKG_Cheater This struct communicates one detected violation of the protocol. @var TP_DKG_Cheater::step This is the step in which the violation occured. @var TP_DKG_Cheater::error This is the error code specifying the violation. @var TP_DKG_Cheater::peer This specifies which peer caused the violation. @var TP_DKG_Cheater::other_peer This optionally specifies which peer reported the violation, set to 0xfe if unused. */ typedef struct { int step; int error; uint8_t peer; uint8_t other_peer; int invalid_index; } TP_DKG_Cheater; // error codes: // step 18 // 6; accused revealed a key that was not complained about // 3; hmac verification failure // 4; share decryption failure // 5; invalid share index // 7; unchecked complaint // 16 + recv_msg error code - invalid msg 8 (final noise hs + hmac-ed share) // 32 + recv_msg error code - invalid msg11 - key reveal message // 127 invalid params for verification from accused // 128 false complaint // 129 correct complaint // recv_msg error codes // 1 invalid msg len // 2 unexpected msgno // 3 from // 4 to // 5 expired // 6 signature fail /** @struct TP_DKG_TPState This struct contains the state of the TP during the execution of the TP DKG protocol. Most values of this struct are internal variables and should not be used. The following variables are useful and can be used by users of this API: @var TP_DKG_PeerState:n This field contains the value N, specifying the total number of peers participating in this protocol. @var TP_DKG_PeerState:t This field contains the value T, specifying the threshold necessary to use shared secret generated by this DKG. @var TP_DKG_PeerState:cheaters This field contains a list of cheaters and protocol violators at the end of a failed protocol run. */ typedef struct { int step; int prev; uint8_t sessionid[tpdkg_sessionid_SIZE]; uint8_t n; uint8_t t; uint8_t sig_pk[crypto_sign_PUBLICKEYBYTES]; uint8_t sig_sk[crypto_sign_SECRETKEYBYTES]; uint64_t *last_ts; uint64_t ts_epsilon; uint8_t (*peer_sig_pks)[][crypto_sign_PUBLICKEYBYTES]; uint8_t (*peer_lt_pks)[][crypto_sign_PUBLICKEYBYTES]; uint8_t (*commitments)[][crypto_core_ristretto255_BYTES]; // note this could be optimized by only storing the encrypted share and the hmac // and also dropping all items where i==j uint8_t (*encrypted_shares)[][tpdkg_msg8_SIZE]; uint16_t complaints_len; uint16_t (*complaints)[]; size_t cheater_len; TP_DKG_Cheater (*cheaters)[]; size_t cheater_max; crypto_generichash_state transcript; } TP_DKG_TPState; size_t tpdkg_tpstate_size(void); uint8_t tpdkg_tpstate_n(TP_DKG_TPState *ctx); uint8_t tpdkg_tpstate_t(TP_DKG_TPState *ctx); size_t tpdkg_tpstate_cheater_len(TP_DKG_TPState *ctx); uint8_t* tpdkg_tpstate_sessionid(TP_DKG_TPState *ctx); int tpdkg_tpstate_step(TP_DKG_TPState *ctx); /* * Trusted Party functions */ /** Starts a new execution of a TP DKG protocol. This function initializes the state of the TP and creates an initial message containing the parameters for the peers. @param [in] ctx : pointer to a TP_DKG_TPState struct, this struct will be initialized by this function. @param [in] ts_epsilon: how many seconds a message can be old, before it is considered unfresh and is rejected. The correct value here is difficult to set, small local executions with only 2-out-of-3 setups will work with as few as 2-3 seconds, big deployments with 126-out-of-127 might need up to a few hours... @param [in] n: the number of peers participating in this execution. @param [in] t: the threshold necessary to use the results of this DKG. @param [in] proto_name: an array of bytes used as a domain seperation tag (DST). Set it to the name of your application. @param [in] proto_name_len: the size of the array proto_name, to allow non-zero terminated DSTs. @param [out] msg0_len: the size of memory allocated to the msg0 parameter. should be exactly tpdkg_msg0_SIZE; @param [out] msg0: a message to be sent to all peers to initalize them. @return 0 if no errors. **/ int tpdkg_start_tp(TP_DKG_TPState *ctx, const uint64_t ts_epsilon, const uint8_t n, const uint8_t t, const char *proto_name, const size_t proto_name_len, const size_t msg0_len, TP_DKG_Message *msg0); /** This function sets all the variable sized buffers in the TP_DKG_PeerState structure. A number of buffers are needed in the TP state that depend on the N and T parameters. These can be allocated on the stack as follows: @param [in] cheater_max: is the number of max cheat attempts to be recorded. Normally the maximum is t*t-1. It should be provided as (sizeof(cheaters) / sizeof(TP_DKG_Cheater)) @code uint8_t tp_commitments[n*t][crypto_core_ristretto255_BYTES]; uint16_t tp_complaints[n*n]; uint8_t encrypted_shares[n*n][tpdkg_msg8_SIZE]; TP_DKG_Cheater cheaters[t*t - 1]; uint8_t tp_peers_sig_pks[n][crypto_sign_PUBLICKEYBYTES]; uint8_t peer_lt_pks[n][crypto_sign_PUBLICKEYBYTES]; tpdkg_tp_set_bufs(&tp, &tp_commitments, &tp_complaints, &encrypted_shares, &cheaters, sizeof(cheaters) / sizeof(TP_DKG_Cheater), &tp_peers_sig_pks, &peer_lt_pks); @endcode Important to note that peer_lt_pks should contain the long-term signing public-keys of each peer. This array must be populated in the correct order before the first call to tpdkg_tp_next(). */ void tpdkg_tp_set_bufs(TP_DKG_TPState *ctx, uint8_t (*commitments)[][crypto_core_ristretto255_BYTES], uint16_t (*complaints)[], uint8_t (*encrypted_shares)[][tpdkg_msg8_SIZE], TP_DKG_Cheater (*cheaters)[], const size_t cheater_max, uint8_t (*tp_peers_sig_pks)[][crypto_sign_PUBLICKEYBYTES], uint8_t (*peer_lt_pks)[][crypto_sign_PUBLICKEYBYTES], uint64_t *last_ts); /** This function calculates the size of the buffer needed to hold all outputs from the peers serving as input to the next step of the TP. An implementer should allocate a buffer of this size, and concatenate all messages from all peers in the order of the peers. The allocated buffer is to be passed as an input to the tpdkg_pt_next() function, after this the buffer SHOULD be deallocated. @param [in] ctx: an initialized TP_DKG_TPState struct. @return 1 on error, otherwise the size to be allocated (can be 0) */ size_t tpdkg_tp_input_size(const TP_DKG_TPState *ctx); /** This function calculates the size of the message from each peer to be received by the TP. @param [in] ctx: an initialized TP_DKG_TPState struct. @param [out] sizes: a array of type size_t with exactly N elements. @return 0 on if the sizes differ from peer to peer, otherwise all peers will be sending messages of equal size. In the latter case all items of the sizes array hold the same valid value. */ int tpdkg_tp_input_sizes(const TP_DKG_TPState *ctx, size_t *sizes); /** This function calculates the size of the buffer needed to hold the output from the tpdkg_tp_next() function. An implementer should allocate a buffer of this size and pass it as parameter to tpdkg_tp_next(). @param [in] ctx: an initialized TP_DKG_TPState struct. @return 1 on error, otherwise the size to be allocated (can be 0) */ size_t tpdkg_tp_output_size(const TP_DKG_TPState *ctx); /** This function exeutes the next step of the TP DKG protocol for the trusted party. @param [in] ctx: pointer to a valid TP_DKG_TPState. @param [in] input: buffer to the input of the current step. @param [in] input_len: size of the input buffer. @param [out] output: buffer to the output of the current step. @param [in] output_len: size of the output buffer. @return 0 if no error An example of how to use this in concert with tpdkg_tp_input_size() and tpdkg_tp_output_size(): @code uint8_t tp_out[tpdkg_tp_output_size(&tp)]; uint8_t tp_in[tpdkg_tp_input_size(&tp)]; recv(socket, tp_in, sizeof(tp_in)); ret = tpdkg_tp_next(&tp, tp_in, sizeof(tp_in), tp_out, sizeof tp_out); @endcode */ int tpdkg_tp_next(TP_DKG_TPState *ctx, const uint8_t *input, const size_t input_len, uint8_t *output, const size_t output_len); /** This function "converts" the output of tpdkg_tp_next() into a message for the ith peer. The outputs of steps of the protocol are sometimes broadcast messages where the output is the same for all peers, but some of the outputs are dedicated and unique messages for each peer. This function returns a pointer to a message and the size of the message to be sent for a particular peer specified as a parameter. @param [in] ctx: pointer to a valid TP_DKG_TPState. @param [in] base: a pointer to the output of the tpdkg_tp_next() function. @param [in] base_size: the size of the output of the tpdkg_tp_next() function. @param [in] peer: the index of the peer (starting with 0 for the first) @param [out] msg: pointer to a pointer to the message to be sent to the ith peer. @param [out] len: pointer to the length of the message to be sent to the ith peer. @return 0 if no error example how to use this in concert with tpdkg_tp_next(): @code ret = tpdkg_tp_next(&tp, tp_in, sizeof(tp_in), tp_out, sizeof tp_out); if(0!=ret) { // clean up peers for(int i=0;i #include #include #include int debug = 0; #ifdef UNIT_TEST void debian_rng_scalar(uint8_t *scalar) { static int warned=0; static uint8_t rng_i=2; if(!warned) { fprintf(stderr, "\e[0;31mWARNING! This version of liboprf DKG is compiled with a *NON* random generator for UNIT_TESTS\e[0m\n"); warned=1; } memset(scalar,0,crypto_core_ristretto255_SCALARBYTES); scalar[0]=rng_i++; //static uint16_t rng_i=0; //uint16_t tmp[64 / sizeof(uint16_t)]; //for(unsigned j=0;j<(64/ sizeof(uint16_t));j++) { // tmp[j]=rng_i++; //} //crypto_core_ristretto255_scalar_reduce(scalar,(uint8_t*)tmp); } #endif void dump(const uint8_t *p, const size_t len, const char* msg, ...) { if(!debug) return; va_list args; va_start(args, msg); vfprintf(stderr,msg, args); va_end(args); fprintf(stderr," "); for(size_t i=0;i #include extern int debug; #ifdef UNIT_TEST void debian_rng_scalar(uint8_t *scalar); #endif //UNIT_TEST void dump(const uint8_t *p, const size_t len, const char* msg, ...); void fail(char* msg, ...); #endif // TOPRF_UTILS_H