commit a30bd40031422589233368dffaf60d9c4fbfa959
parent c35b6704f19ec924e68cf169119aac281861106b
Author: Nick Mathewson <nickm@torproject.org>
Date: Wed, 21 May 2025 10:15:07 -0400
Merge branch '41052_cgo_encryption' into 'main'
CGO: Crypto implementation
Closes #41052
See merge request tpo/core/tor!879
Diffstat:
23 files changed, 3719 insertions(+), 27 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -383,6 +383,33 @@ src/ext/mulodi4.c is distributed under this license:
or promote products derived from this Software.
===============================================================================
+Parts of src/ext/polyval are based on Thomas Pornin's GHASH implementation in
+BearSSL, and distributed under the following license:
+
+ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+
+===============================================================================
If you got Tor as a static binary with OpenSSL included, then you should know:
"This product includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit (http://www.openssl.org/)"
diff --git a/Makefile.am b/Makefile.am
@@ -112,7 +112,8 @@ TOR_CRYPTO_LIBS = \
src/lib/libtor-tls.a \
src/lib/libtor-crypt-ops.a \
$(LIBKECCAK_TINY) \
- $(LIBDONNA)
+ $(LIBDONNA) \
+ $(LIBPOLYVAL)
if BUILD_MODULE_POW
TOR_CRYPTO_LIBS += $(EQUIX_LIBS)
@@ -126,6 +127,7 @@ TOR_CRYPTO_TESTING_LIBS = \
src/lib/libtor-crypt-ops-testing.a \
$(LIBKECCAK_TINY) \
$(LIBDONNA) \
+ $(LIBPOLYVAL) \
$(EQUIX_LIBS)
endif
diff --git a/configure.ac b/configure.ac
@@ -994,6 +994,23 @@ if test "x$enable_nss" = "xyes"; then
[have_nss=no; AC_MSG_ERROR([You asked for NSS but I can't find it, $pkg_config_user_action, or set NSS_CFLAGS and NSS_LIBS.])])
AC_SUBST(NSS_CFLAGS)
AC_SUBST(NSS_LIBS)
+
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$LIBS $NSS_LIBS"
+ CFLAGS="$CFLAGS $NSS_CFLAGS"
+ AC_MSG_CHECKING([whether NSS defines ssl_kea_ecdh_hybrid(_psk)])
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ #include <sslt.h>
+ int v = (int) ssl_kea_ecdh_hybrid_psk;
+ int v2 = (int) ssl_kea_ecdh_hybrid;
+ ]], [[]])],
+ [ AC_MSG_RESULT([yes]);
+ AC_DEFINE(NSS_HAS_ECDH_HYBRID, 1, [whether nss defines ecdh_hybrid key exchange.])
+ ],
+ [ AC_MSG_RESULT([no]) ])
+ LIBS="$save_LIBS"
+ CPPFLAGS="$save_CPPFLAGS"
fi
dnl ------------------------------------------------------
diff --git a/src/core/crypto/include.am b/src/core/crypto/include.am
@@ -6,7 +6,8 @@ LIBTOR_APP_A_SOURCES += \
src/core/crypto/onion_fast.c \
src/core/crypto/onion_ntor.c \
src/core/crypto/onion_ntor_v3.c \
- src/core/crypto/relay_crypto.c
+ src/core/crypto/relay_crypto.c \
+ src/core/crypto/relay_crypto_cgo.c
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
@@ -15,4 +16,5 @@ noinst_HEADERS += \
src/core/crypto/onion_fast.h \
src/core/crypto/onion_ntor.h \
src/core/crypto/onion_ntor_v3.h \
- src/core/crypto/relay_crypto.h
+ src/core/crypto/relay_crypto.h \
+ src/core/crypto/relay_crypto_cgo.h
diff --git a/src/core/crypto/relay_crypto_cgo.c b/src/core/crypto/relay_crypto_cgo.c
@@ -0,0 +1,563 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2025, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file relay_crypto_cgo.c
+ * \brief Implementation for counter galois onion encryption.
+ **/
+
+#define RELAY_CRYPTO_CGO_PRIVATE
+#define USE_AES_RAW
+
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "lib/crypt_ops/aes.h"
+#include "ext/polyval/polyval.h"
+#include "lib/crypt_ops/crypto_util.h"
+#include "lib/log/util_bug.h"
+#include "lib/arch/bytes.h"
+#include "ext/polyval/polyval.h"
+#include "core/crypto/relay_crypto_cgo.h"
+#include "core/or/cell_st.h"
+
+#if 0
+// XXXX debugging.
+#include "lib/encoding/binascii.h"
+#include <stdio.h>
+#endif
+
+#include <string.h>
+
+static int
+cgo_et_keylen(int aesbits)
+{
+ return (aesbits / 8) + POLYVAL_KEY_LEN;
+}
+
+/** Initialize an instance of the tweakable block cipher,
+ * using an 'aesbits'-bit AES key.
+ *
+ * The total key material used from 'key' will be
+ * (aesbits / 8) + 16.
+ *
+ * This will be initialized for encryption or decryption depending
+ * on the value of 'encrypt'
+ */
+STATIC int
+cgo_et_init(cgo_et_t *et, int aesbits, bool encrypt,
+ const uint8_t *key)
+{
+ size_t aes_key_bytes = aesbits / 8;
+ et->kb = aes_raw_new(key, aesbits, encrypt);
+ if (et->kb == NULL)
+ return -1;
+ polyval_key_init(&et->ku, key + aes_key_bytes);
+ return 0;
+}
+/** Replace the key on an existing, already initialized cgo_et_t.
+ *
+ * Does fewer allocations than a clear+init. */
+STATIC void
+cgo_et_set_key(cgo_et_t *et, int aesbits, bool encrypt,
+ const uint8_t *key)
+{
+ size_t aes_key_bytes = aesbits / 8;
+ aes_raw_set_key(&et->kb, key, aesbits, encrypt);
+ polyval_key_init(&et->ku, key + aes_key_bytes);
+}
+
+/** Helper: Compute polyval(KU, H | CMD | X_R). */
+static inline void
+compute_et_mask(polyval_key_t *pvk, const et_tweak_t tweak, uint8_t *t_out)
+{
+ // block 0: tweak.h
+ // block 1: one byte of command, first 15 bytes of x_r
+ // block 2...: remainder of x_r, zero-padded.
+ polyval_t pv;
+ uint8_t block1[16];
+ block1[0] = tweak.uiv.cmd;
+ memcpy(block1+1, tweak.x_r, 15);
+ polyval_init_from_key(&pv, pvk);
+ polyval_add_block(&pv, tweak.uiv.h);
+ polyval_add_block(&pv, block1);
+ polyval_add_zpad(&pv, tweak.x_r + 15, ET_TWEAK_LEN_X_R - 15);
+ polyval_get_tag(&pv, t_out);
+}
+/** XOR the 16 byte block from inp into out. */
+static void
+xor_block(uint8_t *out, const uint8_t *inp)
+{
+ for (int i = 0; i < 16; ++i)
+ out[i] ^= inp[i];
+}
+
+/**
+ * Encrypt the 16-byte block in 'block'.
+ */
+STATIC void
+cgo_et_encrypt(cgo_et_t *et, const et_tweak_t tweak,
+ uint8_t *block)
+{
+ uint8_t mask[16];
+ compute_et_mask(&et->ku, tweak, mask);
+ xor_block(block, mask);
+ aes_raw_encrypt(et->kb, block);
+ xor_block(block, mask);
+}
+/**
+ * Decrypt the 16-byte b lock in 'block'
+ */
+STATIC void
+cgo_et_decrypt(cgo_et_t *et, const et_tweak_t tweak,
+ uint8_t *block)
+{
+ uint8_t mask[16];
+ compute_et_mask(&et->ku, tweak, mask);
+ xor_block(block, mask);
+ aes_raw_decrypt(et->kb, block);
+ xor_block(block, mask);
+}
+/**
+ * Release any storage held in 'et'.
+ *
+ * This _doesn't_ wipe 'et'; that's done from a higher-level function.
+ */
+STATIC void
+cgo_et_clear(cgo_et_t *et)
+{
+ aes_raw_free(et->kb);
+}
+
+static int
+cgo_prf_keylen(int aesbits)
+{
+ return (aesbits / 8) + POLYVAL_KEY_LEN;
+}
+
+/**
+ * Initialize a psedorandom function from a given key.
+ * Uses an internal 'aesbits'-bit AES key.
+ *
+ * The total key material used from 'key' will be
+ * (aesbits / 8) + 16.
+ */
+STATIC int
+cgo_prf_init(cgo_prf_t *prf, int aesbits,
+ const uint8_t *key)
+{
+ size_t aes_key_bytes = aesbits / 8;
+ memset(prf,0, sizeof(*prf));
+ prf->k = aes_raw_new(key, aesbits, true);
+ polyval_key_init(&prf->b, key + aes_key_bytes);
+ return 0;
+}
+/** Replace the key on an existing cgo_prf_t.
+ *
+ * Does fewer allocations than a clear+init. */
+STATIC void
+cgo_prf_set_key(cgo_prf_t *prf, int aesbits,
+ const uint8_t *key)
+{
+ size_t aes_key_bytes = aesbits / 8;
+ aes_raw_set_key(&prf->k, key, aesbits, true);
+ polyval_key_init(&prf->b, key + aes_key_bytes);
+}
+/**
+ * Compute the PRF's results on 'input', for position t=0,
+ * XOR it into 'data'.
+ *
+ * 'input' must be PRF_INPUT_LEN bytes long.
+ *
+ * 'data' must be PRF_T0_DATA_LEN bytes long.
+ */
+STATIC void
+cgo_prf_xor_t0(cgo_prf_t *prf, const uint8_t *input,
+ uint8_t *data)
+{
+ uint8_t hash[16];
+ polyval_t pv;
+ polyval_init_from_key(&pv, &prf->b);
+ polyval_add_block(&pv, input);
+ polyval_get_tag(&pv, hash);
+ hash[15] &= 0xC0; // Clear the low six bits.
+
+ aes_raw_counter_xor(prf->k, hash, 0, data, PRF_T0_DATA_LEN);
+}
+/**
+ * Generate 'n' bytes of the PRF's results on 'input', for position t=1,
+ * and store them into 'buf'.
+ *
+ * 'input' must be PRF_INPUT_LEN bytes long.
+ */
+STATIC void
+cgo_prf_gen_t1(cgo_prf_t *prf, const uint8_t *input,
+ uint8_t *buf, size_t n)
+{
+ #define T1_OFFSET 31
+ uint8_t hash[16];
+ polyval_t pv;
+ polyval_init_from_key(&pv, &prf->b);
+ polyval_add_block(&pv, input);
+ polyval_get_tag(&pv, hash);
+ hash[15] &= 0xC0; // Clear the low six bits.
+
+ memset(buf, 0, n);
+ aes_raw_counter_xor(prf->k, hash, T1_OFFSET, buf, n);
+}
+/**
+ * Release any storage held in 'prf'.
+ *
+ * This _doesn't_ wipe 'prf'; that's done from a higher-level function.
+ */
+STATIC void
+cgo_prf_clear(cgo_prf_t *prf)
+{
+ aes_raw_free(prf->k);
+}
+
+static int
+cgo_uiv_keylen(int aesbits)
+{
+ return cgo_et_keylen(aesbits) + cgo_prf_keylen(aesbits);
+}
+
+/**
+ * Initialize the 'uiv' wide-block cipher, using 'aesbits'-bit
+ * AES keys internally.
+ *
+ * Initializes for encryption or decryption depending on the value of
+ * 'encrypt'.
+ *
+ * The total key material used from 'key' will be
+ * (aesbits / 8) * 2 + 32.
+ */
+STATIC int
+cgo_uiv_init(cgo_uiv_t *uiv, int aesbits, bool encrypt,
+ const uint8_t *key)
+{
+ size_t aes_key_bytes = aesbits / 8;
+ if (cgo_et_init(&uiv->j, aesbits, encrypt, key) < 0)
+ return -1;
+ if (cgo_prf_init(&uiv->s, aesbits, key + aes_key_bytes + POLYVAL_KEY_LEN)<0)
+ return -1;
+#ifdef TOR_UNIT_TESTS
+ /* Testing only: copy the keys so we can test UIV_UPDATE function. */
+ size_t total_key_len = aes_key_bytes * 2 + POLYVAL_KEY_LEN * 2;
+ tor_assert(total_key_len <= sizeof(uiv->uiv_keys_));
+ memset(uiv->uiv_keys_, 0, sizeof(uiv->uiv_keys_));
+ memcpy(uiv->uiv_keys_, key, total_key_len);
+#endif
+ return 0;
+}
+/**
+ * Encrypt 'cell_body', with the provided tweak.
+ *
+ * The cell body must be UIV_BLOCK_LEN bytes long.
+ */
+STATIC void
+cgo_uiv_encrypt(cgo_uiv_t *uiv, const uiv_tweak_t tweak, uint8_t *cell_body)
+{
+ uint8_t *X_L = cell_body;
+ uint8_t *X_R = cell_body + 16;
+
+ const et_tweak_t et_tweak = {
+ .uiv = tweak,
+ .x_r = X_R,
+ };
+ cgo_et_encrypt(&uiv->j, et_tweak, X_L);
+ cgo_prf_xor_t0(&uiv->s, X_L, X_R);
+}
+/**
+ * Decrypt 'cell_body', with the provided tweak.
+ *
+ * The cell body must be UIV_BLOCK_LEN bytes long.
+ */
+STATIC void
+cgo_uiv_decrypt(cgo_uiv_t *uiv, const uiv_tweak_t tweak, uint8_t *cell_body)
+{
+ uint8_t *X_L = cell_body;
+ uint8_t *X_R = cell_body + 16;
+
+ const et_tweak_t et_tweak = {
+ .uiv = tweak,
+ .x_r = X_R,
+ };
+ cgo_prf_xor_t0(&uiv->s, X_L, X_R);
+ cgo_et_decrypt(&uiv->j, et_tweak, X_L);
+}
+/**
+ * Irreversibly ransform the keys of this UIV+, and the provided nonce,
+ * using the nonce as input.
+ *
+ * The nonce must be 16 bytes long.
+ */
+STATIC void
+cgo_uiv_update(cgo_uiv_t *uiv, int aesbits, bool encrypt, uint8_t *nonce)
+{
+ size_t aes_bytes = aesbits / 8;
+ size_t single_key_len = aes_bytes + POLYVAL_KEY_LEN;
+ size_t total_key_len = single_key_len * 2 + 16;
+ // Note: We could store this on the stack, but stack-protector
+ // wouldn't like that.
+ uint8_t *new_keys = tor_malloc(total_key_len);
+
+ cgo_prf_gen_t1(&uiv->s, nonce, new_keys, total_key_len);
+
+ cgo_et_set_key(&uiv->j, aesbits, encrypt, new_keys);
+ cgo_prf_set_key(&uiv->s, aesbits, new_keys + single_key_len);
+
+ memcpy(nonce, new_keys + single_key_len * 2, 16);
+
+#ifdef TOR_UNIT_TESTS
+ /* Testing only: copy the keys so we can test UIV_UPDATE function. */
+ memset(uiv->uiv_keys_, 0, sizeof(uiv->uiv_keys_));
+ memcpy(uiv->uiv_keys_, new_keys, total_key_len);
+#endif
+
+ // This is key material, so we should really discard it.
+ memwipe(new_keys, 0, total_key_len);
+ tor_free(new_keys);
+}
+/**
+ * Release any storage held in 'prf'.
+ *
+ * This _doesn't_ wipe 'prf'; that's done from a higher-level function.
+ */
+STATIC void
+cgo_uiv_clear(cgo_uiv_t *uiv)
+{
+ cgo_et_clear(&uiv->j);
+ cgo_prf_clear(&uiv->s);
+}
+
+/* ====================
+ * High level counter galois onion implementations.
+ */
+
+/**
+ * Return the total number of bytes needed to initialize a cgo_crypt_t.
+ */
+size_t
+cgo_key_material_len(int aesbits)
+{
+ tor_assert(aesbits == 128 || aesbits == 192 || aesbits == 256);
+ return (cgo_uiv_keylen(aesbits) + CGO_TAG_LEN);
+}
+
+/**
+ * Instantiate a CGO authenticated encryption object from the provided
+ * 'keylen' bytes in 'keys'.
+ *
+ * 'keylen' must equal 'cgo_key_material_len(aesbits)'.
+ *
+ * The client and relay must have two cgo_crypt_t objects each:
+ * one for the forward direction, and one for the reverse direction.
+ */
+cgo_crypt_t *
+cgo_crypt_new(cgo_mode_t mode, int aesbits, const uint8_t *keys, size_t keylen)
+{
+ tor_assert(keylen == cgo_key_material_len(aesbits));
+ const uint8_t *end_of_keys = keys + keylen;
+ // Relays encrypt; clients decrypt.
+ // Don't reverse this: UIV+ is only non-malleable for _encryption_.
+ bool encrypt = (mode == CGO_MODE_RELAY_BACKWARD ||
+ mode == CGO_MODE_RELAY_FORWARD);
+ int r;
+
+ cgo_crypt_t *cgo = tor_malloc_zero(sizeof(cgo_crypt_t));
+ r = cgo_uiv_init(&cgo->uiv, aesbits, encrypt, keys);
+ tor_assert(r == 0);
+ keys += cgo_uiv_keylen(aesbits);
+ memcpy(cgo->nonce, keys, CGO_TAG_LEN);
+ keys += CGO_TAG_LEN;
+ tor_assert(keys == end_of_keys);
+
+ cgo->aes_bytes = aesbits / 8;
+
+ return cgo;
+}
+/**
+ * Clean up 'cgo' and free it.
+ */
+void
+cgo_crypt_free_(cgo_crypt_t *cgo)
+{
+ if (!cgo)
+ return;
+ cgo_uiv_clear(&cgo->uiv);
+ memwipe(cgo, 0, sizeof(cgo_crypt_t));
+ tor_free(cgo);
+}
+
+/**
+ * Internal: Run the UIV Update operation on our UIV+ instance.
+ */
+static void
+cgo_crypt_update(cgo_crypt_t *cgo, cgo_mode_t mode)
+{
+ bool encrypt = (mode == CGO_MODE_RELAY_BACKWARD ||
+ mode == CGO_MODE_RELAY_FORWARD);
+ cgo_uiv_update(&cgo->uiv, cgo->aes_bytes * 8, encrypt, cgo->nonce);
+}
+
+/**
+ * Forward CGO encryption operation at a relay:
+ * process an outbound cell from the client.
+ *
+ * If the cell is for this relay, set *'recognized_tag_out'
+ * to point to a CGO_TAG_LEN value that should be used
+ * if we want to acknowledge this cell with an authenticated SENDME.
+ *
+ * The value of 'recognized_tag_out' will become invalid
+ * as soon as any change is made to this 'cgo' object,
+ * or to the cell; if you need it, you should copy it immediately.
+ *
+ * If the cell is not for this relay, set *'recognized_tag_out' to NULL.
+ */
+void
+cgo_crypt_relay_forward(cgo_crypt_t *cgo, cell_t *cell,
+ const uint8_t **recognized_tag_out)
+{
+ uiv_tweak_t h = {
+ .h = cgo->tprime,
+ .cmd = cell->command,
+ };
+ memcpy(cgo->last_tag_relay_fwd, cell->payload, CGO_TAG_LEN);
+ cgo_uiv_encrypt(&cgo->uiv, h, cell->payload);
+ memcpy(cgo->tprime, cell->payload, CGO_TAG_LEN);
+ if (tor_memeq(cell->payload, cgo->nonce, CGO_TAG_LEN)) {
+ cgo_crypt_update(cgo, CGO_MODE_RELAY_FORWARD);
+ *recognized_tag_out = cgo->last_tag_relay_fwd;
+ } else {
+ *recognized_tag_out = NULL;
+ }
+}
+
+/**
+ * Backward CGO encryption operation at a relay:
+ * process an inbound cell from another relay, for the client.
+ */
+void
+cgo_crypt_relay_backward(cgo_crypt_t *cgo, cell_t *cell)
+{
+ uiv_tweak_t h = {
+ .h = cgo->tprime,
+ .cmd = cell->command,
+ };
+ cgo_uiv_encrypt(&cgo->uiv, h, cell->payload);
+ memcpy(cgo->tprime, cell->payload, CGO_TAG_LEN);
+}
+
+/**
+ * Backward CGO encryption operation at a relay:
+ * encrypt an inbound message that we are originating, for the client.
+ *
+ * The provided cell must have its command value set,
+ * and should have the first CGO_TAG_LEN bytes of its payload unused.
+ *
+ * Set '*tag_out' to a value that we should expect
+ * if we want an authenticated SENDME for this cell.
+ *
+ * The value of 'recognized_tag_out' will become invalid
+ * as soon as any change is made to this 'cgo' object,
+ * or to the cell; if you need it, you should copy it immediately.
+ */
+void
+cgo_crypt_relay_originate(cgo_crypt_t *cgo, cell_t *cell,
+ const uint8_t **tag_out)
+{
+ uiv_tweak_t h = {
+ .h = cgo->tprime,
+ .cmd = cell->command,
+ };
+ memcpy(cell->payload, cgo->nonce, CGO_TAG_LEN);
+ cgo_uiv_encrypt(&cgo->uiv, h, cell->payload);
+ memcpy(&cgo->tprime, cell->payload, CGO_TAG_LEN);
+ memcpy(&cgo->nonce, cell->payload, CGO_TAG_LEN);
+ if (tag_out) {
+ // tor_assert(tor_memeq(cgo->tprime, cell->payload, CGO_TAG_LEN));
+ *tag_out = cgo->tprime;
+ }
+ cgo_crypt_update(cgo, CGO_MODE_RELAY_BACKWARD);
+}
+
+/**
+ * Forward CGO encryption at a client:
+ * process a cell for a non-destination hop.
+ **/
+void
+cgo_crypt_client_forward(cgo_crypt_t *cgo, cell_t *cell)
+{
+ uint8_t tprime_new[CGO_TAG_LEN];
+ memcpy(tprime_new, cell->payload, CGO_TAG_LEN);
+ uiv_tweak_t h = {
+ .h = cgo->tprime,
+ .cmd = cell->command,
+ };
+ cgo_uiv_decrypt(&cgo->uiv, h, cell->payload);
+ memcpy(cgo->tprime, tprime_new, CGO_TAG_LEN);
+}
+
+/**
+ * Forward CGO encryption at a client:
+ * originate a cell for a given target hop.
+ *
+ * The provided cell must have its command value set,
+ * and should have the first CGO_TAG_LEN bytes of its payload unused.
+ *
+ * Set '*tag_out' to a value that we should expect
+ * if we want an authenticated SENDME for this cell.
+ *
+ * The value of 'recognized_tag_out' will become invalid
+ * as soon as any change is made to this 'cgo' object,
+ * or to the cell; if you need it, you should copy it immediately.
+ */
+void
+cgo_crypt_client_originate(cgo_crypt_t *cgo, cell_t *cell,
+ const uint8_t **tag_out)
+{
+ memcpy(cell->payload, cgo->nonce, CGO_TAG_LEN);
+ cgo_crypt_client_forward(cgo, cell);
+ cgo_crypt_update(cgo, CGO_MODE_CLIENT_FORWARD);
+ *tag_out = cell->payload;
+}
+
+/**
+ * Backward CGO encryption operation at a rclient.
+ * process an inbound cell from a relay.
+ *
+ * If the cell originated from this this relay, set *'recognized_tag_out'
+ * to point to a CGO_TAG_LEN value that should be used
+ * if we want to acknowledge this cell with an authenticated SENDME.
+ *
+ * The value of 'recognized_tag_out' will become invalid
+ * as soon as any change is made to this 'cgo' object,
+ * or to the cell; if you need it, you should copy it immediately.
+ *
+ * If the cell is not from this relay, set *'recognized_tag_out' to NULL.
+ */
+void
+cgo_crypt_client_backward(cgo_crypt_t *cgo, cell_t *cell,
+ const uint8_t **recognized_tag_out)
+{
+ uiv_tweak_t h = {
+ .h = cgo->tprime,
+ .cmd = cell->command,
+ };
+ uint8_t t_orig[CGO_TAG_LEN];
+ memcpy(t_orig, cell->payload, CGO_TAG_LEN);
+
+ cgo_uiv_decrypt(&cgo->uiv, h, cell->payload);
+ memcpy(cgo->tprime, t_orig, CGO_TAG_LEN);
+ if (tor_memeq(cell->payload, cgo->nonce, CGO_TAG_LEN)) {
+ memcpy(cgo->nonce, t_orig, CGO_TAG_LEN);
+ cgo_crypt_update(cgo, CGO_MODE_CLIENT_BACKWARD);
+ // tor_assert(tor_memeq(cgo->tprime, t_orig, CGO_TAG_LEN));
+ *recognized_tag_out = cgo->tprime;
+ } else {
+ *recognized_tag_out = NULL;
+ }
+}
diff --git a/src/core/crypto/relay_crypto_cgo.h b/src/core/crypto/relay_crypto_cgo.h
@@ -0,0 +1,218 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2025, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file relay_crypto_cgo.h
+ * \brief Header file for relay_crypto_cgo.c.
+ **/
+
+#ifndef TOR_RELAY_CRYPTO_CGO_H
+#define TOR_RELAY_CRYPTO_CGO_H
+
+#include "lib/testsupport/testsupport.h"
+
+/**
+ * State to implement forward _or_ reverse crypto between a client and a single
+ * hop on a circuit.
+ *
+ * (There needs to be one of these for each direction.
+ */
+typedef struct cgo_crypt_t cgo_crypt_t;
+
+typedef enum {
+ CGO_MODE_CLIENT_FORWARD,
+ CGO_MODE_CLIENT_BACKWARD,
+ CGO_MODE_RELAY_FORWARD,
+ CGO_MODE_RELAY_BACKWARD,
+} cgo_mode_t;
+
+/**
+ * Length of a CGO cell tag.
+ *
+ * This is the value used for authenticated SENDMES.
+ **/
+#define CGO_TAG_LEN 16
+
+struct cell_t;
+
+size_t cgo_key_material_len(int aesbits);
+cgo_crypt_t * cgo_crypt_new(cgo_mode_t mode, int aesbits,
+ const uint8_t *keys, size_t keylen);
+void cgo_crypt_free_(cgo_crypt_t *cgo);
+#define cgo_crypt_free(cgo) \
+ FREE_AND_NULL(cgo_crypt_t, cgo_crypt_free_, (cgo))
+
+void cgo_crypt_relay_forward(cgo_crypt_t *cgo, struct cell_t *cell,
+ const uint8_t **recognized_tag_out);
+void cgo_crypt_relay_backward(cgo_crypt_t *cgo, struct cell_t *cell);
+void cgo_crypt_relay_originate(cgo_crypt_t *cgo, struct cell_t *cell,
+ const uint8_t **tag_out);
+void cgo_crypt_client_forward(cgo_crypt_t *cgo, struct cell_t *cell);
+void cgo_crypt_client_originate(cgo_crypt_t *cgo, struct cell_t *cell,
+ const uint8_t **tag_out);
+void cgo_crypt_client_backward(cgo_crypt_t *cgo, struct cell_t *cell,
+ const uint8_t **recognized_tag_out);
+
+#ifdef RELAY_CRYPTO_CGO_PRIVATE
+/* Internal types and definitions for CGO encryption algorithms.
+ *
+ * Where reasonable, the identifiers here are chosen to match those
+ * in the spec (proposal 359), which in turn were chosen to match
+ * those in the paper.
+ */
+
+/**
+ * Tweakable block cipher, following the LRW2 construction,
+ * instantiated with AES.
+ *
+ * Any given instance can be used for encryption _or_ decryption,
+ * not both.
+ */
+typedef struct cgo_et_t {
+ /**
+ * AES block cipher instance
+ */
+ aes_raw_t *kb;
+ /**
+ * Polyval key.
+ */
+ polyval_key_t ku;
+} cgo_et_t;
+/**
+ * Keyed pseudorandom function, based on polyval and AES-CTR.
+ */
+typedef struct cgo_prf_t {
+ /**
+ * AES key: may be 128, 192, or 256 bits.
+ *
+ * Even though we're going to be using this in counter mode,
+ * we don't make an aes_cnt_cipher_t here, since that type
+ * does not support efficient re-use of the key with multiple
+ * IVs.
+ */
+ aes_raw_t *k;
+ /**
+ * Polyval instance.
+ */
+ polyval_key_t b;
+} cgo_prf_t;
+/**
+ * Rugged tweakable pseudorandom permutation, using the UIV+ construction.
+ *
+ * This is, roughly, a wide-block cipher where _encryption_
+ * is non-malleable, but where _decryption_ is malleable.
+ *
+ * UIV+ is the basis of CGO encryption, though it is used in different
+ * ways for each of the relay operations.
+ */
+typedef struct cgo_uiv_t {
+ /**
+ * Tweakable block cipher instance.
+ */
+ cgo_et_t j;
+ /**
+ * PRF instance.
+ */
+ cgo_prf_t s;
+#ifdef TOR_UNIT_TESTS
+ /** Testing only: Copy of keys used to instantiate this UIV.
+ * We use this in tests so that we can confirm the correctness
+ * of cgo_uiv_update().
+ */
+ uint8_t uiv_keys_[32 * 2 + 16 * 2];
+#endif
+} cgo_uiv_t;
+/**
+ * Length of the 'h' component of uiv_tweak_t.
+ */
+#define ET_TWEAK_LEN_H 16
+/**
+ * Length of the 'x_r' component of et_tweak_t.
+ */
+#define ET_TWEAK_LEN_X_R 493
+
+/**
+ * Tweak for the UIV+ wide-block cipher.
+ */
+typedef struct uiv_tweak_t {
+ /** H component of the wide-block cipher.
+ *
+ * This must be ET_TWEAK_LEN_H bytes long.
+ **/
+ const uint8_t *h;
+ /** Additional data component of the wide-block cipher.
+ * This value is sent to the cell command (RELAY or RELAY_EARLY)
+ * for each relay cell.
+ */
+ const uint8_t cmd;
+} uiv_tweak_t;
+/**
+ * Tweak for the ET tweakable block cipher.
+ */
+typedef struct et_tweak_t {
+ /** Components from the UIV+ tweak. */
+ uiv_tweak_t uiv;
+ /**
+ * X_R component of the ET tweak.
+ *
+ * This must be X_R bytes long.
+ */
+ const uint8_t *x_r;
+} et_tweak_t;
+
+/** Length of expected input to the PRF. */
+#define PRF_INPUT_LEN 16
+/** Output length for cgo_prf_xor_t0(). */
+#define PRF_T0_DATA_LEN 493
+
+/** Length of block handled by uiv instantiation. */
+#define UIV_BLOCK_LEN 509
+
+STATIC int cgo_et_init(cgo_et_t *et, int aesbits, bool encrypt,
+ const uint8_t *key);
+STATIC void cgo_et_set_key(cgo_et_t *et, int aesbits, bool encrypt,
+ const uint8_t *key);
+STATIC void cgo_et_encrypt(cgo_et_t *et, const et_tweak_t tweak,
+ uint8_t *block);
+STATIC void cgo_et_decrypt(cgo_et_t *et, const et_tweak_t tweak,
+ uint8_t *block);
+STATIC void cgo_et_clear(cgo_et_t *et);
+
+STATIC int cgo_prf_init(cgo_prf_t *prf, int aesbits,
+ const uint8_t *key);
+STATIC void cgo_prf_set_key(cgo_prf_t *prf, int aesbits,
+ const uint8_t *key);
+STATIC void cgo_prf_xor_t0(cgo_prf_t *prf, const uint8_t *input,
+ uint8_t *data);
+STATIC void cgo_prf_gen_t1(cgo_prf_t *prf, const uint8_t *input,
+ uint8_t *buf, size_t n);
+STATIC void cgo_prf_clear(cgo_prf_t *prf);
+
+STATIC int cgo_uiv_init(cgo_uiv_t *uiv, int aesbits, bool encrypt,
+ const uint8_t *key);
+STATIC void cgo_uiv_encrypt(cgo_uiv_t *uiv, const uiv_tweak_t tweak,
+ uint8_t *cell_body);
+STATIC void cgo_uiv_decrypt(cgo_uiv_t *uiv, const uiv_tweak_t tweak,
+ uint8_t *cell_body);
+STATIC void cgo_uiv_update(cgo_uiv_t *uiv, int aesbits, bool encrypt,
+ uint8_t *nonce);
+STATIC void cgo_uiv_clear(cgo_uiv_t *uiv);
+
+struct cgo_crypt_t {
+ cgo_uiv_t uiv;
+ uint8_t nonce[CGO_TAG_LEN];
+ uint8_t tprime[CGO_TAG_LEN];
+ /**
+ * Stored version of the last incoming cell tag.
+ * Only used for cgo_crypt_relay_fwd, where this information is not
+ * otherwise available after encryption.
+ */
+ uint8_t last_tag_relay_fwd[CGO_TAG_LEN];
+ uint8_t aes_bytes;
+};
+#endif
+
+#endif /* !defined(TOR_RELAY_CRYPTO_CGO_H) */
diff --git a/src/ext/include.am b/src/ext/include.am
@@ -216,6 +216,21 @@ LIBKECCAK_TINY=src/ext/keccak-tiny/libkeccak-tiny.a
noinst_LIBRARIES += $(LIBKECCAK_TINY)
endif
+src_ext_polyval_libpolyval_a_CFLAGS=\
+ @CFLAGS_CONSTTIME@
+src_ext_polyval_libpolyval_a_SOURCES= \
+ src/ext/polyval/polyval.c
+
+POLYVAL_HDRS = \
+ src/ext/polyval/polyval.h \
+ src/ext/polyval/pclmul.c \
+ src/ext/polyval/ctmul64.c \
+ src/ext/polyval/ctmul.c
+
+noinst_HEADERS += $(POLYVAL_HDRS)
+LIBPOLYVAL=src/ext/polyval/libpolyval.a
+noinst_LIBRARIES += $(LIBPOLYVAL)
+
EXTRA_DIST += \
src/ext/timeouts/bench/bench-add.lua \
src/ext/timeouts/bench/bench-aux.lua \
diff --git a/src/ext/polyval/README.tor b/src/ext/polyval/README.tor
@@ -0,0 +1,28 @@
+This code is based on the constant-time GHASH implementations
+from BearSSL, written by Thomas Pornin.
+
+Up-to-date with BearSSL as of 3c040368f6791553610e362401db1efff4b4c5b8.
+
+The license on that code is:
+
+> Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+>
+> Permission is hereby granted, free of charge, to any person obtaining
+> a copy of this software and associated documentation files (the
+> "Software"), to deal in the Software without restriction, including
+> without limitation the rights to use, copy, modify, merge, publish,
+> distribute, sublicense, and/or sell copies of the Software, and to
+> permit persons to whom the Software is furnished to do so, subject to
+> the following conditions:
+>
+> The above copyright notice and this permission notice shall be
+> included in all copies or substantial portions of the Software.
+>
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+> BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+> ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+> CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+> SOFTWARE.
diff --git a/src/ext/polyval/ctmul.c b/src/ext/polyval/ctmul.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * We compute "carryless multiplications" through normal integer
+ * multiplications, masking out enough bits to create "holes" in which
+ * carries may expand without altering our bits; we really use 8 data
+ * bits per 32-bit word, spaced every fourth bit. Accumulated carries
+ * may not exceed 8 in total, which fits in 4 bits.
+ *
+ * It would be possible to use a 3-bit spacing, allowing two operands,
+ * one with 7 non-zero data bits, the other one with 10 or 11 non-zero
+ * data bits; this asymmetric splitting makes the overall code more
+ * complex with thresholds and exceptions, and does not appear to be
+ * worth the effort.
+ */
+
+/*
+ * We cannot really autodetect whether multiplications are "slow" or
+ * not. A typical example is the ARM Cortex M0+, which exists in two
+ * versions: one with a 1-cycle multiplication opcode, the other with
+ * a 32-cycle multiplication opcode. They both use exactly the same
+ * architecture and ABI, and cannot be distinguished from each other
+ * at compile-time.
+ *
+ * Since most modern CPU (even embedded CPU) still have fast
+ * multiplications, we use the "fast mul" code by default.
+ */
+
+// A 32x32 -> 64 multiply.
+#define MUL(x, y) (((uint64_t)(x)) * ((uint64_t)(y)))
+
+#ifdef BR_SLOW_MUL
+
+/*
+ * This implementation uses Karatsuba-like reduction to make fewer
+ * integer multiplications (9 instead of 16), at the expense of extra
+ * logical operations (XOR, shifts...). On modern x86 CPU that offer
+ * fast, pipelined multiplications, this code is about twice slower than
+ * the simpler code with 16 multiplications. This tendency may be
+ * reversed on low-end platforms with expensive multiplications.
+ */
+
+#define MUL32(h, l, x, y) do { \
+ uint64_t mul32tmp = MUL(x, y); \
+ (h) = (uint32_t)(mul32tmp >> 32); \
+ (l) = (uint32_t)mul32tmp; \
+ } while (0)
+
+static inline void
+bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y)
+{
+ uint32_t x0, x1, x2, x3;
+ uint32_t y0, y1, y2, y3;
+ uint32_t a0, a1, a2, a3, a4, a5, a6, a7, a8;
+ uint32_t b0, b1, b2, b3, b4, b5, b6, b7, b8;
+
+ x0 = x & (uint32_t)0x11111111;
+ x1 = x & (uint32_t)0x22222222;
+ x2 = x & (uint32_t)0x44444444;
+ x3 = x & (uint32_t)0x88888888;
+ y0 = y & (uint32_t)0x11111111;
+ y1 = y & (uint32_t)0x22222222;
+ y2 = y & (uint32_t)0x44444444;
+ y3 = y & (uint32_t)0x88888888;
+
+ /*
+ * (x0+W*x1)*(y0+W*y1) -> a0:b0
+ * (x2+W*x3)*(y2+W*y3) -> a3:b3
+ * ((x0+x2)+W*(x1+x3))*((y0+y2)+W*(y1+y3)) -> a6:b6
+ */
+ a0 = x0;
+ b0 = y0;
+ a1 = x1 >> 1;
+ b1 = y1 >> 1;
+ a2 = a0 ^ a1;
+ b2 = b0 ^ b1;
+ a3 = x2 >> 2;
+ b3 = y2 >> 2;
+ a4 = x3 >> 3;
+ b4 = y3 >> 3;
+ a5 = a3 ^ a4;
+ b5 = b3 ^ b4;
+ a6 = a0 ^ a3;
+ b6 = b0 ^ b3;
+ a7 = a1 ^ a4;
+ b7 = b1 ^ b4;
+ a8 = a6 ^ a7;
+ b8 = b6 ^ b7;
+
+ MUL32(b0, a0, b0, a0);
+ MUL32(b1, a1, b1, a1);
+ MUL32(b2, a2, b2, a2);
+ MUL32(b3, a3, b3, a3);
+ MUL32(b4, a4, b4, a4);
+ MUL32(b5, a5, b5, a5);
+ MUL32(b6, a6, b6, a6);
+ MUL32(b7, a7, b7, a7);
+ MUL32(b8, a8, b8, a8);
+
+ a0 &= (uint32_t)0x11111111;
+ a1 &= (uint32_t)0x11111111;
+ a2 &= (uint32_t)0x11111111;
+ a3 &= (uint32_t)0x11111111;
+ a4 &= (uint32_t)0x11111111;
+ a5 &= (uint32_t)0x11111111;
+ a6 &= (uint32_t)0x11111111;
+ a7 &= (uint32_t)0x11111111;
+ a8 &= (uint32_t)0x11111111;
+ b0 &= (uint32_t)0x11111111;
+ b1 &= (uint32_t)0x11111111;
+ b2 &= (uint32_t)0x11111111;
+ b3 &= (uint32_t)0x11111111;
+ b4 &= (uint32_t)0x11111111;
+ b5 &= (uint32_t)0x11111111;
+ b6 &= (uint32_t)0x11111111;
+ b7 &= (uint32_t)0x11111111;
+ b8 &= (uint32_t)0x11111111;
+
+ a2 ^= a0 ^ a1;
+ b2 ^= b0 ^ b1;
+ a0 ^= (a2 << 1) ^ (a1 << 2);
+ b0 ^= (b2 << 1) ^ (b1 << 2);
+ a5 ^= a3 ^ a4;
+ b5 ^= b3 ^ b4;
+ a3 ^= (a5 << 1) ^ (a4 << 2);
+ b3 ^= (b5 << 1) ^ (b4 << 2);
+ a8 ^= a6 ^ a7;
+ b8 ^= b6 ^ b7;
+ a6 ^= (a8 << 1) ^ (a7 << 2);
+ b6 ^= (b8 << 1) ^ (b7 << 2);
+ a6 ^= a0 ^ a3;
+ b6 ^= b0 ^ b3;
+ *lo = a0 ^ (a6 << 2) ^ (a3 << 4);
+ *hi = b0 ^ (b6 << 2) ^ (b3 << 4) ^ (a6 >> 30) ^ (a3 >> 28);
+}
+
+#else
+
+/*
+ * Simple multiplication in GF(2)[X], using 16 integer multiplications.
+ */
+
+static inline void
+bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y)
+{
+ uint32_t x0, x1, x2, x3;
+ uint32_t y0, y1, y2, y3;
+ uint64_t z0, z1, z2, z3;
+ uint64_t z;
+
+ x0 = x & (uint32_t)0x11111111;
+ x1 = x & (uint32_t)0x22222222;
+ x2 = x & (uint32_t)0x44444444;
+ x3 = x & (uint32_t)0x88888888;
+ y0 = y & (uint32_t)0x11111111;
+ y1 = y & (uint32_t)0x22222222;
+ y2 = y & (uint32_t)0x44444444;
+ y3 = y & (uint32_t)0x88888888;
+ z0 = MUL(x0, y0) ^ MUL(x1, y3) ^ MUL(x2, y2) ^ MUL(x3, y1);
+ z1 = MUL(x0, y1) ^ MUL(x1, y0) ^ MUL(x2, y3) ^ MUL(x3, y2);
+ z2 = MUL(x0, y2) ^ MUL(x1, y1) ^ MUL(x2, y0) ^ MUL(x3, y3);
+ z3 = MUL(x0, y3) ^ MUL(x1, y2) ^ MUL(x2, y1) ^ MUL(x3, y0);
+ z0 &= (uint64_t)0x1111111111111111;
+ z1 &= (uint64_t)0x2222222222222222;
+ z2 &= (uint64_t)0x4444444444444444;
+ z3 &= (uint64_t)0x8888888888888888;
+ z = z0 | z1 | z2 | z3;
+ *lo = (uint32_t)z;
+ *hi = (uint32_t)(z >> 32);
+}
+
+#endif
+
+static void
+pv_mul_y_h(polyval_t *pv)
+{
+ uint32_t *yw = pv->y.v;
+ const uint32_t *hw = pv->key.h.v;
+
+ /*
+ * Throughout the loop we handle the y and h values as arrays
+ * of 32-bit words.
+ */
+ {
+ int i;
+ uint32_t a[9], b[9], zw[8];
+ uint32_t c0, c1, c2, c3, d0, d1, d2, d3, e0, e1, e2, e3;
+
+ /*
+ * We multiply two 128-bit field elements. We use
+ * Karatsuba to turn that into three 64-bit
+ * multiplications, which are themselves done with a
+ * total of nine 32-bit multiplications.
+ */
+
+ /*
+ * y[0,1]*h[0,1] -> 0..2
+ * y[2,3]*h[2,3] -> 3..5
+ * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6..8
+ */
+ a[0] = yw[0];
+ b[0] = hw[0];
+ a[1] = yw[1];
+ b[1] = hw[1];
+ a[2] = a[0] ^ a[1];
+ b[2] = b[0] ^ b[1];
+
+ a[3] = yw[2];
+ b[3] = hw[2];
+ a[4] = yw[3];
+ b[4] = hw[3];
+ a[5] = a[3] ^ a[4];
+ b[5] = b[3] ^ b[4];
+
+ a[6] = a[0] ^ a[3];
+ b[6] = b[0] ^ b[3];
+ a[7] = a[1] ^ a[4];
+ b[7] = b[1] ^ b[4];
+ a[8] = a[6] ^ a[7];
+ b[8] = b[6] ^ b[7];
+
+ for (i = 0; i < 9; i ++) {
+ bmul(&b[i], &a[i], b[i], a[i]);
+ }
+
+ c0 = a[0];
+ c1 = b[0] ^ a[2] ^ a[0] ^ a[1];
+ c2 = a[1] ^ b[2] ^ b[0] ^ b[1];
+ c3 = b[1];
+ d0 = a[3];
+ d1 = b[3] ^ a[5] ^ a[3] ^ a[4];
+ d2 = a[4] ^ b[5] ^ b[3] ^ b[4];
+ d3 = b[4];
+ e0 = a[6];
+ e1 = b[6] ^ a[8] ^ a[6] ^ a[7];
+ e2 = a[7] ^ b[8] ^ b[6] ^ b[7];
+ e3 = b[7];
+
+ e0 ^= c0 ^ d0;
+ e1 ^= c1 ^ d1;
+ e2 ^= c2 ^ d2;
+ e3 ^= c3 ^ d3;
+ c2 ^= e0;
+ c3 ^= e1;
+ d0 ^= e2;
+ d1 ^= e3;
+
+#if 0
+ // This rotation is GHASH-only.
+ /*
+ * GHASH specification has the bits "reversed" (most
+ * significant is in fact least significant), which does
+ * not matter for a carryless multiplication, except that
+ * the 255-bit result must be shifted by 1 bit.
+ */
+ zw[0] = c0 << 1;
+ zw[1] = (c1 << 1) | (c0 >> 31);
+ zw[2] = (c2 << 1) | (c1 >> 31);
+ zw[3] = (c3 << 1) | (c2 >> 31);
+ zw[4] = (d0 << 1) | (c3 >> 31);
+ zw[5] = (d1 << 1) | (d0 >> 31);
+ zw[6] = (d2 << 1) | (d1 >> 31);
+ zw[7] = (d3 << 1) | (d2 >> 31);
+#else
+ zw[0] = c0;
+ zw[1] = c1;
+ zw[2] = c2;
+ zw[3] = c3;
+ zw[4] = d0;
+ zw[5] = d1;
+ zw[6] = d2;
+ zw[7] = d3;
+#endif
+
+ /*
+ * We now do the reduction modulo the field polynomial
+ * to get back to 128 bits.
+ */
+ for (i = 0; i < 4; i ++) {
+ uint32_t lw;
+
+ lw = zw[i];
+ zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7);
+ zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25);
+ }
+ memcpy(yw, zw + 4, 16);
+ }
+}
+#undef MUL
diff --git a/src/ext/polyval/ctmul64.c b/src/ext/polyval/ctmul64.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * This is the 64-bit variant of br_ghash_ctmul32(), with 64-bit operands
+ * and bit reversal of 64-bit words.
+ */
+
+static inline uint64_t
+bmul64(uint64_t x, uint64_t y)
+{
+ uint64_t x0, x1, x2, x3;
+ uint64_t y0, y1, y2, y3;
+ uint64_t z0, z1, z2, z3;
+
+ x0 = x & (uint64_t)0x1111111111111111;
+ x1 = x & (uint64_t)0x2222222222222222;
+ x2 = x & (uint64_t)0x4444444444444444;
+ x3 = x & (uint64_t)0x8888888888888888;
+ y0 = y & (uint64_t)0x1111111111111111;
+ y1 = y & (uint64_t)0x2222222222222222;
+ y2 = y & (uint64_t)0x4444444444444444;
+ y3 = y & (uint64_t)0x8888888888888888;
+ z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);
+ z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);
+ z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);
+ z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);
+ z0 &= (uint64_t)0x1111111111111111;
+ z1 &= (uint64_t)0x2222222222222222;
+ z2 &= (uint64_t)0x4444444444444444;
+ z3 &= (uint64_t)0x8888888888888888;
+ return z0 | z1 | z2 | z3;
+}
+
+static uint64_t
+rev64(uint64_t x)
+{
+#define RMS(m, s) do { \
+ x = ((x & (uint64_t)(m)) << (s)) \
+ | ((x >> (s)) & (uint64_t)(m)); \
+ } while (0)
+
+ RMS(0x5555555555555555, 1);
+ RMS(0x3333333333333333, 2);
+ RMS(0x0F0F0F0F0F0F0F0F, 4);
+ RMS(0x00FF00FF00FF00FF, 8);
+ RMS(0x0000FFFF0000FFFF, 16);
+ return (x << 32) | (x >> 32);
+
+#undef RMS
+}
+
+
+static void
+pv_mul_y_h(polyval_t *pv)
+{
+ uint64_t y0, y1;
+ uint64_t h0, h1, h2, h0r, h1r, h2r;
+
+ y0 = pv->y.lo;
+ y1 = pv->y.hi;
+ h0 = pv->key.h.lo;
+ h1 = pv->key.h.hi;
+ h0r = rev64(h0);
+ h1r = rev64(h1);
+
+ h2 = h0 ^ h1;
+ h2r = h0r ^ h1r;
+ {
+ uint64_t y0r, y1r, y2, y2r;
+ uint64_t z0, z1, z2, z0h, z1h, z2h;
+ uint64_t v0, v1, v2, v3;
+
+ y0r = rev64(y0);
+ y1r = rev64(y1);
+ y2 = y0 ^ y1;
+ y2r = y0r ^ y1r;
+
+ z0 = bmul64(y0, h0);
+ z1 = bmul64(y1, h1);
+ z2 = bmul64(y2, h2);
+ z0h = bmul64(y0r, h0r);
+ z1h = bmul64(y1r, h1r);
+ z2h = bmul64(y2r, h2r);
+ z2 ^= z0 ^ z1;
+ z2h ^= z0h ^ z1h;
+ z0h = rev64(z0h) >> 1;
+ z1h = rev64(z1h) >> 1;
+ z2h = rev64(z2h) >> 1;
+
+ v0 = z0;
+ v1 = z0h ^ z2;
+ v2 = z1 ^ z2h;
+ v3 = z1h;
+
+#if 0
+ // This step is GHASH only.
+ v3 = (v3 << 1) | (v2 >> 63);
+ v2 = (v2 << 1) | (v1 >> 63);
+ v1 = (v1 << 1) | (v0 >> 63);
+ v0 = (v0 << 1);
+#endif
+
+ v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7);
+ v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57);
+ v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7);
+ v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57);
+
+ pv->y.lo = v2;
+ pv->y.hi = v3;
+ }
+}
diff --git a/src/ext/polyval/pclmul.c b/src/ext/polyval/pclmul.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * This is the GHASH implementation that leverages the pclmulqdq opcode
+ * (from the AES-NI instructions).
+ */
+
+#include <wmmintrin.h>
+
+#ifndef __GNUC__
+#define __attribute__(x)
+#endif
+
+#define BR_TARGET(x) __attribute__((target(x)))
+
+#if defined(__GNUC__) && !defined(__clang__)
+ _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul\")")
+#endif
+
+#if 0
+/*
+ * Test CPU support for PCLMULQDQ.
+ */
+static inline int
+pclmul_supported(void)
+{
+ /*
+ * Bit mask for features in ECX:
+ * 1 PCLMULQDQ support
+ */
+ return br_cpuid(0, 0, 0x00000002, 0);
+}
+
+/* see bearssl_hash.h */
+br_ghash
+br_ghash_pclmul_get(void)
+{
+ return pclmul_supported() ? &br_ghash_pclmul : 0;
+}
+
+BR_TARGETS_X86_UP
+#endif
+/*
+ * Call pclmulqdq. Clang appears to have trouble with the intrinsic, so,
+ * for that compiler, we use inline assembly. Inline assembly is
+ * potentially a bit slower because the compiler does not understand
+ * what the opcode does, and thus cannot optimize instruction
+ * scheduling.
+ *
+ * We use a target of "sse2" only, so that Clang may still handle the
+ * '__m128i' type and allocate SSE2 registers.
+ */
+#ifdef __clang__
+ BR_TARGET("sse2")
+static inline __m128i
+pclmulqdq00(__m128i x, __m128i y)
+{
+ __asm__ ("pclmulqdq $0x00, %1, %0" : "+x" (x) : "x" (y));
+ return x;
+}
+BR_TARGET("sse2")
+static inline __m128i
+pclmulqdq11(__m128i x, __m128i y)
+{
+ __asm__ ("pclmulqdq $0x11, %1, %0" : "+x" (x) : "x" (y));
+ return x;
+}
+#else
+#define pclmulqdq00(x, y) _mm_clmulepi64_si128(x, y, 0x00)
+#define pclmulqdq11(x, y) _mm_clmulepi64_si128(x, y, 0x11)
+#endif
+
+/*
+ * From a 128-bit value kw, compute kx as the XOR of the two 64-bit
+ * halves of kw (into the right half of kx; left half is unspecified).
+ */
+#define BK(kw, kx) do { \
+ kx = _mm_xor_si128(kw, _mm_shuffle_epi32(kw, 0x0E)); \
+ } while (0)
+
+/*
+ * Combine two 64-bit values (k0:k1) into a 128-bit (kw) value and
+ * the XOR of the two values (kx).
+ */
+#define PBK(k0, k1, kw, kx) do { \
+ kw = _mm_unpacklo_epi64(k1, k0); \
+ kx = _mm_xor_si128(k0, k1); \
+ } while (0)
+
+/*
+ * Perform reduction in GF(2^128). The 256-bit value is in x0..x3;
+ * result is written in x0..x1.
+ */
+#define REDUCE_F128(x0, x1, x2, x3) do { \
+ x1 = _mm_xor_si128( \
+ x1, \
+ _mm_xor_si128( \
+ _mm_xor_si128( \
+ x3, \
+ _mm_srli_epi64(x3, 1)), \
+ _mm_xor_si128( \
+ _mm_srli_epi64(x3, 2), \
+ _mm_srli_epi64(x3, 7)))); \
+ x2 = _mm_xor_si128( \
+ _mm_xor_si128( \
+ x2, \
+ _mm_slli_epi64(x3, 63)), \
+ _mm_xor_si128( \
+ _mm_slli_epi64(x3, 62), \
+ _mm_slli_epi64(x3, 57))); \
+ x0 = _mm_xor_si128( \
+ x0, \
+ _mm_xor_si128( \
+ _mm_xor_si128( \
+ x2, \
+ _mm_srli_epi64(x2, 1)), \
+ _mm_xor_si128( \
+ _mm_srli_epi64(x2, 2), \
+ _mm_srli_epi64(x2, 7)))); \
+ x1 = _mm_xor_si128( \
+ _mm_xor_si128( \
+ x1, \
+ _mm_slli_epi64(x2, 63)), \
+ _mm_xor_si128( \
+ _mm_slli_epi64(x2, 62), \
+ _mm_slli_epi64(x2, 57))); \
+ } while (0)
+
+
+/* see bearssl_hash.h */
+BR_TARGET("ssse3,pclmul")
+static
+void pv_mul_y_h(polyval_t *pv)
+{
+ __m128i yw, h1w, h1x;
+
+ h1w = pv->key.h;
+ BK(h1w, h1x);
+
+ {
+ __m128i aw, ax;
+ __m128i t0, t1, t2, t3;
+
+ aw = pv->y;
+ BK(aw, ax);
+
+ t1 = pclmulqdq11(aw, h1w);
+ t3 = pclmulqdq00(aw, h1w);
+ t2 = pclmulqdq00(ax, h1x);
+ t2 = _mm_xor_si128(t2, _mm_xor_si128(t1, t3));
+ t0 = _mm_shuffle_epi32(t1, 0x0E);
+ t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E));
+ t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E));
+#if 0 // This step is GHASH-only.
+ SL_256(t0, t1, t2, t3);
+#endif
+ REDUCE_F128(t0, t1, t2, t3);
+ yw = _mm_unpacklo_epi64(t1, t0);
+ }
+
+ pv->y = yw;
+}
diff --git a/src/ext/polyval/polyval.c b/src/ext/polyval/polyval.c
@@ -0,0 +1,280 @@
+/* Copyright (c) 2025, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file polyval.h
+ * \brief Implementation for polyval universal hash function.
+ *
+ * Polyval, which was first defined for AES-GCM-SIV, is a
+ * universal hash based on multiplication in GF(2^128).
+ * Unlike the more familiar GHASH, it is defined to work on
+ * little-endian inputs, and so is more straightforward and efficient
+ * on little-endian architectures.
+ *
+ * In Tor we use it as part of the Counter Galois Onion relay
+ * encryption format.
+ **/
+
+/* Implementation notes:
+ *
+ * Our implementation is based on the GHASH code from BearSSL
+ * by Thomas Pornin. There are three implementations:
+ *
+ * pclmul.c -- An x86-only version, based on the CLMUL instructions
+ * introduced for westlake processors in 2010.
+ *
+ * ctmul64.c -- A portable contant-time implementation for 64-bit
+ * processors.
+ *
+ * ctmul.c -- A portable constant-time implementation for 32-bit
+ * processors with an efficient 32x32->64 multiply instruction.
+ *
+ * Note that the "ctmul" implementations are only constant-time
+ * if the corresponding CPU multiply and rotate instructions are
+ * also constant-time. But that's an architectural assumption we
+ * make in Tor.
+ */
+
+#include "ext/polyval/polyval.h"
+
+#include <string.h>
+
+typedef pv_u128_ u128;
+
+/* ========
+ * We declare these functions, to help implement polyval.
+ *
+ * They have different definitions depending on our representation
+ * of 128-bit integers.
+ */
+/**
+ * Read a u128-bit little-endian integer from 'bytes',
+ * which may not be aligned.
+ */
+static inline u128 u128_from_bytes(const uint8_t *bytes);
+/**
+ * Store a u128-bit little-endian integer to 'bytes_out',
+ * which may not be aligned.
+ */
+static inline void u128_to_bytes(u128, uint8_t *bytes_out);
+/**
+ * XOR a u128 into the y field of a polyval_t struct.
+ *
+ * (Within the polyval struct, perform "y ^= v").
+ */
+static inline void pv_xor_y(polyval_t *, u128 v);
+
+/* ========
+ * The function which we expect our backend to implement.
+ */
+/**
+ * Within the polyval struct, perform "y *= h".
+ *
+ * (This is a carryless multiply in the Polyval galois field)
+ */
+static void pv_mul_y_h(polyval_t *);
+
+/* =====
+ * Endianness conversion for big-endian platforms
+ */
+#ifdef WORDS_BIG_ENDIAN
+#ifdef __GNUC__
+#define bswap64(x) __builtin_bswap64(x)
+#define bswap32(x) __builtin_bswap32(x)
+#else
+/* The (compiler should optimize these into a decent bswap instruction) */
+static inline uint64_t
+bswap64(uint64_t v)
+{
+ return
+ ((value & 0xFF00000000000000) >> 56) |
+ ((value & 0x00FF000000000000) >> 48) |
+ ((value & 0x0000FF0000000000) >> 40) |
+ ((value & 0x000000FF00000000) >> 32) |
+ ((value & 0x00000000FF000000) >> 24) |
+ ((value & 0x0000000000FF0000) >> 16) |
+ ((value & 0x000000000000FF00) >> 8) |
+ ((value & 0x00000000000000FF));
+}
+static inline uint64_t
+bswap32(uint64_t v)
+{
+ return
+ ((value & 0xFF000000) >> 24) |
+ ((value & 0x00FF0000) >> 16) |
+ ((value & 0x0000FF00) >> 8) |
+ ((value & 0x000000FF));
+}
+#endif
+#endif
+
+#ifdef WORDS_BIG_ENDIAN
+#define convert_byte_order64(x) bswap64(x)
+#define convert_byte_order32(x) bswap32(x)
+#else
+#define convert_byte_order64(x) (x)
+#define convert_byte_order32(x) (x)
+#endif
+
+#ifdef PV_USE_PCLMUL
+
+#include "ext/polyval/pclmul.c"
+
+static inline u128
+u128_from_bytes(const uint8_t *bytes)
+{
+ return _mm_loadu_si128((const u128*)bytes);
+}
+static inline void
+u128_to_bytes(u128 val, uint8_t *bytes_out)
+{
+ _mm_storeu_si128((u128*)bytes_out, val);
+}
+static inline void
+pv_xor_y(polyval_t *pv, u128 v)
+{
+ pv->y = _mm_xor_si128(pv->y, v);
+}
+#elif defined(PV_USE_CTMUL64)
+
+#include "ext/polyval/ctmul64.c"
+
+static inline u128
+u128_from_bytes(const uint8_t *bytes)
+{
+ u128 r;
+ memcpy(&r.lo, bytes, 8);
+ memcpy(&r.hi, bytes + 8, 8);
+ r.lo = convert_byte_order64(r.lo);
+ r.hi = convert_byte_order64(r.hi);
+ return r;
+}
+static inline void
+u128_to_bytes(u128 val, uint8_t *bytes_out)
+{
+ uint64_t lo = convert_byte_order64(val.lo);
+ uint64_t hi = convert_byte_order64(val.hi);
+ memcpy(bytes_out, &lo, 8);
+ memcpy(bytes_out + 8, &hi, 8);
+}
+static inline void
+pv_xor_y(polyval_t *pv, u128 val)
+{
+ pv->y.lo ^= val.lo;
+ pv->y.hi ^= val.hi;
+}
+#elif defined(PV_USE_CTMUL)
+#include "ext/polyval/ctmul.c"
+
+static inline u128
+u128_from_bytes(const uint8_t *bytes)
+{
+ u128 r;
+ memcpy(&r.v, bytes, 16);
+ for (int i = 0; i < 4; ++i) {
+ r.v[i] = convert_byte_order32(r.v[i]);
+ }
+ return r;
+}
+static inline void
+u128_to_bytes(u128 val, uint8_t *bytes_out)
+{
+ uint32_t v[4];
+ for (int i = 0; i < 4; ++i) {
+ v[i] = convert_byte_order32(val.v[i]);
+ }
+ memcpy(bytes_out, v, 16);
+}
+static inline void
+pv_xor_y(polyval_t *pv, u128 val)
+{
+ for (int i = 0; i < 4; ++i) {
+ pv->y.v[i] ^= val.v[i];
+ }
+}
+#endif
+
+void
+polyval_key_init(polyval_key_t *pvk, const uint8_t *key)
+{
+ pvk->h = u128_from_bytes(key);
+}
+void
+polyval_init(polyval_t *pv, const uint8_t *key)
+{
+ polyval_key_init(&pv->key, key);
+ memset(&pv->y, 0, sizeof(u128));
+}
+void
+polyval_init_from_key(polyval_t *pv, const polyval_key_t *key)
+{
+ memcpy(&pv->key, key, sizeof(polyval_key_t));
+ memset(&pv->y, 0, sizeof(u128));
+}
+void
+polyval_add_block(polyval_t *pv, const uint8_t *block)
+{
+ u128 b = u128_from_bytes(block);
+ pv_xor_y(pv, b);
+ pv_mul_y_h(pv);
+}
+void
+polyval_add_zpad(polyval_t *pv, const uint8_t *data, size_t n)
+{
+ while (n > 16) {
+ polyval_add_block(pv, data);
+ data += 16;
+ n -= 16;
+ }
+ if (n) {
+ uint8_t block[16];
+ memset(&block, 0, sizeof(block));
+ memcpy(block, data, n);
+ polyval_add_block(pv, block);
+ }
+}
+void
+polyval_get_tag(const polyval_t *pv, uint8_t *tag_out)
+{
+ u128_to_bytes(pv->y, tag_out);
+}
+void
+polyval_reset(polyval_t *pv)
+{
+ memset(&pv->y, 0, sizeof(u128));
+}
+
+#if 0
+#include <stdio.h>
+int
+main(int c, char **v)
+{
+ // From RFC 8452 appendix A
+ uint8_t key[16] =
+ { 0x25, 0x62, 0x93, 0x47, 0x58, 0x92, 0x42, 0x76,
+ 0x1d, 0x31, 0xf8, 0x26, 0xba, 0x4b, 0x75, 0x7b };
+ uint8_t block1[16] =
+ { 0x4f, 0x4f, 0x95, 0x66, 0x8c, 0x83, 0xdf, 0xb6,
+ 0x40, 0x17, 0x62, 0xbb, 0x2d, 0x01, 0xa2, 0x62 };
+ uint8_t block2[16] = {
+ 0xd1, 0xa2, 0x4d, 0xdd, 0x27, 0x21, 0xd0, 0x06,
+ 0xbb, 0xe4, 0x5f, 0x20, 0xd3, 0xc9, 0xf3, 0x62 };
+ uint8_t expect_result[16] = {
+ 0xf7, 0xa3, 0xb4, 0x7b, 0x84, 0x61, 0x19, 0xfa,
+ 0xe5, 0xb7, 0x86, 0x6c, 0xf5, 0xe5, 0xb7, 0x7e };
+
+ polyval_t pv;
+ uint8_t tag[16];
+ polyval_init(&pv, key);
+ polyval_add_block(&pv, block1);
+ polyval_add_block(&pv, block2);
+ polyval_get_tag(&pv, tag);
+ if (!memcmp(expect_result, tag, 16)) {
+ puts("OK");
+ return 0;
+ } else {
+ puts("NOPE");
+ return 1;
+ }
+}
+#endif
diff --git a/src/ext/polyval/polyval.h b/src/ext/polyval/polyval.h
@@ -0,0 +1,120 @@
+/* Copyright (c) 2025, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file polyval.h
+ * \brief APIs for polyval universal hash function.
+ **/
+
+#ifndef TOR_POLYVAL_H
+#define TOR_POLYVAL_H
+
+#include "orconfig.h"
+#include "lib/cc/torint.h"
+
+/* Decide which implementation to use. */
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) \
+ || defined(_M_X64) || defined(_M_IX86) || defined(__i486) \
+ || defined(__i386__)
+/* Use intel intrinsics for carryless multiply.
+ *
+ * TODO: In theory we should detect whether we have the relevant instructions,
+ * but they are all at least 15 years old.
+ */
+#define PV_USE_PCLMUL
+#elif SIZEOF_VOID_P >= 8
+/* It's a 64-bit architecture; use the generic 64-bit constant-time
+ * implementation.
+ */
+#define PV_USE_CTMUL64
+#elif SIZEOF_VOID_P == 4
+/* It's a 64-bit architecture; use the generic 32-bit constant-time
+ * implementation.
+ */
+#define PV_USE_CTMUL
+#else
+#error "sizeof(void*) is implausibly weird."
+#endif
+
+/**
+ * Declare a 128 bit integer type.
+ # The exact representation will depend on which implementation we've chosen.
+ */
+#ifdef PV_USE_PCLMUL
+#include <emmintrin.h>
+typedef __m128i pv_u128_;
+#elif defined(PV_USE_CTMUL64)
+typedef struct pv_u128_ {
+ uint64_t lo;
+ uint64_t hi;
+} pv_u128_;
+#elif defined(PV_USE_CTMUL)
+typedef struct pv_u128_ {
+ uint32_t v[4];
+} pv_u128_;
+#endif
+
+/** A key for a polyval hash, plus any precomputed key material. */
+typedef struct polyval_key_t {
+ pv_u128_ h;
+} polyval_key_t;
+
+/**
+ * State for an instance of the polyval hash.
+ **/
+typedef struct polyval_t {
+ /** The key used for this instance of polyval. */
+ polyval_key_t key;
+ /** The accumulator */
+ pv_u128_ y;
+} polyval_t;
+
+/**
+ * Length of a polyval key, in bytes.
+ */
+#define POLYVAL_KEY_LEN 16
+/**
+ * Length of a polyval block, in bytes.
+ */
+#define POLYVAL_BLOCK_LEN 16
+/**
+ * Length of a polyval tag (output), in bytes.
+ */
+#define POLYVAL_TAG_LEN 16
+
+/** Do any necessary precomputation from a polyval key,
+ * and store it.
+ */
+void polyval_key_init(polyval_key_t *, const uint8_t *key);
+/**
+ * Initialize a polyval instance with a given key.
+ */
+void polyval_init(polyval_t *, const uint8_t *key);
+/**
+ * Initialize a polyval instance with a preconstructed key.
+ */
+void polyval_init_from_key(polyval_t *, const polyval_key_t *key);
+/**
+ * Update a polyval instance with a new 16-byte block.
+ */
+void polyval_add_block(polyval_t *, const uint8_t *block);
+/**
+ * Update a polyval instance with 'n' bytes from 'data'.
+ * If 'n' is not evenly divisible by 16, pad it at the end with zeros.
+ *
+ * NOTE: This is not a general-purpose padding construction;
+ * it can be insecure if your are using it in context where the input length
+ * is variable.
+ */
+void polyval_add_zpad(polyval_t *, const uint8_t *data, size_t n);
+/**
+ * Copy the 16-byte tag from a polyval instance into 'tag_out'
+ */
+void polyval_get_tag(const polyval_t *, uint8_t *tag_out);
+/**
+ * Reset a polyval instance to its original state,
+ * retaining its key.
+ */
+void polyval_reset(polyval_t *);
+
+#endif
diff --git a/src/lib/crypt_ops/aes.h b/src/lib/crypt_ops/aes.h
@@ -15,6 +15,7 @@
#include "lib/cc/torint.h"
#include "lib/malloc/malloc.h"
+#include "lib/testsupport/testsupport.h"
typedef struct aes_cnt_cipher_t aes_cnt_cipher_t;
@@ -28,4 +29,38 @@ void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len);
int evaluate_evp_for_aes(int force_value);
int evaluate_ctr_for_aes(void);
+#ifdef USE_AES_RAW
+typedef struct aes_raw_t aes_raw_t;
+
+aes_raw_t *aes_raw_new(const uint8_t *key, int key_bits, bool encrypt);
+void aes_raw_set_key(aes_raw_t **cipher, const uint8_t *key,
+ int key_bits, bool encrypt);
+void aes_raw_free_(aes_raw_t *cipher);
+#define aes_raw_free(cipher) \
+ FREE_AND_NULL(aes_raw_t, aes_raw_free_, (cipher))
+void aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block);
+void aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block);
+
+void aes_raw_counter_xor(const aes_raw_t *aes,
+ const uint8_t *iv, uint32_t iv_offset,
+ uint8_t *data, size_t n);
+#endif
+
+#ifdef TOR_AES_PRIVATE
+#include "lib/arch/bytes.h"
+
+/** Increment the big-endian 128-bit counter in 'iv' by 'offset'. */
+static inline void
+aes_ctr_add_iv_offset(uint8_t *iv, uint32_t offset)
+{
+
+ uint64_t h_hi = tor_ntohll(get_uint64(iv + 0));
+ uint64_t h_lo = tor_ntohll(get_uint64(iv + 8));
+ h_lo += offset;
+ h_hi += (h_lo < offset);
+ set_uint64(iv + 0, tor_htonll(h_hi));
+ set_uint64(iv + 8, tor_htonll(h_lo));
+}
+#endif
+
#endif /* !defined(TOR_AES_H) */
diff --git a/src/lib/crypt_ops/aes_nss.c b/src/lib/crypt_ops/aes_nss.c
@@ -9,6 +9,9 @@
* \brief Use NSS to implement AES_CTR.
**/
+#define USE_AES_RAW
+#define TOR_AES_PRIVATE
+
#include "orconfig.h"
#include "lib/crypt_ops/aes.h"
#include "lib/crypt_ops/crypto_nss_mgt.h"
@@ -104,3 +107,116 @@ evaluate_ctr_for_aes(void)
{
return 0;
}
+
+aes_raw_t *
+aes_raw_new(const uint8_t *key, int key_bits, bool encrypt)
+{
+ const CK_MECHANISM_TYPE ckm = CKM_AES_ECB;
+ SECItem keyItem = { .type = siBuffer, // ????
+ .data = (unsigned char *)key,
+ .len = (key_bits / 8) };
+ SECItem ivItem = { .type = siBuffer,
+ .data = NULL,
+ .len = 0 };
+ PK11SlotInfo *slot = NULL;
+ PK11SymKey *keyObj = NULL;
+ SECItem *ivObj = NULL;
+ PK11Context *result = NULL;
+
+ slot = PK11_GetBestSlot(ckm, NULL);
+ if (!slot)
+ goto err;
+
+ CK_ATTRIBUTE_TYPE mode = encrypt ? CKA_ENCRYPT : CKA_DECRYPT;
+
+ keyObj = PK11_ImportSymKey(slot, ckm, PK11_OriginUnwrap,
+ mode, &keyItem, NULL);
+ if (!keyObj)
+ goto err;
+
+ ivObj = PK11_ParamFromIV(ckm, &ivItem);
+ if (!ivObj)
+ goto err;
+
+ PORT_SetError(SEC_ERROR_IO);
+ result = PK11_CreateContextBySymKey(ckm, mode, keyObj, ivObj);
+
+ err:
+
+ if (ivObj)
+ SECITEM_FreeItem(ivObj, PR_TRUE);
+ if (keyObj)
+ PK11_FreeSymKey(keyObj);
+ if (slot)
+ PK11_FreeSlot(slot);
+
+ tor_assert(result);
+ return (aes_raw_t *)result;
+}
+void
+aes_raw_free_(aes_raw_t *cipher_)
+{
+ if (!cipher_)
+ return;
+ PK11Context *ctx = (PK11Context*)cipher_;
+ PK11_DestroyContext(ctx, PR_TRUE);
+}
+void
+aes_raw_set_key(aes_raw_t **cipher, const uint8_t *key,
+ int key_bits, bool encrypt)
+{
+ // For NSS, I could not find a method to change the key
+ // of an existing context.
+ aes_raw_free(*cipher);
+ *cipher = aes_raw_new(key, key_bits, encrypt);
+}
+void
+aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block)
+{
+ SECStatus s;
+ PK11Context *ctx = (PK11Context*)cipher;
+ int result_len = 0;
+ s = PK11_CipherOp(ctx, block, &result_len, 16, block, 16);
+ tor_assert(s == SECSuccess);
+ tor_assert(result_len == 16);
+}
+void
+aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block)
+{
+ /* This is the same function call for NSS. */
+ aes_raw_encrypt(cipher, block);
+}
+
+static inline void
+xor_bytes(uint8_t *outp, const uint8_t *inp, size_t n)
+{
+ for (size_t i = 0; i < n; ++i) {
+ outp[i] ^= inp[i];
+ }
+}
+
+void
+aes_raw_counter_xor(const aes_raw_t *cipher,
+ const uint8_t *iv, uint32_t iv_offset,
+ uint8_t *data, size_t n)
+{
+ uint8_t counter[16];
+ uint8_t buf[16];
+
+ memcpy(counter, iv, 16);
+ aes_ctr_add_iv_offset(counter, iv_offset);
+
+ while (n) {
+ memcpy(buf, counter, 16);
+ aes_raw_encrypt(cipher, buf);
+ if (n >= 16) {
+ xor_bytes(data, buf, 16);
+ n -= 16;
+ data += 16;
+ } else {
+ xor_bytes(data, buf, n);
+ break;
+ }
+ aes_ctr_add_iv_offset(counter, 1);
+ }
+}
diff --git a/src/lib/crypt_ops/aes_openssl.c b/src/lib/crypt_ops/aes_openssl.c
@@ -9,6 +9,9 @@
* \brief Use OpenSSL to implement AES_CTR.
**/
+#define USE_AES_RAW
+#define TOR_AES_PRIVATE
+
#include "orconfig.h"
#include "lib/crypt_ops/aes.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -88,6 +91,17 @@ ENABLE_GCC_WARNING("-Wredundant-decls")
* make sure that we have a fixed version.)
*/
+/* Helper function to use EVP with openssl's counter-mode wrapper. */
+static void
+evp_block128_fn(const uint8_t in[16],
+ uint8_t out[16],
+ const void *key)
+{
+ EVP_CIPHER_CTX *ctx = (void*)key;
+ int inl=16, outl=16;
+ EVP_EncryptUpdate(ctx, out, &outl, in, inl);
+}
+
#ifdef USE_EVP_AES_CTR
/* We don't actually define the struct here. */
@@ -340,17 +354,6 @@ aes_cipher_free_(aes_cnt_cipher_t *cipher)
#define UPDATE_CTR_BUF(c, n)
#endif /* defined(USING_COUNTER_VARS) */
-/* Helper function to use EVP with openssl's counter-mode wrapper. */
-static void
-evp_block128_fn(const uint8_t in[16],
- uint8_t out[16],
- const void *key)
-{
- EVP_CIPHER_CTX *ctx = (void*)key;
- int inl=16, outl=16;
- EVP_EncryptUpdate(ctx, out, &outl, in, inl);
-}
-
/** Encrypt <b>len</b> bytes from <b>input</b>, storing the results in place.
* Uses the key in <b>cipher</b>, and advances the counter by <b>len</b> bytes
* as it encrypts.
@@ -383,19 +386,131 @@ aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
}
}
-/** Reset the 128-bit counter of <b>cipher</b> to the 16-bit big-endian value
- * in <b>iv</b>. */
-static void
-aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv)
+#endif /* defined(USE_EVP_AES_CTR) */
+
+/* ========
+ * Functions for "raw" (ECB) AES.
+ *
+ * I'm choosing the name "raw" here because ECB is not a mode;
+ * it's a disaster. The only way to use this safely is
+ * within a real construction.
+ */
+
+/**
+ * Create a new instance of AES using a key of length 'key_bits'
+ * for raw block encryption.
+ *
+ * This is even more low-level than counter-mode, and you should
+ * only use it with extreme caution.
+ */
+aes_raw_t *
+aes_raw_new(const uint8_t *key, int key_bits, bool encrypt)
{
-#ifdef USING_COUNTER_VARS
- cipher->counter3 = tor_ntohl(get_uint32(iv));
- cipher->counter2 = tor_ntohl(get_uint32(iv+4));
- cipher->counter1 = tor_ntohl(get_uint32(iv+8));
- cipher->counter0 = tor_ntohl(get_uint32(iv+12));
-#endif /* defined(USING_COUNTER_VARS) */
- cipher->pos = 0;
- memcpy(cipher->ctr_buf.buf, iv, 16);
+ EVP_CIPHER_CTX *cipher = EVP_CIPHER_CTX_new();
+ tor_assert(cipher);
+ const EVP_CIPHER *c = NULL;
+ switch (key_bits) {
+ case 128: c = EVP_aes_128_ecb(); break;
+ case 192: c = EVP_aes_192_ecb(); break;
+ case 256: c = EVP_aes_256_ecb(); break;
+ default: tor_assert_unreached();
+ }
+
+ int r = EVP_CipherInit(cipher, c, key, NULL, encrypt);
+ tor_assert(r == 1);
+ EVP_CIPHER_CTX_set_padding(cipher, 0);
+ return (aes_raw_t *)cipher;
+}
+/**
+ * Replace the key on an existing aes_raw_t.
+ *
+ * This may be faster than freeing and reallocating.
+ */
+void
+aes_raw_set_key(aes_raw_t **cipher_, const uint8_t *key,
+ int key_bits, bool encrypt)
+{
+ const EVP_CIPHER *c = *(EVP_CIPHER**) cipher_;
+ switch (key_bits) {
+ case 128: c = EVP_aes_128_ecb(); break;
+ case 192: c = EVP_aes_192_ecb(); break;
+ case 256: c = EVP_aes_256_ecb(); break;
+ default: tor_assert_unreached();
+ }
+ aes_raw_t *cipherp = *cipher_;
+ EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *)cipherp;
+ EVP_CIPHER_CTX_reset(cipher);
+ int r = EVP_CipherInit(cipher, c, key, NULL, encrypt);
+ tor_assert(r == 1);
+ EVP_CIPHER_CTX_set_padding(cipher, 0);
}
-#endif /* defined(USE_EVP_AES_CTR) */
+/**
+ * Release storage held by 'cipher'.
+ */
+void
+aes_raw_free_(aes_raw_t *cipher_)
+{
+ if (!cipher_)
+ return;
+ EVP_CIPHER_CTX *cipher = (EVP_CIPHER_CTX *)cipher_;
+#ifdef OPENSSL_1_1_API
+ EVP_CIPHER_CTX_reset(cipher);
+#else
+ EVP_CIPHER_CTX_cleanup(cipher);
+#endif
+ EVP_CIPHER_CTX_free(cipher);
+}
+#define aes_raw_free(cipher) \
+ FREE_AND_NULL(aes_raw_t, aes_raw_free_, (cipher))
+/**
+ * Encrypt a single 16-byte block with 'cipher',
+ * which must have been initialized for encryption.
+ */
+void
+aes_raw_encrypt(const aes_raw_t *cipher, uint8_t *block)
+{
+ int outl = 16;
+ int r = EVP_EncryptUpdate((EVP_CIPHER_CTX *)cipher, block, &outl, block, 16);
+ tor_assert(r == 1);
+ tor_assert(outl == 16);
+}
+/**
+ * Decrypt a single 16-byte block with 'cipher',
+ * which must have been initialized for decryption.
+ */
+void
+aes_raw_decrypt(const aes_raw_t *cipher, uint8_t *block)
+{
+ int outl = 16;
+ int r = EVP_DecryptUpdate((EVP_CIPHER_CTX *)cipher, block, &outl, block, 16);
+ tor_assert(r == 1);
+ tor_assert(outl == 16);
+}
+
+/**
+ * Use the AES encryption key AES in counter mode,
+ * starting at the position (iv + iv_offset)*16,
+ * to encrypt the 'n' bytes of data in 'data'.
+ *
+ * Unlike aes_crypt_inplace, this function can re-use the same key repeatedly
+ * with diferent IVs.
+ */
+void
+aes_raw_counter_xor(const aes_raw_t *cipher,
+ const uint8_t *iv, uint32_t iv_offset,
+ uint8_t *data, size_t n)
+{
+ uint8_t counter[16];
+ uint8_t buf[16];
+ unsigned int pos = 0;
+
+ memcpy(counter, iv, 16);
+ if (iv_offset) {
+ aes_ctr_add_iv_offset(counter, iv_offset);
+ }
+
+ CRYPTO_ctr128_encrypt(data, data, n,
+ (EVP_CIPHER_CTX *)cipher,
+ counter, buf, &pos, evp_block128_fn);
+}
diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c
@@ -76,6 +76,11 @@ we_like_ssl_kea(SSLKEAType kt)
case ssl_kea_ecdh_psk: return false;
case ssl_kea_dh_psk: return false;
+#ifdef NSS_HAS_ECDH_HYBRID
+ case ssl_kea_ecdh_hybrid_psk: return false;
+ case ssl_kea_ecdh_hybrid: return true;
+#endif
+
case ssl_kea_dh: return true;
case ssl_kea_ecdh: return true;
case ssl_kea_tls13_any: return true;
diff --git a/src/test/cgo_vectors.inc b/src/test/cgo_vectors.inc
@@ -0,0 +1,651 @@
+/* CGO test vectors. Chosen from those generated by
+ * the python reference implementation.
+ */
+
+/* Accept python booleans here. */
+#define True true
+#define False false
+
+static const struct et_testvec {
+ bool encrypt;
+ const char *keys;
+ const char *tweaks;
+ const char *block;
+ const char *expect;
+} ET_TESTVECS[] = {
+// Zeroes, encrypt
+{
+ // Encrypt
+ True,
+ // (KB,KU)
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ // T
+ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // M
+ "00000000000000000000000000000000",
+ // OUTPUT
+ "66e94bd4ef8a2c3b884cfa59ca342b2e",
+},
+// Zeroes, decrypt
+{
+ // Encrypt
+ False,
+ // (KB,KU)
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ // T
+ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // M
+ "00000000000000000000000000000000",
+ // OUTPUT
+ "140f0f1011b5223d79587717ffd9ec3a",
+},
+// Pseudorandom 1, Encrypt
+{
+ // Encrypt
+ True,
+ // (KB,KU)
+ "39dd87e0b958cec5d2ba04a17fad9f134770f20f14038bdcd751056a7f16041f",
+ // T
+ "fbf69df9bfc3bec7e4a5dd0c9785dd18727dab2b11baf2898b3b775baed777d209812a71e8d5a1f624a4c2c3ccd91064f494f5deb2b7ab362cda53df3e0291cc439052a05cdbc8fe259f7190792b637eeaf0c5ebdf7d02ec6b89beecf131a916f5c6989267e28defaa5937b35f0a1ce1ef91838c408b2d199170f29e76ae21b8b62a733e4de9d281e6935d20d991e3e1801907f6477f9fd40bd4e72de681336e603bb7ec17d512728864b7cebc9bc6bbc0629082830fa3702cb2eff0fb289b7431d4e1b0b6109599c91c4c78540792331e592fe8c0c190ea18275386ec3d85f68996b6891e484ad4b0601008ead6ed60145f8d01b81d1cf31556744b1676f6c5caea56c5cd424350e0bc3c478efc2e11d868ddf73185627c778ba8b7d684f3d0b9dfe7e1b63985bb43e37a2e5938cae8b1741cb58aea2b383de9bf0531e344a5651f7f145aad1656e695e30ee6483b5e18e43b0aa6e308f2e1c8cfdd85a118476c9ca91c8ca993563b2df014289738c4b6ce772e2ac36a26547b97ba26673e28e634f88a91007e220f1beaa97ae00972954fc705de30642014fa5c4c07792a0f0b4a8ef3c6f0584b1029171a28cd5898e760c91f71c5f9610747ae21f30f1b1bfa7e4df9aedfa8b006f29e89e5b182ac9957067f86767ed5620abcb2c50a41c423e48a676864a2d151c5bf2442f3b90bfd7c047f92cd112367d0579c9f02",
+ // M
+ "40f417ba5a4c78a23e6540b52b68e1e6",
+ // OUTPUT
+ "84bfff8347889f1a9f2cf930c82677be",
+},
+// Pseudorandom 1, Decrypt
+{
+ // Encrypt
+ False,
+ // (KB,KU)
+ "39dd87e0b958cec5d2ba04a17fad9f134770f20f14038bdcd751056a7f16041f",
+ // T
+ "fbf69df9bfc3bec7e4a5dd0c9785dd18727dab2b11baf2898b3b775baed777d209812a71e8d5a1f624a4c2c3ccd91064f494f5deb2b7ab362cda53df3e0291cc439052a05cdbc8fe259f7190792b637eeaf0c5ebdf7d02ec6b89beecf131a916f5c6989267e28defaa5937b35f0a1ce1ef91838c408b2d199170f29e76ae21b8b62a733e4de9d281e6935d20d991e3e1801907f6477f9fd40bd4e72de681336e603bb7ec17d512728864b7cebc9bc6bbc0629082830fa3702cb2eff0fb289b7431d4e1b0b6109599c91c4c78540792331e592fe8c0c190ea18275386ec3d85f68996b6891e484ad4b0601008ead6ed60145f8d01b81d1cf31556744b1676f6c5caea56c5cd424350e0bc3c478efc2e11d868ddf73185627c778ba8b7d684f3d0b9dfe7e1b63985bb43e37a2e5938cae8b1741cb58aea2b383de9bf0531e344a5651f7f145aad1656e695e30ee6483b5e18e43b0aa6e308f2e1c8cfdd85a118476c9ca91c8ca993563b2df014289738c4b6ce772e2ac36a26547b97ba26673e28e634f88a91007e220f1beaa97ae00972954fc705de30642014fa5c4c07792a0f0b4a8ef3c6f0584b1029171a28cd5898e760c91f71c5f9610747ae21f30f1b1bfa7e4df9aedfa8b006f29e89e5b182ac9957067f86767ed5620abcb2c50a41c423e48a676864a2d151c5bf2442f3b90bfd7c047f92cd112367d0579c9f02",
+ // M
+ "40f417ba5a4c78a23e6540b52b68e1e6",
+ // OUTPUT
+ "e2c0bfdef28b5504cf0ec708a6866a17",
+}};
+
+static const struct prf_testvec {
+ const char *keys;
+ int t;
+ const char *input;
+ const char *expect;
+} PRF_TESTVECS[] = {
+// All zeros, t=0
+{
+ // K,B
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ // T
+ 0,
+ // t
+ "00000000000000000000000000000000",
+ // OUTPUT
+ "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c",
+},
+// All zeros, t=1
+{
+ // K,B
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ // T
+ 1,
+ // t
+ "00000000000000000000000000000000",
+ // OUTPUT
+ "7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f7329612dce4a0e5bc792b5b5a55f9c2f30e07",
+},
+// All ones, t=0
+{
+ // K,B
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ // T
+ 0,
+ // t
+ "ffffffffffffffffffffffffffffffff",
+ // OUTPUT
+ "3ae902931ae8d3ba07a2efdbf0411525c966356463673443646d3ed3e5ba68a61ccd8ae0d8f8d84adca5c0023f02efd10cc7bc7c9fbfd169bf47a792bbba07d6c9338101d0c28e476e99520413a37c3c9045909a8d37c6cba7f9e33254ff0b2ea11ccd6d0a6eed028bb3acccb38fe0a50ea2ca51dc35dc12541f5ce00611336ef966d9a9027a6342c09590d056880e79bfd1a271aff821114649e33a6b4d83be0883b3ad4b315ac6b77017c748a8bb71a981678ff9c6ca086507efb6e8850043767bea06d66ee5e9b2870107474150044488a2d00bd1d5154e0f1aeac5af0b73049004f8717baa13c1ae0088f2dfdf8e08a612aa11a8bb64ab2a4d292967504a6cb451a56275b756c2d7f65aab728617154693a7b31d048802b0ce635754977fb851bb21dddcd9564795e31523fcc35ccfc066b9542508b4daa65b4c9083b12a5cd08f7c45906523d5d7131f279959900473a756e48ababa93fb42663401d84bef93c6cfd6e02fc17797a7004671d21d3bc35cb2e9a344da0a16c300f3c977b6c892e0c2a9517862bec47a51fd49c5a4d46620ea5df9a055e89c2d54abffb00704c1219175433bc1683d93c75ffd7feccc605092b197c5aa5aa995ba0c0e33870b0f513a5eefd9d64fc6e89862709ca9876df86c189181e70e4eed2d876a12480b64afaffe54ba4ac8f23043d8",
+},
+// All ones, t=1
+{
+ // K,B
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ // T
+ 1,
+ // t
+ "ffffffffffffffffffffffffffffffff",
+ // OUTPUT
+ "be938fc23009440bfb5d7bba1d28428ec0897793bb878b8e1eb3ec1257b88024d551d770b56c9312de3dd4ac64e194c91185a89f2ba01f90b03b3acb93f634df4b263f03af0acda2f9721d0f4c0783c7",
+},
+// Pseudorandom 1, t=0
+{
+ // K,B
+ "908bf9a158c67f9cd5cb5cee476a4b30b9ec92756d94b1f9f40073c185c39780",
+ // T
+ 0,
+ // t
+ "d5d73799a0f37a1c7ff3ceb187ebd059",
+ // OUTPUT
+ "0573c27e297dad58e84942c498d3c376c1f8423dea1df70338259814f2b939ffe074b22fae1385e2d453aca882cb6257ec4fc86915f05be11ae36df4d8678ff29f68c45797c2a4158c4c30c703faeda452858ae37b7735f47b2924cd6f6040e7f6b19958f6d5a12aae72b589d6f85e5a3267881b2916da948fe1626d68ee60a13c90599b40f8a14fd8d1354bc5beb23f38043d7e547b879f618302426dd7785bc2caf44b31a2e1ec5d4dcb4047415d0bbc6900dfdfa01e61c4aa3624f6d7f03cc1641610bd0d6f155cae7465a3d1e0ae8db7d5a00afd27824fd35b65a91728981566c7a046f1773210b76a449b76b5684eb3532a06225d89b70aae1d20c27d03c528b00051a3eb74f3b217b3d474076b8c4bab837476c6191bc7ae8266328d5a65f6a2c55c30999984e2747b7dc45af9e43533b750d9196cd2d64947b6dcf839821002441a428bbbeee45de052502aa76385b47aedbdbeed500c359fdd1ba042a5c9956a1b2e3e456472665f7a674d898a9c5ee58e6288304a323986f0d09b731ae401ac5f8ebeaf808cecce9945439ec76cccb5aafb875faf1274bc29beb29413e01ef72cb37eebc06428c24221f8af3c5ea742fc41506d501d8e45bed5d982ab16669da486c985a3e140eb55c754aaf3d7923d76519f8bac02e0e0c0961411d8c010d1c58498caeae8c69c62",
+},
+// Pseudorandom 1, t=1
+{
+ // K,B
+ "908bf9a158c67f9cd5cb5cee476a4b30b9ec92756d94b1f9f40073c185c39780",
+ // T
+ 1,
+ // t
+ "d5d73799a0f37a1c7ff3ceb187ebd059",
+ // OUTPUT
+ "75c5c6787bd0edf325cf772b8c09478df5094f093eddda9d4b7c2ab4ebcdd84c87192038ade81b8560ef7f5a3eb89a4957cf9bd138c575b6951f9940d44d443f47616dfdaf73be7a4664aa46bc279c20",
+},
+// Pseudorandom 2, t=0
+{
+ // K,B
+ "fcd9361d1dca1c7b9a24f754464eeda5727152bc98a818b2e720a0afa9103e10",
+ // T
+ 0,
+ // t
+ "d22ea954482f5bc511c6fcae80233d57",
+ // OUTPUT
+ "e5be8144283c5b638a7bbcae231cfb9d6727ee8f04bcf0f3c7ff94930facee8030712bc8b0d151a5ea27c4f614cd46fe1ef9eee2f64c8d8ddfce7ab1ed01cdd610e7b341b75408a6a8310ed62389348b76a59277a0eee05bdd5f5227d43fc113294b3af71d505a0c88d920387f44ef33029797d0c282991683adca83449e68aff578df836ee6b89cfc5fb0e8ce0d8d5146a09d57ec816e0fbbbdf80b298dfe6509aefcc892a6dd4bbbbfc6d9507e4013305986bb9d0cc050de172faa2039623cb93177a0b7c5966933ad2ee6fa930dbfe24148b63561551364fdcc3a1e1a5381d62a9508c6bd86a43ed602e5fcc0cee2c8d2a67c7de50428fa72ef75fd4aafe4bbc17cb03ffeb69066e5c6ee65c1df67fc9c33515d45cfc504c2d2db213b36df5a6b7864ccf11061464048329f2a79b6935b4219aab811fa07896497ba8dc47c1f2e9207e4be7a4f3651bba673d4911787df8423cc60601785ac5072516954efa6e30f27c04136f6bdff2d23b0489b2d7c9aea7f5320d48c337eeb2dd4f06eedab55316ba8f45b6f9a584ae8241183a261b467be3b500febbb609a38895d92f0aa8ca31197e81c85aefcea4d7a5f0d4f7825de0260f9563db272720c723a38f935113d1f2a89b02303eced1312316f29001f224a730031ac6e002916a2077fff2de0cb740622692fde1ffe1811",
+},
+// Pseudorandom 2, t=1
+{
+ // K,B
+ "fcd9361d1dca1c7b9a24f754464eeda5727152bc98a818b2e720a0afa9103e10",
+ // T
+ 1,
+ // t
+ "d22ea954482f5bc511c6fcae80233d57",
+ // OUTPUT
+ "242f479249fefc782eb74cb5304e54cf9f1230ba8908c1a322650edd916ecf76527d3a84db32d8ca0931b0420c8bcf388042cb152ee080af416a37cf2e0406de5ebb9c27061650e72552ecadca5af451",
+},
+// Pseudorandom 3, t=0
+{
+ // K,B
+ "b445f9a92d267dbd3b2dd9ad0cf90538b4013b72df0a23ef997f7baf9440733a",
+ // T
+ 0,
+ // t
+ "1d16d4b08c19887a050603dc8f17bb6d",
+ // OUTPUT
+ "d609818f6c26b96efadb6e5d84ed63c4d426e133cc72acc222a161feb8810f99d0d8dbace6181b8f41e601cf7bd33a3a23e84bf8898505e222a42fb889fe759e48fda34e6d39c357e6445864e55633bc264d4f4d33d0afd20a51ad1b3d6d18288d6930ac9775e6928cdce46642b5b81bdbbdb469f1d6f1a889a2c76c0258ca6a95c5f590c54f1503ec46f1b3ad6e93233f9f4ca9a57bc14aa505f4678d9fee8fa7b8f047252569b83c79e3a4abea6d4a481e159e91dced13f58be46f41ef52f1ebb17cd68875f2dee11ab6409fe5f0d5a189fdc86b4b214f2ccd47d419e66ba3889bac4b7da810b3ba647082662c74c2e2972962d8af31fc05a22e0df7f5e87a6bdfb2b414bf55e46581ca982bca237a0af99030d079b6e81404b6bad3011bdf114e2d042e019342a41b06d1ece656ff994b80796747ca413f783c903f0980873c95b1b3d6d3c99410d75993a9b28ae23d26847da256e09f7c727f1b05eb1fa4aea6d0b4b69307363c2ec7d75e136c14f3ca44d2d2bf001095ee5505bcb56c06842233411e5bc38da56d97c1ce6b1807db9b832fc10625d55fb259a5cd75c0a1d27a8b8a8c9b2a98bdfe7903a927026f2d2616b481e13e3bf7eb1039ec892a2fa054fd8dd6aac76b0efbece35b374310583d1c5f594604c3a49b35af7c3065f9f5f3bbe5cac3e8522a0654463c",
+},
+// Pseudorandom 3, t=1
+{
+ // K,B
+ "b445f9a92d267dbd3b2dd9ad0cf90538b4013b72df0a23ef997f7baf9440733a",
+ // T
+ 1,
+ // t
+ "1d16d4b08c19887a050603dc8f17bb6d",
+ // OUTPUT
+ "85da4380c7376cdd451aef93c15303626a9a54b1b21ddf5fa88beb1ade9331438764e8ad4f640dae16e3708806bab62d948e2ac6210b198184d0bface602a49f606d13e72574d7cda3e8458736d180b6",
+},
+};
+
+static const struct uiv_testvec {
+ bool encrypt;
+ const char *keys;
+ const char *tweaks;
+ const char *x_l;
+ const char *x_r;
+ struct {
+ const char *y_l;
+ const char *y_r;
+ } y;
+} UIV_TESTVECS[] = {
+// All zeros, encrypt
+{
+ // Encrypt
+ True,
+ // {J,S}
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // H
+ "0000000000000000000000000000000000",
+ // X_L
+ "00000000000000000000000000000000",
+ // X_R
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // Output={Y_L, Y_R}
+ {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"},
+},
+// All zeros, decrypt
+{
+ // Encrypt
+ False,
+ // {J,S}
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // H
+ "0000000000000000000000000000000000",
+ // X_L
+ "00000000000000000000000000000000",
+ // X_R
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // Output={Y_L, Y_R}
+ {"140f0f1011b5223d79587717ffd9ec3a", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"},
+},
+// All ones, encrypt
+{
+ // Encrypt
+ True,
+ // {J,S}
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ // H
+ "ffffffffffffffffffffffffffffffffff",
+ // X_L
+ "ffffffffffffffffffffffffffffffff",
+ // X_R
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ // Output={Y_L, Y_R}
+ {"7209baed4b605b158b7eb25de2200e83", "5546c0d2d8da37d92908803d88ff5a646e24a9f9c8c0e9f239726ccc5107d45ed813697aab0b27969930489e47c87475d71b92fc875e268d2ed92fa735b8258c657ff883512adf916a7a8819596e878415da7dc689fc658b862235133b4366e5bea11ece0990a544cb324e27313d67567797213ddb9102e75caca82a15035e44a306c906f8c17e2c88975808b35ad13443849d9ebec10f2c888738ff5b7cb3043b2bbd6098b167746addcc55238fb32d9ef404f3d0f7db0bc5f30aca0cf9ce5f87c989268d18b1069b33bbd5b7818a99603ec0d82871e75cffd1d84e2be1e0f8e8b3678b1ccd7a5a676d83fe0e68f09027ad912d58d2257932750b383e2f2fa3c889ee9d71919cc05d982230c6ff8b7e5e3ed302ed82bed429794c261aa009d231bb6c8675e513313432017cea50843a0309153f7f9d556330f19c38bc5ae6d33d63abaa7ebabd3335c1bf59a2121378288da679259bb1b8a8b027938f3e902c655c781e7f5d9514e53502e7ebc31e344344c3ae2a6397a9a8b846dab8a84174e91664804c7804bab09d6d40aeeb491d6f6184830ac7b5807418a05a7ab9938c3fdc18066b5d503f8c98e83be033b6fba905324267618cc6989b486e0decf7cc897d17be093286a4d4fb5016c3e3323ccc416a30473081473bd471e430194ec4e2ac0af3bca0577b78f4c70e4d"},
+},
+// All ones, decrypt
+{
+ // Encrypt
+ False,
+ // {J,S}
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ // H
+ "ffffffffffffffffffffffffffffffffff",
+ // X_L
+ "ffffffffffffffffffffffffffffffff",
+ // X_R
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ // Output={Y_L, Y_R}
+ {"a9166add184e00b007217cb4e4f52ee5", "c516fd6ce5172c45f85d10240fbeeada3699ca9b9c98cbbc9b92c12c1a459759e332751f270727b5235a3ffdc0fd102ef338438360402e9640b8586d4445f82936cc7efe2f3d71b89166adfbec5c83c36fba6f6572c8393458061ccdab00f4d15ee33292f59112fd744c53334c701f5af15d35ae23ca23edabe0a31ff9eecc9106992656fd859cbd3f6a6f2fa977f186402e5d8e5007deeeb9b61cc594b27c41f77c4c52b4cea539488fe838b757448e567e9870063935f79af81049177affbc898415f929911a164d78fef8b8beaffbbb775d2ff42e2aeab1f0e5153a50f48cfb6ffb078e8455ec3e51ff770d202071f759ed55ee57449b54d5b2d6d698afb5934bae5a9d8a48a93d2809a5548d79e8eab96c584ce2fb77fd4f319ca8ab688047ae44de222326a9b86a1ceadc033ca3303f9946abdaf74b2559a4b36f7c4ed5a32f7083ba6f9adc2a28ece0d866a66ffb8c58a91b7545456c04bd99cbfe27b4106c3930291fd03e886858ffb98e2de2c43ca34d165cbb25f5e93cff0c368849376d1f3d56ae879d413b85ae02b63a5b2b99df15a2065faa1763d2ab54004ff8fb3ede6e8abcc43e97c26c38a0028013339faf6d4e683a55a5566a45f3f1cc78f4f0aec5a1102629b03917679d8f635678920793e76e7e18f1b112d27895edb7f49b505001ab45b5370dcfbc27"},
+},
+// Pseudorandom 1, Encrypt
+{
+ // Encrypt
+ True,
+ // {J,S}
+ "22169d562646db8ce3322daf9fa8e84bed57dac18beabdb619b40f5a02786e439e6132a5b7e7445ef962e2c7f30a0b2ec994ee1935e1787d6f89cbc15b9254d5",
+ // H
+ "81b1a82c63d8dd9f682f734e82e259a14b",
+ // X_L
+ "db4adc246c6a54fe55e11901f08f0eee",
+ // X_R
+ "dccb8aa0570982d5b08fa6b4fbb3bc7bcd7e1cb374f114fcdd0ed53255c523c1e8ecabfbaab00105af9933eff304a40877e3006be82417e44462fc6955777baf2f2f9c99966ddee30b7c65050dcc8f5d7bc22f9192e1c4a83ca0a2338deca9da4fed14058812ace259e9851f50c83d97515b647ff56749a3c615e1860a404e9b05619a48aa3e5f09779e72c77dfdd1ab5d796860178938efffb4e43bda443c2fba0d5be14baa375d881ee5e14d760a12c4d9807c8c54b714a75324c4074296ba8c86beceb4dc2337946f0af67c759d999d56aceebefd80438dc625b0b50f749440e8cd5bcee1afa05ff8cff1bfd3e0e68930b74b3baa7e6cb723896afc3098326716e0554319c9f8f3683a8fd359ae48a3591dac67adeea6e24600037cb1a42c38b23a9e7c31e6d0b13b84e88341458050856c476f6875dfe17806e0cd72baeebd0e1108fb13088a887153a1d13bac414ed120c26bda5bc08202fc1489746305dcda5dfc3e6a869b52d63654f3bc35841a2345df8691caf1de06d5ebd214af729e239efd62d05060eab13fb973ffb41f461224e2eee1f739529d37e8db40c065e52de7b8f19fbf695470341062c7f212d8cf5310cc17f487e04e8ed03fe50f3758eda9e41bf37af62f94709b16e01b4305d1a5ccad2bcacc7e35d4a1d1a40c26dbf3153739175ca65ab59cc1c9",
+ // Output={Y_L, Y_R}
+ {"9ff8aec547f02caae7555ad7b0cb1372", "d2ceaad0ef52ac304d9550f0c365fa7728dca633f4f62228b241e47754dfa01c709e66f54a018e667573dbf5063c10a6167592250a8f6af17c68d5e190c5e8bdb40082b54e428ada58b3a805cdd56d87cc56591f8ac5f310eb37ce4d8a6ea6a80c3d7316f872aeb8a1a40ef7d1f0bbd1711d38c500eccc0acb88c1a3491ceee45bf82ba3fdf939dcbedb4f140fae21339f671df748d18e8bc8d72eb8e7cf18feafcd6f363345e2b05bc2d4d6f3affb8589d002aadb711d5ad2fa81398137b9e88f5a8663787e746bb878c0973d9b80145f8dd18bce30ea10e13ad07aeb469f62c4507ff8aaba09ed988a794232b5fc4e64466103366ed474fb99406fc80dd5ae5cb90001b1485476978dada0df83456feb3674ec7070b177871203410c5f7adbefbf5069c64bce59ef381514cb2a8d0804d855cca0a9c84d4c60c44e7242ffc479aabf357016166e9b184311c0e04dd9d1c512ae508b8f8c6bfdba68d46e338250f23668aaf11f45f57bfbc8e32d14ccab853af085a17405058ecd993cb21b41f8456c54a3900a50c270fc2b0931394ba257fd49bf79ae54d9c39a8504067b9cee1e42b688dcc606bee57006bc561b991dd10c56c129d1db8997e0d163fd06fca83249f146e348a4f35d0cb47d0ea6b3c6c587487f3816e13c2494d6d1e866fa182855cd668462a30b4e7019d2"},
+},
+// Pseudorandom 1, Decrypt
+{
+ // Encrypt
+ False,
+ // {J,S}
+ "22169d562646db8ce3322daf9fa8e84bed57dac18beabdb619b40f5a02786e439e6132a5b7e7445ef962e2c7f30a0b2ec994ee1935e1787d6f89cbc15b9254d5",
+ // H
+ "81b1a82c63d8dd9f682f734e82e259a14b",
+ // X_L
+ "db4adc246c6a54fe55e11901f08f0eee",
+ // X_R
+ "dccb8aa0570982d5b08fa6b4fbb3bc7bcd7e1cb374f114fcdd0ed53255c523c1e8ecabfbaab00105af9933eff304a40877e3006be82417e44462fc6955777baf2f2f9c99966ddee30b7c65050dcc8f5d7bc22f9192e1c4a83ca0a2338deca9da4fed14058812ace259e9851f50c83d97515b647ff56749a3c615e1860a404e9b05619a48aa3e5f09779e72c77dfdd1ab5d796860178938efffb4e43bda443c2fba0d5be14baa375d881ee5e14d760a12c4d9807c8c54b714a75324c4074296ba8c86beceb4dc2337946f0af67c759d999d56aceebefd80438dc625b0b50f749440e8cd5bcee1afa05ff8cff1bfd3e0e68930b74b3baa7e6cb723896afc3098326716e0554319c9f8f3683a8fd359ae48a3591dac67adeea6e24600037cb1a42c38b23a9e7c31e6d0b13b84e88341458050856c476f6875dfe17806e0cd72baeebd0e1108fb13088a887153a1d13bac414ed120c26bda5bc08202fc1489746305dcda5dfc3e6a869b52d63654f3bc35841a2345df8691caf1de06d5ebd214af729e239efd62d05060eab13fb973ffb41f461224e2eee1f739529d37e8db40c065e52de7b8f19fbf695470341062c7f212d8cf5310cc17f487e04e8ed03fe50f3758eda9e41bf37af62f94709b16e01b4305d1a5ccad2bcacc7e35d4a1d1a40c26dbf3153739175ca65ab59cc1c9",
+ // Output={Y_L, Y_R}
+ {"1c1593f30a020d44b7b2cf9b75204808", "c8135c678f97432394c2fa38ee6f590104a99028da2624a44d9a503adf1fe0d236ed5253d2e1cfca479c1b41609ef7cab58d7bb4d8e50e21108f837791f2e3066d3c40672f8e0f1a304d25ba20401a8aac6b15c1582788fe8996277b5cb554cd82e0920f212293b8bc4357349465f75e2f688a084d4c4741e2b384523d51cf94062cb7e6c1481eb48f1eb37e00937e0a2b2e12c88ac1b8ca2eef537b74b9f22e016b1a72818eddd1bde1e3643f4aa8fbf1e69543475131c17e8562c6c7d9a4375936fcc1c6ffeb131195e2168cd26368c3ab40f436563b4a5b6db2a7fa61e521321dad4d1aaaca8d0b38d68de26f402233d3bc25c78cd9019d2985f0f02c51cd07423726bd7ef3d19a8bb7b5a94d54ed86c460e7b02388fcedaa99902bc43c8339a171e89dc8123a9cd05287f2c0a39fdf24dd56dcf4326c163d38c9282d1f2f9a0faf50beb6e5caeb300a6192f6c1aaa5ba515bb677bb399edfcb05eab48870e79018d60ccdf3f1b5b6eb1e1a9e24a8a11da26c0919e6ec7db6a1260d6299e7a2830d48d3bf33b40f4c5cc0c4acae037a4bf5731fff732f44752bd002c8493f1d48ea6c5f0cbbd596d679c7130d687211e74a96473275f2c8df1634ad36aab16eb0221777e98f62057d669b51bee20ab45db78b619aa619a40245d9ddd074a35c54b77f7ccc0410c00719e423"},
+},
+// Pseudorandom 2, Encrypt
+{
+ // Encrypt
+ True,
+ // {J,S}
+ "e61126a280c66e99171b1ec940a75ba6d4c3301062760a9ff9f9b332433b8408af4a49ad5326b95da7f501bb8b34bce8ce6e8c33f57263a4779a161d3736b7e4",
+ // H
+ "837d18ad2b0162977d3461349b00bcfdd7",
+ // X_L
+ "4b9fa9b1d31ada9a15d29cd0bd920a53",
+ // X_R
+ "c819e68a3dbdb6e730e4c9ed6dc11187f7ef0f021f63f0da32b55c8e2c78d4bc55d0e487329542e0b63a8f57313a146443cb5b8ba9eaf77d7e80884333b0e33b806da9cb32e231b5a23aa9ffa6f598df337126b26d6f9ef0d6c6a1bb59d83d253ea0ddc7272d633eb785dd7649fb7618a3b2c721cfba7d3e3d4a95fafcb90c2c60a52258ff3da3e1ab1205747e049e4730d734eaa5744a18fa8b8c4aed37d28857a5877839a40659e9754795859dad3163d6358234072ae62f64e58c861fd2225c60a708bb9b199e2070315e6d8eda8365b7cdaf5d067280086fda2a304ccbf3177fb0d34bbc3b02b4aaf42e535fbf2a15b782a8f3004eecda69aade92eb7bc92b6d552172bd26db28dcdf36547fa2794bf598db51ba0578f176e0cd3db04bf8333819a17f9c0d6faa9128930a3d8e93170d1bdf4e17a26f794631c870d9fd0edc73c3ce51753cbf59f3c942b689ccd08d8c0e0b19840b5113b760893b7d3b3a7c8f2c8794cab2f35a49d1d3f8c93bc353f376904d1961d3958cdc7a1841fe305c5c48b98f3b829ab1540876c3bd9d73e979107ab6f8146fe8acf33bde92b0a0ec2088dca60ae8374bda9d36977e5653762e8744d2b66d5bcc26dde754ec5eb3f665fbdd1ce2d0a7a48c499c0a5b846a7cb3c478484703c31ebb0c20c66bc1c1722529be0bb850d9bff7437ca7",
+ // Output={Y_L, Y_R}
+ {"6db7f5e28e54c81ce9a22df58eef5f65", "bc742015a226d2f1f855c06e9c12ce9866a311622befc8ff5f796c1813308fecb8c91b7fdc00de93198498afeec55422f678fd1822131877c947236c4c978b0f0fc3d0ddeee5770bac3c635895d9b922399a0062e4c80b9ea753f89608ed6920fc2f8a9e09ba87b40c6ef2a9354524e7f0ac1d967ef520a348e37fccc35f584ed5270b7e4694cd263a25f8869e07693df3f9a5fbc6aa4f8697456fa830e07f6ab89d3ae18790b6208c09ec2cf530239bb7d514691a01b4a772233693dc398bc6b4a08e412dce4d3b3556c0aa8ad2d0ee474ef56c1dd232b677c2d38be103921b8373e9e1c8ef2e98ededce0439351e74ca751db03e8213cd6adb6ee5a7b3103675776b82e59120d21e4b4e03e01aa420c254530ed74c24dcc514ddb241450642dedd0c5b1a0f7c2a7af243b96f1d1312ff8448a0c3a2b9cdaa90c45d11fdd82e6b17bc83f246313d7d67dd380165ceac938f5cd7896ffb8c22669526345f42892e1cb2b5af64f39139e6f3d5ed8e03efa61d653bbfcdf387c9ccf9de686b9603a681143ccd21a12004c810acc7e9c17bbdeba632bc9e5f0c6d3cbf72c8e7b958fb66d38bdb77c1e170de541b0750d942e9f8bcf123bd4a369af220135816b6d9b09778a8bc5e0378ec82678c1344a978fd1b271376ac31ba3981a1639a3808a8cd35424daa91d59f6e34967434"},
+},
+// Pseudorandom 2, Decrypt
+{
+ // Encrypt
+ False,
+ // {J,S}
+ "e61126a280c66e99171b1ec940a75ba6d4c3301062760a9ff9f9b332433b8408af4a49ad5326b95da7f501bb8b34bce8ce6e8c33f57263a4779a161d3736b7e4",
+ // H
+ "837d18ad2b0162977d3461349b00bcfdd7",
+ // X_L
+ "4b9fa9b1d31ada9a15d29cd0bd920a53",
+ // X_R
+ "c819e68a3dbdb6e730e4c9ed6dc11187f7ef0f021f63f0da32b55c8e2c78d4bc55d0e487329542e0b63a8f57313a146443cb5b8ba9eaf77d7e80884333b0e33b806da9cb32e231b5a23aa9ffa6f598df337126b26d6f9ef0d6c6a1bb59d83d253ea0ddc7272d633eb785dd7649fb7618a3b2c721cfba7d3e3d4a95fafcb90c2c60a52258ff3da3e1ab1205747e049e4730d734eaa5744a18fa8b8c4aed37d28857a5877839a40659e9754795859dad3163d6358234072ae62f64e58c861fd2225c60a708bb9b199e2070315e6d8eda8365b7cdaf5d067280086fda2a304ccbf3177fb0d34bbc3b02b4aaf42e535fbf2a15b782a8f3004eecda69aade92eb7bc92b6d552172bd26db28dcdf36547fa2794bf598db51ba0578f176e0cd3db04bf8333819a17f9c0d6faa9128930a3d8e93170d1bdf4e17a26f794631c870d9fd0edc73c3ce51753cbf59f3c942b689ccd08d8c0e0b19840b5113b760893b7d3b3a7c8f2c8794cab2f35a49d1d3f8c93bc353f376904d1961d3958cdc7a1841fe305c5c48b98f3b829ab1540876c3bd9d73e979107ab6f8146fe8acf33bde92b0a0ec2088dca60ae8374bda9d36977e5653762e8744d2b66d5bcc26dde754ec5eb3f665fbdd1ce2d0a7a48c499c0a5b846a7cb3c478484703c31ebb0c20c66bc1c1722529be0bb850d9bff7437ca7",
+ // Output={Y_L, Y_R}
+ {"e6d9d943df0c57ffcf625bd142f023cc", "16fcd880981c22d459e61a502213668f6f040c57f9db8cf39fc07bce35a9df2e2cd083359e833944bb1da2d107caa11d171abfe5878787ca89c5460753a8df4c3af7d9e1091a68e1976eba0ba81005f60f1fb2f26b6163896070efb1c39e31d24bfcd23e897062645b5d5766ab81eef662ca789d4e5bf7aa76414d01acd67e9ec372e63f5a676fb4645cbff0c47b3ec0c667b781ac42a0fedb75eaf39fce4da7f37a660db56ca92836609ca32faa4987f232e89177cee0b45ab8d34ca1c9a9f29fcd057cc6e491387f75e01ffc40ddef01c0bb557803cb514afb19718a9b918ed266f5c3283d93b6fdd1232758f059a0f6f78b7d5e8cb0d61a7e974936b6bf007a0121db05051a3f3279c3b295de61af596f8ce8820480f666f963ad4c9af0490272f88eb01bdad77ca43c8d5cc3abf7b1d1b6b15890b43008d68ddbc9f2426985d6ef946cae5099b1b81eb500959d8e5571b438f796aafadfa85ae29e6373878f0eac3f91e75cd37c609064e57fc588bdba25f5f2cd095e14d01fe72ddb30f784fe97ccb7619ebe809a5acb24f73a69f9a3b348b99ff554fa316b4b16cb7cdcd79602ac17003057e7bff980521e43a57a43df4c13ed71740767ab277e1da09b371843aa1160b599b5cc0b1cb4c31d348718b64b9a6d66cd691185465ae5dcea649391b342bea21d430df41080"},
+},
+};
+
+static const struct uiv_update_testvec {
+ const char *keys;
+ const char *nonce;
+ struct {
+ const char *new_keys;
+ const char *new_nonce;
+ } output;
+} UIV_UPDATE_TESTVECS[] = {
+// All zeros
+{
+ // {J,S}
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // N
+ "00000000000000000000000000000000",
+ // Output={{J',S'}, N'}
+ {"7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f73296", "12dce4a0e5bc792b5b5a55f9c2f30e07"},
+},
+// All ones
+{
+ // {J,S}
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ // N
+ "ffffffffffffffffffffffffffffffff",
+ // Output={{J',S'}, N'}
+ {"be938fc23009440bfb5d7bba1d28428ec0897793bb878b8e1eb3ec1257b88024d551d770b56c9312de3dd4ac64e194c91185a89f2ba01f90b03b3acb93f634df", "4b263f03af0acda2f9721d0f4c0783c7"},
+},
+// Pseudorandom 1
+{
+ // {J,S}
+ "bf9b13b7097f5eee96b15423348ebf7aa13da31a2955a72ff17c7f75f9fd92f3280bb2d8992bc2a5f70f8e4e10f0404f16f3a0bbb91975bae7e11180adcba6da",
+ // N
+ "1ecb6e1ee6f0531c233676fd1c3ca701",
+ // Output={{J',S'}, N'}
+ {"4c03bdb301aaa20b907ac88ecd3174bb1b476a00a81ad67cb4eceba22354ce8f241ab2da59d565781634e9252358006b5b78166ea59028e1ff40a71687dd2f11", "30151c332e40594324ef033a469d4f50"},
+},
+// Pseudorandom 2
+{
+ // {J,S}
+ "e773e6211d22f03e0220bd6e69803b2d0bfbd6321a9e0184e49660bc1989318a868d5ccd3f769537c4990df2998cddc14cd853d8614c6e7e3548af9c824b457d",
+ // N
+ "d8097e67afff2d56a6279229cfb37f29",
+ // Output={{J',S'}, N'}
+ {"c9f14480f4d46a1e40ba3daaab9004ec0e7afab84f3c60da9f7f01ab46aab7a81e2138eed6f141047bc4169013450134586120852ca9a952417b402834fbedf4", "c79fdf8d9ae28e55eaed6e556e12b994"},
+},
+// Pseudorandom 3
+{
+ // {J,S}
+ "a150329bf382e5c3b11619ac72ac3b2cdf55b19e94fd2f92bfca40ef540274ba571c53695d5d8f0d4d4935d2b599ee095754d3bbdd9929d60997eb4f745e0a48",
+ // N
+ "071652e3ea1b1d299ac07ab3df431090",
+ // Output={{J',S'}, N'}
+ {"7c7a284801c7aa0f727f8e24b87a2dca1b7550577924490291a7343924dfd1b9e2b86e4f7db39b77715888f7d3b9aa4ea44bd72a8b1eb79df0d46f25c130fc87", "3c8ecadfbe9ee9587332a6568c7f2476"},
+},
+};
+
+typedef struct cgo_tv_state_t {
+ const char *keys;
+ const char *nonce;
+ const char *tprime;
+} cgo_tv_state_t;
+
+static const struct cgo_relay_testvec {
+ bool inbound;
+ cgo_tv_state_t state_in;
+ const char *cmd;
+ const char *tag;
+ const char *msg;
+ struct {
+ cgo_tv_state_t state;
+ struct {
+ const char *t_out;
+ const char *msg_out;
+ } result;
+ } output;
+} CGO_RELAY_TESTVECS[] = {
+// All zeros, inbound
+{
+ // Inbound
+ True,
+ // R = {K, N, T'}
+ {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"},
+ // AD
+ "00",
+ // T
+ "00000000000000000000000000000000",
+ // C
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // Output={R', {T_out, C_out}}
+ {{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "66e94bd4ef8a2c3b884cfa59ca342b2e"}, {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}},
+},
+// All zeros, outbound
+{
+ // Inbound
+ False,
+ // R = {K, N, T'}
+ {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"},
+ // AD
+ "00",
+ // T
+ "00000000000000000000000000000000",
+ // C
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // Output={R', {T_out, C_out}}
+ {{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "66e94bd4ef8a2c3b884cfa59ca342b2e"}, {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}},
+},
+// All ones, inbound
+{
+ // Inbound
+ True,
+ // R = {K, N, T'}
+ {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"},
+ // AD
+ "ff",
+ // T
+ "ffffffffffffffffffffffffffffffff",
+ // C
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ // Output={R', {T_out, C_out}}
+ {{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "7209baed4b605b158b7eb25de2200e83"}, {"7209baed4b605b158b7eb25de2200e83", "5546c0d2d8da37d92908803d88ff5a646e24a9f9c8c0e9f239726ccc5107d45ed813697aab0b27969930489e47c87475d71b92fc875e268d2ed92fa735b8258c657ff883512adf916a7a8819596e878415da7dc689fc658b862235133b4366e5bea11ece0990a544cb324e27313d67567797213ddb9102e75caca82a15035e44a306c906f8c17e2c88975808b35ad13443849d9ebec10f2c888738ff5b7cb3043b2bbd6098b167746addcc55238fb32d9ef404f3d0f7db0bc5f30aca0cf9ce5f87c989268d18b1069b33bbd5b7818a99603ec0d82871e75cffd1d84e2be1e0f8e8b3678b1ccd7a5a676d83fe0e68f09027ad912d58d2257932750b383e2f2fa3c889ee9d71919cc05d982230c6ff8b7e5e3ed302ed82bed429794c261aa009d231bb6c8675e513313432017cea50843a0309153f7f9d556330f19c38bc5ae6d33d63abaa7ebabd3335c1bf59a2121378288da679259bb1b8a8b027938f3e902c655c781e7f5d9514e53502e7ebc31e344344c3ae2a6397a9a8b846dab8a84174e91664804c7804bab09d6d40aeeb491d6f6184830ac7b5807418a05a7ab9938c3fdc18066b5d503f8c98e83be033b6fba905324267618cc6989b486e0decf7cc897d17be093286a4d4fb5016c3e3323ccc416a30473081473bd471e430194ec4e2ac0af3bca0577b78f4c70e4d"}},
+},
+// All ones, outbound
+{
+ // Inbound
+ False,
+ // R = {K, N, T'}
+ {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"},
+ // AD
+ "ff",
+ // T
+ "ffffffffffffffffffffffffffffffff",
+ // C
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ // Output={R', {T_out, C_out}}
+ {{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "7209baed4b605b158b7eb25de2200e83"}, {"7209baed4b605b158b7eb25de2200e83", "5546c0d2d8da37d92908803d88ff5a646e24a9f9c8c0e9f239726ccc5107d45ed813697aab0b27969930489e47c87475d71b92fc875e268d2ed92fa735b8258c657ff883512adf916a7a8819596e878415da7dc689fc658b862235133b4366e5bea11ece0990a544cb324e27313d67567797213ddb9102e75caca82a15035e44a306c906f8c17e2c88975808b35ad13443849d9ebec10f2c888738ff5b7cb3043b2bbd6098b167746addcc55238fb32d9ef404f3d0f7db0bc5f30aca0cf9ce5f87c989268d18b1069b33bbd5b7818a99603ec0d82871e75cffd1d84e2be1e0f8e8b3678b1ccd7a5a676d83fe0e68f09027ad912d58d2257932750b383e2f2fa3c889ee9d71919cc05d982230c6ff8b7e5e3ed302ed82bed429794c261aa009d231bb6c8675e513313432017cea50843a0309153f7f9d556330f19c38bc5ae6d33d63abaa7ebabd3335c1bf59a2121378288da679259bb1b8a8b027938f3e902c655c781e7f5d9514e53502e7ebc31e344344c3ae2a6397a9a8b846dab8a84174e91664804c7804bab09d6d40aeeb491d6f6184830ac7b5807418a05a7ab9938c3fdc18066b5d503f8c98e83be033b6fba905324267618cc6989b486e0decf7cc897d17be093286a4d4fb5016c3e3323ccc416a30473081473bd471e430194ec4e2ac0af3bca0577b78f4c70e4d"}},
+},
+// Pseudorandom 1, inbound
+{
+ // Inbound
+ True,
+ // R = {K, N, T'}
+ {"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "310495f73b4d20f4d8069bb1d2ed5638"},
+ // AD
+ "88",
+ // T
+ "5de86524ea1542e8f1b8ea118c12d1fd",
+ // C
+ "43f965f6b01b939d972a2b9bd3b2cefe4315da3f97b51af875dc7717b97d9ac37c9e18e4a00fdcc65dde90ebd6c2909fa3e1d83cb07863596408f94334522c1e04688855c44dbee3bad7ab2872c1b87493766c6e0639bcdbbb2717be2d848c37ef034607f6b05facec43f5c1ef99a78631ab8387385cf0b272b0759513807451c63b4ba7f8908e5822b43bea59013c4bba59ab70dd9951ad1d015ccc9b4067aa02cc40d530e2e2bc473906f03a69f5f92183d2094af98edd23199940572edf095a42ec9be535982d6bdf8e525cf2a26011082d0ad019bd3580be817b1049db2e3ca35ee1212b15faa2c35bd4b342c930cc44e77336d84fcbd36454aa3a3cd7961047b58fd26383d1fbe0beb250f8389c1e949728d3d8218b36f4989e3499ced2e660b7ed6a5edb51a36f2fe9f32238f1a318141fcb3bed2c8a34efb5f98b8bccf2548fb542826e6abf3db576ccb064c905c246ecb4ecd5d638e7d3705b549df99de126227485f8dcb499dabc6f3e5d9735a70f1073f708293b2855dd64c981bdfceb8c75bd7d692f7a2d26f453c302d4593af2bb17a785d52bc87914f62056326dbedb8b5d45333dc7fca8d5eea986b1c19ff122b60c74f9220a3eaddf0f40ee105fee1c336c93afef1804a81bb57f918dbd7ef220428dd26c6d83c95e6adcec8f997b8ed810dcdc0bb3867f37",
+ // Output={R', {T_out, C_out}}
+ {{"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "84fe1db6790ae6e32e418a70bb70d695"}, {"84fe1db6790ae6e32e418a70bb70d695", "be638eacedc6fbbdf8d9f75f414b3b43ff4fdef3c261a24ffec5eae75a3a1016432bdfc6df956b1e19eb011dc891238d86938ee98d7e0beac3df360818e45aff037e42e345153f5814937d53f92492b03f526c3e85464912742bbb26df3258e7fe0e3fdd7c8b855122543a6d277f896bec6875e6d320d5f329b90d1e57ea2aa9691542c13c9601f7dae18313737387a85eff1ba244be546cd1511782555b8ab90306bd85170e3a489c13f892f4430ae39c49ab1514d05b510709da34651dbe600f68642541ee9ab2163a0e442b6017014c80e05b622d53fa40cbd5eaafbfec34289c5b48c2908a2e7749e1c3f0cceab57bea1f3c925756e477d0c32c1d6262f259a5b20b8234aba22c36604fa6c9f0b953724089b549b7442adae8a91a7a7c3070aad0099d3cb94c17b2f767a8933bbae1de8322d73d9688f6f211b9b3922e758b2407179083490d3bd2d3f366e012f86aa268c2d24ea843953b3cc4a83f33c795f5df035da1c7ef4b160d013d201adcc469def9b4c6334cb9f091f789ba1a23cb2a667564eea9ea3a24c5f1fea54c8f7842ba6266c5405b6cf5f611ee4d0253b09500ce0e704ae2b9aad6271b59ac3e34a446c03c1cf261757c6798d6cc9fe6be8793666d8d046cb5aee99a0598184b3c614444a7b0ed812fe46c1e7ae9a0aee9f49908e705896edf53a3a90f"}},
+},
+// Pseudorandom 1, outbound
+{
+ // Inbound
+ False,
+ // R = {K, N, T'}
+ {"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "310495f73b4d20f4d8069bb1d2ed5638"},
+ // AD
+ "88",
+ // T
+ "5de86524ea1542e8f1b8ea118c12d1fd",
+ // C
+ "43f965f6b01b939d972a2b9bd3b2cefe4315da3f97b51af875dc7717b97d9ac37c9e18e4a00fdcc65dde90ebd6c2909fa3e1d83cb07863596408f94334522c1e04688855c44dbee3bad7ab2872c1b87493766c6e0639bcdbbb2717be2d848c37ef034607f6b05facec43f5c1ef99a78631ab8387385cf0b272b0759513807451c63b4ba7f8908e5822b43bea59013c4bba59ab70dd9951ad1d015ccc9b4067aa02cc40d530e2e2bc473906f03a69f5f92183d2094af98edd23199940572edf095a42ec9be535982d6bdf8e525cf2a26011082d0ad019bd3580be817b1049db2e3ca35ee1212b15faa2c35bd4b342c930cc44e77336d84fcbd36454aa3a3cd7961047b58fd26383d1fbe0beb250f8389c1e949728d3d8218b36f4989e3499ced2e660b7ed6a5edb51a36f2fe9f32238f1a318141fcb3bed2c8a34efb5f98b8bccf2548fb542826e6abf3db576ccb064c905c246ecb4ecd5d638e7d3705b549df99de126227485f8dcb499dabc6f3e5d9735a70f1073f708293b2855dd64c981bdfceb8c75bd7d692f7a2d26f453c302d4593af2bb17a785d52bc87914f62056326dbedb8b5d45333dc7fca8d5eea986b1c19ff122b60c74f9220a3eaddf0f40ee105fee1c336c93afef1804a81bb57f918dbd7ef220428dd26c6d83c95e6adcec8f997b8ed810dcdc0bb3867f37",
+ // Output={R', {T_out, C_out}}
+ {{"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "84fe1db6790ae6e32e418a70bb70d695"}, {"84fe1db6790ae6e32e418a70bb70d695", "be638eacedc6fbbdf8d9f75f414b3b43ff4fdef3c261a24ffec5eae75a3a1016432bdfc6df956b1e19eb011dc891238d86938ee98d7e0beac3df360818e45aff037e42e345153f5814937d53f92492b03f526c3e85464912742bbb26df3258e7fe0e3fdd7c8b855122543a6d277f896bec6875e6d320d5f329b90d1e57ea2aa9691542c13c9601f7dae18313737387a85eff1ba244be546cd1511782555b8ab90306bd85170e3a489c13f892f4430ae39c49ab1514d05b510709da34651dbe600f68642541ee9ab2163a0e442b6017014c80e05b622d53fa40cbd5eaafbfec34289c5b48c2908a2e7749e1c3f0cceab57bea1f3c925756e477d0c32c1d6262f259a5b20b8234aba22c36604fa6c9f0b953724089b549b7442adae8a91a7a7c3070aad0099d3cb94c17b2f767a8933bbae1de8322d73d9688f6f211b9b3922e758b2407179083490d3bd2d3f366e012f86aa268c2d24ea843953b3cc4a83f33c795f5df035da1c7ef4b160d013d201adcc469def9b4c6334cb9f091f789ba1a23cb2a667564eea9ea3a24c5f1fea54c8f7842ba6266c5405b6cf5f611ee4d0253b09500ce0e704ae2b9aad6271b59ac3e34a446c03c1cf261757c6798d6cc9fe6be8793666d8d046cb5aee99a0598184b3c614444a7b0ed812fe46c1e7ae9a0aee9f49908e705896edf53a3a90f"}},
+},
+// Pseudorandom 2, inbound
+{
+ // Inbound
+ True,
+ // R = {K, N, T'}
+ {"302b0f1333b68c8c2c367b1aa02701e07f715b2fc28f34e124893657a98d5442339c9dc55adec43305e5c03e0b9ac69d35f31e92c6bf9aa066607895b453b89e", "02899ad22f2f01d8768323613476c78c", "db34fd587ddf145c5aa1ac58bef5756d"},
+ // AD
+ "ab",
+ // T
+ "867464943ada7a8decef75a961214f9a",
+ // C
+ "0f0cfeed7dcd312b7b769cc859b20a8e18da16451925a0153ae6a57226fec6b2048dea4584e47e078ecbce0f2ca6413a2bb4e30fd6628a036d1749556adb012d110e23c979dc26c2aee3f24bf2ccf27cfd6d294073a20e9c4c5401c09bc4b2e38b6002b2b320b408b99798db1222034813fd70723a141de5a11679a56b704b1cd8751e919565ea129ce1f9fc2883c7d4cac0d8fd4da61d57501788105ef0d622fca6bfbf72b11a3a03d388c99e4aea582db920872be152bf89dc672383263936d93c0c9915db9b103cbcff5e90f4d9dbae0c4ea8e8464332b9ffaa478735faee477e28355be86f572e2ccca91e60e1874edd1d592b0f4f625276dd5a270a830147365c3fa20168088477c08c56352015ee962d1ce6d24456c96b649921ecffbafa21ff713e2d0da18f2e72e49830ada7878b7fba8eb3700c1db10cbd62ddd6bf1350374a10df5578e6b0774b510d15f11bbe95fd3ed87a8bd68c5110621e12d708f266ee8e48979e2d0fb222c008faea9d9f4ae14951301f9359ed133c5328e6fdd817e83ad84341500752b052bea6432841c801ffd68856c597dc0ce006c89222f1173194044de3d0f75b670923c4de63c683de97990af9430f83ba7510220f56a46e8a47b6ee46a4fcc132d33e059dc3783e3dfe2ecd673588feeb4af5945e18693238520aada42ab371ff4e",
+ // Output={R', {T_out, C_out}}
+ {{"302b0f1333b68c8c2c367b1aa02701e07f715b2fc28f34e124893657a98d5442339c9dc55adec43305e5c03e0b9ac69d35f31e92c6bf9aa066607895b453b89e", "02899ad22f2f01d8768323613476c78c", "61637a70ae9a95105b1e78ff6892e60e"}, {"61637a70ae9a95105b1e78ff6892e60e", "b9b2516c278a8b4bba221b185e990d4814e94b8ea6ef5e7585945ec250c1d427d2c322e3c3f3f406a43408296e0820debb518543be2ed9a18d61b0ac46e1de159101fb6431711f43eb3e35a0ab1451c30e4d895f888cfada66cffe67de67254e8bd4b3e0834f07033206c3449ae8f8ced104c14a0df0ac8fc2757ae63e1cdc99da87f5bc9fc66d2bb5216e641c04f234da501fa721263229948e51ce73c355e302219f6a8f24daeb6c771ff7aeb7f16fc431551618d32c3ea78543bc71d95593a1675b5a1fa936db5945dff819abb197da2dfa460a7619033c9de74679f02fa73badd4ce89a43b25517a12eedd5b3464ca44f4c68e8f14e671f366a541f340b376a5890202f72e15cc22ba1d2573190e3cc65ba042e874d05ed11a16bd5f93a8defb047a223d647b54b0531fc76beb3c7a23766d7cf84479aaa3c25a8b7cc40a31603283aaf98daedc2990c2c4b6006d0a9e80be6bc1a34e65b12a7414acc4046f5f653b0ea2b44e1c93ce1ae8763aa88c366349db4b2305b57030290e989f65d035fdf0375bd889552a79f6647a5810ed2020c1821e78b150501f3e41e4b836ea079fc7b89e215efd9dfb02bcbeb857b0940cb70f64840b40cddf0fc3e3ff3e561b709d8eccbd62b6cb28ebe49003cd1569eb569e87bc24c5d245079da7ae610146aef4225b6f3c6e0ce3aacc"}},
+},
+};
+
+static const struct cgo_relay_originate_testvec {
+ cgo_tv_state_t state_in;
+ const char *cmd;
+ const char *msg;
+ struct {
+ cgo_tv_state_t state;
+ struct {
+ const char *t_out;
+ const char *msg_out;
+ } result;
+ } output;
+} CGO_RELAY_ORIGINATE_TESTVECS[] = {
+// All zeroes, originating
+{
+ // R = {K, N, T'}
+ {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"},
+ // AD
+ "00",
+ // M
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // Output={R', {T_out, C_out}}
+ {{"7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f73296", "12dce4a0e5bc792b5b5a55f9c2f30e07", "66e94bd4ef8a2c3b884cfa59ca342b2e"}, {"66e94bd4ef8a2c3b884cfa59ca342b2e", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}},
+},
+// Pseudorandom 1, originating
+{
+ // R = {K, N, T'}
+ {"3ab14ee71f417dc6cba5aaaba8eff9c3cd5f408020b4e8586ff734dad4aff593f4d863afbc519eba44d6e8643ae3fabf7ba8cd0803094d82b18acb03c1207927", "e616de4990c8efc5e58131f635f35776", "310495f73b4d20f4d8069bb1d2ed5638"},
+ // AD
+ "88",
+ // M
+ "43f965f6b01b939d972a2b9bd3b2cefe4315da3f97b51af875dc7717b97d9ac37c9e18e4a00fdcc65dde90ebd6c2909fa3e1d83cb07863596408f94334522c1e04688855c44dbee3bad7ab2872c1b87493766c6e0639bcdbbb2717be2d848c37ef034607f6b05facec43f5c1ef99a78631ab8387385cf0b272b0759513807451c63b4ba7f8908e5822b43bea59013c4bba59ab70dd9951ad1d015ccc9b4067aa02cc40d530e2e2bc473906f03a69f5f92183d2094af98edd23199940572edf095a42ec9be535982d6bdf8e525cf2a26011082d0ad019bd3580be817b1049db2e3ca35ee1212b15faa2c35bd4b342c930cc44e77336d84fcbd36454aa3a3cd7961047b58fd26383d1fbe0beb250f8389c1e949728d3d8218b36f4989e3499ced2e660b7ed6a5edb51a36f2fe9f32238f1a318141fcb3bed2c8a34efb5f98b8bccf2548fb542826e6abf3db576ccb064c905c246ecb4ecd5d638e7d3705b549df99de126227485f8dcb499dabc6f3e5d9735a70f1073f708293b2855dd64c981bdfceb8c75bd7d692f7a2d26f453c302d4593af2bb17a785d52bc87914f62056326dbedb8b5d45333dc7fca8d5eea986b1c19ff122b60c74f9220a3eaddf0f40ee105fee1c336c93afef1804a81bb57f918dbd7ef220428dd26c6d83c95e6adcec8f997b8ed810dcdc0bb3867f37",
+ // Output={R', {T_out, C_out}}
+ {{"c24b000843784bc008c70b977e62ed82085ed0cda9f841da2c89d1832e763b9e283c36875fa41caae5913293d8014451c10fedddf362849bcaaa1833a3b8fcd8", "497798331f2c32ca4de4b1b55b82c306", "b8b3b69f6e175a5649013ca99c838291"}, {"b8b3b69f6e175a5649013ca99c838291", "94773462bcfb3728ec6f2f4e3b7020234abd8a6fa778a49788509b6452556e951f49a20a552035b38143907c59788c6865dac89ec22af08cc98ed1fcf55debccd3bb18c91340205524b36e1ec0ca0c082f79c575e7e0c77ade4b6084f6b6a12592f9a24c715bc92ee2531641cb11c6e9a462242354d655c392fccc1c84af5217cefb9806eb9990cf36034188600b2a123d860d0c661362f511e7d4eafc46a38c030fbe884a681fedef9c04375793435784579a3640ce2d75d9553936e877c3c24b33e0ffa88d59fed2fbbaf91e446c8d37a6b1400f7dfcd6ba8fa425c36e111a71c661f81ac8824524038a8dab5ac5a17014f4e7af5638e27e14869b51a9a2ff43fc9b3d7205e9f2e9f20c80d52778c26589179631345b0cedcb76d4862e3f88dcd27074da5d8b36ce7f2fbb972dafe327fd0e68620f5b284b1a7f1e64e33df2abd0f4aabe30b0e168f52ea39f1c5755276bc5c25cfa3960c2646ac13cbf2d9d1748e9c8db3664a98b4ef4e6f4a401cde973a62f0d4a6409447dfd2500b916015e50d79eeaa6508295d7959cb45af82b2b1b081b84911f9feeb994ddc5c472b342eef82d611809051658215158b99f5e3002e97f343e3b29eaad6489557573780b13956e4665dd0b859631d9937d4f90e0f810b36babfe8a1371b6eb985fd600d8353962cca9ce5b9d2ebf0da8"}},
+},
+// Pseudorandom 2, originating
+{
+ // R = {K, N, T'}
+ {"302b0f1333b68c8c2c367b1aa02701e07f715b2fc28f34e124893657a98d5442339c9dc55adec43305e5c03e0b9ac69d35f31e92c6bf9aa066607895b453b89e", "02899ad22f2f01d8768323613476c78c", "db34fd587ddf145c5aa1ac58bef5756d"},
+ // AD
+ "ab",
+ // M
+ "0f0cfeed7dcd312b7b769cc859b20a8e18da16451925a0153ae6a57226fec6b2048dea4584e47e078ecbce0f2ca6413a2bb4e30fd6628a036d1749556adb012d110e23c979dc26c2aee3f24bf2ccf27cfd6d294073a20e9c4c5401c09bc4b2e38b6002b2b320b408b99798db1222034813fd70723a141de5a11679a56b704b1cd8751e919565ea129ce1f9fc2883c7d4cac0d8fd4da61d57501788105ef0d622fca6bfbf72b11a3a03d388c99e4aea582db920872be152bf89dc672383263936d93c0c9915db9b103cbcff5e90f4d9dbae0c4ea8e8464332b9ffaa478735faee477e28355be86f572e2ccca91e60e1874edd1d592b0f4f625276dd5a270a830147365c3fa20168088477c08c56352015ee962d1ce6d24456c96b649921ecffbafa21ff713e2d0da18f2e72e49830ada7878b7fba8eb3700c1db10cbd62ddd6bf1350374a10df5578e6b0774b510d15f11bbe95fd3ed87a8bd68c5110621e12d708f266ee8e48979e2d0fb222c008faea9d9f4ae14951301f9359ed133c5328e6fdd817e83ad84341500752b052bea6432841c801ffd68856c597dc0ce006c89222f1173194044de3d0f75b670923c4de63c683de97990af9430f83ba7510220f56a46e8a47b6ee46a4fcc132d33e059dc3783e3dfe2ecd673588feeb4af5945e18693238520aada42ab371ff4e",
+ // Output={R', {T_out, C_out}}
+ {{"60b9d644a620c3f36181f6f3ecbb0be41d400b78822dd3247247d286a5b80baec2dfc3694f119beab9b40fd538844d159e7bf256fb2ce53fe33e4c8763180b0a", "094b5cdc3a49cc51aab3e1f331f03df6", "99daac5f8bdba8f4807e719c768cb3ce"}, {"99daac5f8bdba8f4807e719c768cb3ce", "30db410a04452437045b7f51210bd01eab5d034c146c766ef73a9500b1c7f75d5ea7b1fe47f8eb927bcac6fb756e80cdd48b381a431c858432047410cd526bd91283a53ab94371bff4c4370e8dc8671349316759bdd01bbe432423a66a8497a7091c8056af277112a04c65946dbf82d076e66647456e991ff44c689e57d475956a3c1dd5f1a870e711ed57dc287b96f6437e2e4194e341a2dc5913631eab53f899f09ee41361b4d74c508f42ae972c93d21797342242b7e4e39d24888dfd215458a8e134fb9da152a0b1e5304685919f5dc3da8a0dc04906763075432ce92afe1283b1d344c36832bb54cf47a28c13263fd34558ef1c7827b4d8c1aea20f23316b04d1750bf42b6317a421618c3af00f5469d28aa52e8aef1e76d80754a52982285c1d558c61268d40f2e931c0b3848f70da72b07867df56de689a19f2db0a379207ca462a0bc97a3ea7d111a144454432e4d0eb3ee1fc5f905923effa1b196ce29f9c07d32fabcdfcce4c2d582a7b80b65fff05ffd2b5e7d91fca0817e9458c68d6919ad442ca1d20d77c7c0b6e924af2665d9eeaeeac28692f978eecd4e1d5878ce300f8035d0a7ff6050a172c1d328bb392e4d55198a976d45f7d9670eeb67ed4b79c95b219fc9cf3c7613c128e2224d2799d9459b4941a248589d7bc1cd644ac96aa49e0d630288b73a028"}},
+},
+// Pseudorandom 3, originating
+{
+ // R = {K, N, T'}
+ {"f69da975bf0055353e52a8b3fa834b1bcedf1445e4b2f1dca13f59a306e8040ce64d5922b2b9de5735a96e2fa2e9524e99ce5b8888fd000f570f148191bdb54f", "8e4219f5b72d0bbf1f47005632816b36", "c5301aaf38e66f698293618354d06e0a"},
+ // AD
+ "90",
+ // M
+ "727ee8dff3a22ad873545c040d22a67a6caac97c308a0f4109da1a1d67695d9fd7570a27593fefcdc0ce568ff6f8998a03791e12720a86d95110540073e104a86ba14ac9e58705ff20ebfced49a91d832a635924193dbf14ff995da7d4cbb4752d364908c1096606cee429adad73513bfd848fb6132fad9531178b419d4c6670224e858ff0a413b083b58cb6a8297bc7474e48050ac926c3a568df88feb135e9011d26eb2327c0797fd821a9bca3052e116f26844a2a5d23542ea666f2225700dd134cc166e2cd36f88be6a4b367be083e7d7be99a9205489de7ece3308846fcad66dd249ada0c559999fc3dd9e36036831e3e2aa51d0190b227f3bb54b365ea668009298612308361537b66e143fdb5b3da43a6a141910b7daef3dd4c5a819749c1d5d005c3c39bf7d2d749754614e794c51a965694904d30fa5be6fba2360ccf46c4ed2b4829f6434bb8951e82580a4da3d7075d734c4c12560693b9bacb1ce7ee953d7ce9dec24d7a129e8e582a3e2e1168e7b966c2e435b21f9b7ba83e27023b287e7fc420c5934af909e1a3fcb8415347c5ebd30aebaf6fe11cbea60d8dbe78cd54736dcb6a0cab929175417510d0ab2c4688b91c8d75d5a9b51ff15fddeb1a08402dc7748eb5b9d219f4ecb4116be1765a03fd06fc01d8e366b945cf6557257ef0ec2b74619d4e081c89",
+ // Output={R', {T_out, C_out}}
+ {{"c658a50d452e0ac66a543a15dfb30f791509266d47e259d56374787e3e2ccc49a06c6d2d65553223ace6097a3fb7cee5f4af4602a4c73c8128391e2454b7caa1", "2436c77f19dee78ff65f39967659e7d5", "276d823e18b1a06c0fe224431630b7b2"}, {"276d823e18b1a06c0fe224431630b7b2", "545b61a9a2d88a6f0e389c864fcdec76f5d04b836a1d1a48b26895f4c8829af6de70ac08578f2e1cd054f4a9ab5efbdbd872b712ca451270f472a621a95827a382829d794395ae507ccc1df35a677d069207296faa9c2a1d3a454ada30deac8e3a2fd4cfa69c298f9ae0f6a6d15b2a3404c84233c29fc8e85cdf009dfab83ff18f0a7f9ed8a4d7ef10e6fae321c5c526f01dc5f045ec9504e270cb634b072b03d1a0ef8b013913684b935d2883bdfd49ce8dbde8e603663b7ebe869072d61462aea8f7da0d7bc4be054032995c5f5862493f3e45580d9415a3f68eb083092a4c1066f06725da1751b025efb015683cc1935cfafafe7aef90d9c18f2a5f2cce060716838303ca8b7de3164fc09a9d15ccbedd7c24bd47f9585b3b333012ce3a1718cd8ad493b90695734350ac345c42c911d5038b9f288d2d5da8e1bafe1f22967eef3f705a49310f7ebb0837303ede480564cbd5174d354c15668846ed5e9b40002f831d118aeb1d78fd41a9e80064da3bc0f84fe0898e0e2d81cf20a14baebb1f1d784682fce429625f6a8999177f9e1adf515638280279f5dbbb8eff1fb09ba3782cb6bb49ae28b38883808c69c70a45cf2efb5932c67c77756a9eae3cc63cab0f3554cc55e6fe6f1d1fe6a7fd27c248fa0f491a5c459c0e51bc06d9574cb22c1c4d5aa64b4b66875233bbdd"}},
+},
+};
+
+static const struct cgo_client_originate_testvec {
+ cgo_tv_state_t state_in[3];
+ int target_hop;
+ const char *cmd;
+ const char *msg;
+ struct {
+ cgo_tv_state_t state[3];
+ struct {
+ const char *t_out;
+ const char *msg_out;
+ } result;
+ } output;
+} CGO_CLIENT_ORIGINATE_TESTVECS[] = {
+// All zeros, hop 3/3
+{
+ // S{}
+ {{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}, {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000"}},
+ // d
+ 3,
+ // AD
+ "00",
+ // M
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // Output={S'{}, T, C}
+ {{{"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "af65bb470269ecd7af01f68f1a2b7b78"}, {"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "140f0f1011b5223d79587717ffd9ec3a"}, {"7941dd0a63d994703e63d94a446804213ab4fb1d2b7ba376590a2c241d1f508dc6a7f418a14503deb89b17aadb2806f73fc06e5d14e675f5ec880023d4f73296", "12dce4a0e5bc792b5b5a55f9c2f30e07", "00000000000000000000000000000000"}}, {"1471e71e6fb1f04233a8ec5daa6209e0", "66e94bd4ef8a2c3b884cfa59ca342b2e58e2fccefa7e3061367f1d57a4e7455a0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40deb3fa6794f8fd8f55a88dcbda9d68f2137cc9c83420077e7cf28ab2696b0df05d11452b58ac50aa2eb3a195b61b87e5c65a6dd5d7f7a84065d5a17ff46273086002496db63fa4b91bee387fa3030c95a73f8d0437e0915fbce5d7a62d8dab0a58b2431bc0bede02550f40238969ec780410befccde6944b69dd007debe39a9dbc5e24f519a4bdf478b1d9ec0b67125f28b06efaa55d79412ad628d45089c3c304f94db3a21df6cdaf6d2e2e3b355441eff64ad90527e752a4b2ebb4d0a1070ce2e2982e272fdb7cf4b584b095a0f957fdb828689437e37dc48b2ad379c6f3c6e957ee77afb88c65949ba12eec45c22865e4907ae42aee813898acdf91e2e4c21d828e0a76de2bb6bb6f869e5eef1f618dedd27562812b9a14e8996a5c352df3817e60d6ec20119a52c80a61ec195622627240212decca515feab63e2734587948a836a7de205cfec0c288351c"}},
+},
+// All ones, hop 3/3
+{
+ // S{}
+ {{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff"}},
+ // d
+ 3,
+ // AD
+ "ff",
+ // M
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ // Output={S'{}, T, C}
+ {{{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "3cf25f81c98d0be16ddbbffeefbdc308"}, {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff", "a9166add184e00b007217cb4e4f52ee5"}, {"be938fc23009440bfb5d7bba1d28428ec0897793bb878b8e1eb3ec1257b88024d551d770b56c9312de3dd4ac64e194c91185a89f2ba01f90b03b3acb93f634df", "4b263f03af0acda2f9721d0f4c0783c7", "ffffffffffffffffffffffffffffffff"}}, {"c8c388584500c58ced7ee209c08b920a", "c0685473f8558a9f9f2f22cfb31f211c6b25b7ebdabf2507b4269636caa01e1f6d4f4f5690c48d6940361059b37516b52b9d9ad93388f964666e7492a6adb91645a02cf39eed4ebd0354d8f484106c04ebb0e53d858c75a44e3145471bf93d09d48af913fdcefa6a0dd3fb730e604035d494f0a5706c3b63424253b7287392a44e9b2f66f765dd7cda20c76a2444a4dfa84170d810eb13e720867170c243ff4d9662b1df15b826c664f1a52e4f57be57b49105895e8ae3b87fd969034f67ae9784d946935dac622cb4cf786ad937174ceab2c766be361f8efc0479aa0b45c5e90da1dcee6802b5acf53dfee7a12e27d55e832b5f77360cd7190522d9057a556b8e1de773a0c29cc20c44dd963395cce1c19633fe1e386a3cc87082d5e645914d96ce3d8dcb9653dedacd8bfc2fe5d7a3e9e205a9c0961dd83d5b5515842fa3291877146081d5d776c4675de92b3f92edd80d7792b9a9f203c6650a33e54822d45a92c7136cf4fdbe6fe698ed6d3596cce17853aa988142a5925e1cd4382fb4d43307c26d57676c1ae5aaec6100de8414f8fc763e87a052f3d7519d539499d90f427c951d91348d9f0c7d77dd454bd8cd80b9b13a1870f95ea19e8dbdfd78ca4cfd520e5bcfcbd751252775165790b250b0d87989a60ccbd4243f8409a28d1d0536d9d9ad51ee474d24a92870b7"}},
+},
+// Pesudorandom 1, hop 1/3
+{
+ // S{}
+ {{"80819c55d001b73b8d51a5c9ce4fc8e2a197bd4891f0f38df791e92fc687c99214992b6749f5b96d6477f7a2821029f714de39b47396fff84b79406ceb667213", "475cec821a2bb29682c9de4ed89fa2bc", "63c839b54659920bbf42c8a76eedc3a9"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "eae6b850f1f43e00be741946b5038517"}, {"cc01d778ccfabfad7a442a266aac199e277b38618ba19816d1d668c139367c8ae4c9fc4e6b5a7a214175506d4dffa1c159bc499afc638e6a54a546380b65bcd8", "e459433194d5ce2daf958ef6cb22a391", "34df2febf45efcb197fabf5eef51bf5e"}},
+ // d
+ 1,
+ // AD
+ "00",
+ // M
+ "32b9e80d44f7fd35dc254f1b07cd10ca91e1c9ba7835a9581e99245677c1ecec22de4e30ef1799ab658305c8266d4f1c71e4ad51cd9d5798de85ece04f6ee9636ad4a14a132278df2c34a449b7d53cf71fb4e55affbc7cbc6699b97356a81d4f70591177aa509df7d8ada37bd7c6082059081e8058087bd5e357544b2b2067c62a3cb123592b44bef8ccb5f259e859ac8d6c9cf599605b370a067dced095f96dd03b3577d20b78afeb8c25cbe3b2e52f2105e952603af981a739216fc6fa29f1a417ea501199a74bab8821e828a1e66e8e0de40138aca846902f7e2c5545cb2263a8b148e65fd793abbd831d97771d5ecbc07bcde5b5cfa02489783302174b36f7570c546fcb05b1d1031089b806d9b54d2b0ebf0fa0ce8b486e26c36825b55a1bcdd001b4a6ab3686ae3b5fef3500837a1eb58e44602c87ce6d384d3dab73fc18e662f03a4112c6fd70ee2063a5dd37bc159f2584b8bcc63106ff6f219cb3e45d57e3b78c88fb0acbba7b58f2f3c54d1877160199583876e1a321bfaa813e0ce1e1803fff094e437ca879ab2d85248050f720bfac980a8455f1bd83ad8648af0052a3ff1203a75b033254edcbfc144c53ec72b603b404aac06021d51524953e9d267c912cc82d61b70d47775d80451ae59071ce7596f3dfe60ff0f636ec06689993ed52f8efd7d04415350421",
+ // Output={S'{}, T, C}
+ {{{"d0f4674c280810a523aa25f98bbcff032b4f78f536ab763365384c3f55117e26da677483b85954db5e0840ee66ed269c7089e404f881dea4ecfa1619ca809444", "2b6b31a8b26936bf1823ea99b866d000", "475cec821a2bb29682c9de4ed89fa2bc"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "eae6b850f1f43e00be741946b5038517"}, {"cc01d778ccfabfad7a442a266aac199e277b38618ba19816d1d668c139367c8ae4c9fc4e6b5a7a214175506d4dffa1c159bc499afc638e6a54a546380b65bcd8", "e459433194d5ce2daf958ef6cb22a391", "34df2febf45efcb197fabf5eef51bf5e"}}, {"7d05e89f33820206b821fdd7a7465525", "f97feaae58ac1c0e4a69df97b1da3641d0c8795a1ab5e957d94629b9b181129b58bdc5df73588c0068bc67ef14a50d8cb8dd1dce8c1c5ff6b7a0616bbde921f442dd876b3622f88918ba01234920759d4ec3f1079f4d5029b9903fd2b9c60540b89b59134c36b64b58509791cb6b3074f84fed410f27cd4d868a9cb59df2ebe9e3358ed557c4ed2d91e7f3080468734df02536d5e30c27d4021d5ce00eb38b08cde074587fb321510139c4d865da92a4b0ba3833d8b110e3c81e3226099677f91f570add37f6867e9faae6331bc0ca19e475ac75d8dd688b1d77cfa5c28f3e0838bb3f8457bbe7bfb567826cf42913108c268d710253c74dc09def9885c61a3e0ca65231121d746a720d0f6454d09613e9620c0ffe922be22aae5c7e5ac17b083cff28c48c1c205834880689df9dfc5085775695ac3931dce1b05a669c96664fcdb86794d3883de5f9396c351ef26880f8f5d1f64bde7c73fdf177363343a37497de8e9aa4e139c196c9069e4b9a4cfc71e89a8deb80a2a1810e9584002f3d054e64c7e3afd7f215cdac0ea35ae8e6e88c290006ef80c1a193be34f89ac8ac8f03971c2d8f35fa0ceddf9a34d9482bc9cb9787faf942606131abcce19b6ab1aba23bd45c31d15e1189987114f507661916aae148f80b03a3d769a277ca9ce8c2e9d46f4b58319a72627eba3024"}},
+},
+// Pesudorandom 1, hop 3/3
+{
+ // S{}
+ {{"80819c55d001b73b8d51a5c9ce4fc8e2a197bd4891f0f38df791e92fc687c99214992b6749f5b96d6477f7a2821029f714de39b47396fff84b79406ceb667213", "475cec821a2bb29682c9de4ed89fa2bc", "63c839b54659920bbf42c8a76eedc3a9"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "eae6b850f1f43e00be741946b5038517"}, {"cc01d778ccfabfad7a442a266aac199e277b38618ba19816d1d668c139367c8ae4c9fc4e6b5a7a214175506d4dffa1c159bc499afc638e6a54a546380b65bcd8", "e459433194d5ce2daf958ef6cb22a391", "34df2febf45efcb197fabf5eef51bf5e"}},
+ // d
+ 3,
+ // AD
+ "00",
+ // M
+ "32b9e80d44f7fd35dc254f1b07cd10ca91e1c9ba7835a9581e99245677c1ecec22de4e30ef1799ab658305c8266d4f1c71e4ad51cd9d5798de85ece04f6ee9636ad4a14a132278df2c34a449b7d53cf71fb4e55affbc7cbc6699b97356a81d4f70591177aa509df7d8ada37bd7c6082059081e8058087bd5e357544b2b2067c62a3cb123592b44bef8ccb5f259e859ac8d6c9cf599605b370a067dced095f96dd03b3577d20b78afeb8c25cbe3b2e52f2105e952603af981a739216fc6fa29f1a417ea501199a74bab8821e828a1e66e8e0de40138aca846902f7e2c5545cb2263a8b148e65fd793abbd831d97771d5ecbc07bcde5b5cfa02489783302174b36f7570c546fcb05b1d1031089b806d9b54d2b0ebf0fa0ce8b486e26c36825b55a1bcdd001b4a6ab3686ae3b5fef3500837a1eb58e44602c87ce6d384d3dab73fc18e662f03a4112c6fd70ee2063a5dd37bc159f2584b8bcc63106ff6f219cb3e45d57e3b78c88fb0acbba7b58f2f3c54d1877160199583876e1a321bfaa813e0ce1e1803fff094e437ca879ab2d85248050f720bfac980a8455f1bd83ad8648af0052a3ff1203a75b033254edcbfc144c53ec72b603b404aac06021d51524953e9d267c912cc82d61b70d47775d80451ae59071ce7596f3dfe60ff0f636ec06689993ed52f8efd7d04415350421",
+ // Output={S'{}, T, C}
+ {{{"80819c55d001b73b8d51a5c9ce4fc8e2a197bd4891f0f38df791e92fc687c99214992b6749f5b96d6477f7a2821029f714de39b47396fff84b79406ceb667213", "475cec821a2bb29682c9de4ed89fa2bc", "959551c3e8dc83f3cf2e0bf11a1acae3"}, {"79d6e9f34cd2a01b89130bc43002e94a4c3494dfc8db9d11e08d7b8ae7782b38fde2c00e9819d5c619a5c8a92afbabdb727108b5dd4ba9d572b47567685c9e7c", "d6dc99f4ce27ffe7ad3b40c73be86ad8", "9e9c84b867f7dbeb705bfcce09431813"}, {"12f2e45f012ffc1430fee1fb322879ba934f887fe2e7e7ce98071c61bc1086dbb2877845f5fb3869d3a4d23cdbcb44c85aeb9e43771755c9be3bbdb42ecac024", "88ba0caf597d953a26064c5872bdea5b", "e459433194d5ce2daf958ef6cb22a391"}}, {"3222f41f846157bdc258ac55d8f7bd6e", "fb76e827b3a0b6b8d031ea07b273c8f47763cd2c7af610dd0109ff42838bc39d5128492788a36426fc5ab17bab4906c7c4a390ceabe14ccc96ac2ec36dac92ed2a579097d1cb2258aef9cf35e950113adbb305b7ac73e1c1ea9b4e10ff39adc6b129cad8020fdcb349fd383595c61bb551d026b84ed74674bcfbbe027b4814713487a53e5aac4120da59d27b0abce7f438294860c211f19160b53deb9ab5abf49996a1d474518196a1020b460282f9dc3802db33c19e3b50d74fc5f8083403227d9801a158977f36cb2eae1525488660b59e5f45f346f24def7044f1b8e714268ff423d8c9b895e936669b4df15a99ba6382b02349f792b2383a4bd632efb6b6a5b7cbb82eaae1b0261f5386844813f23e08eeb68d63162681d51bf0d38beff2c34afc2e57772887f5c0e341ff2b7c003b24d32bb3873c7f6d5b946c36b18eb0ddfe907c201cd42b7373eb52d0c4bd8eed5179a2081504847f7f99fe529139cdde799105e8c05cf8376eaddf4af1f779835910659ff93ad3f55b25defbcc10567d23247a0f2e688363f91f90184cda34d8e4ad80d4f9f47d9d1af9c10474f7e66bef3ad0a49fbdc8020899289bea741a004df514b8ec5bf2443e3de433cd25916b2889fe6a624e65c4b1306d9feb14fbad48e2c212cb4aa8db92c31b87c20da5b493410fdafaab09fdfb57c9aa"}},
+},
+// Pesudorandom 2, hop 2/3
+{
+ // S{}
+ {{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "7dae89533c98d159590a3bc5da3d5fb6"}, {"ff9b9925190d45c46e5ac9eae38da326739b3180432cf0c36cd9346699bd022c4dcb3aa2811f8ab0a2a72cfdc9e13b817d0a20cc1b03f51b8133c6d36d2c4ffa", "2e666844518d40d4a1efee952db70f36", "eeb1f87fd5c7a6b016b6df886c3f2f92"}, {"25f3b6dc37742bf020ad710e67f87ee274f5fe5d0c75c9a22da939847d1f4878de7d35867c306f3176d92d2d5900d33dec007edf02644f01046b9deff015c30f", "df6876f95d2387d8f419d018a826ffed", "c16980670fba6dcd755c567c721e0dcd"}},
+ // d
+ 2,
+ // AD
+ "da",
+ // M
+ "346681ef9e47fff29ddaf41628ae3021888028316787f1887b6c099c921a8915b4d7937a9565d928764fae620b57d117ccd75cf8b633f2d1f1404b65f2479c8d8d590a15da2b40b14987d8968b7d210965f158627a72ba31ccecd5727f2dabf17dacc69027ccf4c53da96a75e6d28a15ffecaec1965a62402a1cc5e9cc26be181689132f54956f99192ac9bbb929c5aec7048a6653ad40cbc4fb029ea97bc15c8b05395e822af36a8b949817ee0f022c8f971eefc5b31bb46e095d4aea07fa97854e1ca4a208bebb65a605089f60a21ef5685b67d312edff8b2cc81830eab9d27ab0a7be29b7c88abb995492564772d518a912c6b40f58ab41c0497995d9b593f0387a3e597728d08f5267fba8370a062817cdf506119e0c5cc69900709195a2288322de578af491698360ad1f6b34b341e10eb21e22f6c5a6e12e26250aeb528aaa533d592b268fb22b3e77ada84d478ee9d0f2742cbb54be14503c21e39efcc73774b24bf28747203c5ff456457139fec8a46c8243b4b9738c27972e6d8f0ef9fa18944aaeed4deb437522f04795ecd7bee79f0a6d7c6c6acd90dac9a935d5f252134cd4ca1e2e0c4386fdae67950f1234cda5472e61a32bf9f037c068fe81a955d1e56a92ad1a8f16e6a31bfc0f8b3cef96410a72b92a75b09a0071ff0c0e99dd322ab7d8e4a2a2c2122af6",
+ // Output={S'{}, T, C}
+ {{{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "2d8aa5329c2fab108e90f64a904c4def"}, {"64b7371338ad74c249ba606c677f38b5c08ba69a7ae33c1be26ef81ea604a24a968678f48075273c6b35311642a72466fd2a6b059217f66752b0c9e15de40a5f", "5f6d3291d9d5bf3c3bece127fbf3886b", "2e666844518d40d4a1efee952db70f36"}, {"25f3b6dc37742bf020ad710e67f87ee274f5fe5d0c75c9a22da939847d1f4878de7d35867c306f3176d92d2d5900d33dec007edf02644f01046b9deff015c30f", "df6876f95d2387d8f419d018a826ffed", "c16980670fba6dcd755c567c721e0dcd"}}, {"9527488f5d1c2671e0e8139423149285", "c036126d33eea9f7cf865a9ab8e8eaace3a59f1064fa7506d45862ceb119ed854e1ab2f4294c77beb60564e2095f1f219dac41a024361e0fce045947a5e104a6db4b35175b09fca762121d46be7b4b20c674e4a13a53585586c8318549b86c02db4a554e1a43674237136f91e91e75c7ef74e6d4bceeb682e27ffbd2f47ddf667ad89fea7c48e6fbe69b8a3e54eb31585612719394480416296689d427a59b0f3adf4d92fa239c983a2c010cffe9366c01a1c945757ba07aec7c3df58b95f567e8de04d5719c2c7c62cd44668d43777b87db9126b2fccb62b241ec9d9701e8a34125a4dc2653a3de1f77415cafa76bc2713bed61c44001fb23170d716d008f12b236c0380253f2779fe52e6b2c011ffe312617b149c0b2b47055dc832ead1b297ead29028a4a0dbed96809c2aede9b276458a8a6c142a6a7876de3cfba1d4d0dea00095a66b9e925a3593b956a7e734b074941fc60d656e27a7d24f196cfe928400a180a1b7eb591c7b4e394b2c13040a98612e078094586bb197a585505335f4b5f1f721df1ee76ef27a8f6927fc40077be55a45b093d4fa1057a4a88937174885732f91d04a87424539302c7f9590e4d0b62abfdbd0f162fa3c7d750b8f212a2612127fd2443416736578deeccc76284c164a282f94786812031a19f35629e253a86c730f08676fbd0b0b41d"}},
+},
+// Pesudorandom 2, hop 3/3
+{
+ // S{}
+ {{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "7dae89533c98d159590a3bc5da3d5fb6"}, {"ff9b9925190d45c46e5ac9eae38da326739b3180432cf0c36cd9346699bd022c4dcb3aa2811f8ab0a2a72cfdc9e13b817d0a20cc1b03f51b8133c6d36d2c4ffa", "2e666844518d40d4a1efee952db70f36", "eeb1f87fd5c7a6b016b6df886c3f2f92"}, {"25f3b6dc37742bf020ad710e67f87ee274f5fe5d0c75c9a22da939847d1f4878de7d35867c306f3176d92d2d5900d33dec007edf02644f01046b9deff015c30f", "df6876f95d2387d8f419d018a826ffed", "c16980670fba6dcd755c567c721e0dcd"}},
+ // d
+ 3,
+ // AD
+ "da",
+ // M
+ "346681ef9e47fff29ddaf41628ae3021888028316787f1887b6c099c921a8915b4d7937a9565d928764fae620b57d117ccd75cf8b633f2d1f1404b65f2479c8d8d590a15da2b40b14987d8968b7d210965f158627a72ba31ccecd5727f2dabf17dacc69027ccf4c53da96a75e6d28a15ffecaec1965a62402a1cc5e9cc26be181689132f54956f99192ac9bbb929c5aec7048a6653ad40cbc4fb029ea97bc15c8b05395e822af36a8b949817ee0f022c8f971eefc5b31bb46e095d4aea07fa97854e1ca4a208bebb65a605089f60a21ef5685b67d312edff8b2cc81830eab9d27ab0a7be29b7c88abb995492564772d518a912c6b40f58ab41c0497995d9b593f0387a3e597728d08f5267fba8370a062817cdf506119e0c5cc69900709195a2288322de578af491698360ad1f6b34b341e10eb21e22f6c5a6e12e26250aeb528aaa533d592b268fb22b3e77ada84d478ee9d0f2742cbb54be14503c21e39efcc73774b24bf28747203c5ff456457139fec8a46c8243b4b9738c27972e6d8f0ef9fa18944aaeed4deb437522f04795ecd7bee79f0a6d7c6c6acd90dac9a935d5f252134cd4ca1e2e0c4386fdae67950f1234cda5472e61a32bf9f037c068fe81a955d1e56a92ad1a8f16e6a31bfc0f8b3cef96410a72b92a75b09a0071ff0c0e99dd322ab7d8e4a2a2c2122af6",
+ // Output={S'{}, T, C}
+ {{{"f2a93dfda00e7654585b911e90acdc3a825f88b497f329637bb612464d928e4182f1b360db55231f255e7265b1614d8ee895cde4e5f4768f749c051b25ac261e", "6a017e1dfd3fcee547b526b048204901", "d0c6f32d192ad998d5fa04b32a872f8e"}, {"ff9b9925190d45c46e5ac9eae38da326739b3180432cf0c36cd9346699bd022c4dcb3aa2811f8ab0a2a72cfdc9e13b817d0a20cc1b03f51b8133c6d36d2c4ffa", "2e666844518d40d4a1efee952db70f36", "c0ae73b766ba40692b47a08c07265205"}, {"7e710ab0fcc90e1919c4996abac395e440e26eadf2df429defc893bfa97eedc55afa0504c9cee635bb933013d5d1fd54ddd30d5dc8fedcc5b55368837e00c085", "43d445810df84f486bdbe4d69637633f", "df6876f95d2387d8f419d018a826ffed"}}, {"0e49b626343b62d9155ffca96b076d70", "d64d402225cfc1e55c277c5827d8fea52c683693568928ad817bdb161852f9bbb6b316c78c4ef24d3b2620bd584e128e709a399a6c320ab5943816d786a0b7d81f0023b522ebac91e4fc79d9f6b3f5dcc22f17f486ef93518e2f885327ebac19daaaa3998dfdcb5880d76a196a8bba54a0b9169427d1f83abf95fcc8f63dfeb03d50d083e11c38a55d2efbe2c607648a5caa3698393faaaf339ca1d4c48cab8184ec20d8dc4ad03793ff1806b802e932c33f00fa0253bc7da8fa560b19cac163bbf26e4507642fcc39b5df28b3941fccbd30e3e00b64f471a51d7555c3d1b6655b0a6d9d33b9cd0494163591675c50ebb5a867e849a9c6ee43a177d7fe9f6aa992c817b26316054b49894f973ae166fb20f2bfc50704f610e2cc61be08e1305fa58f15b716aaacb50c98e0dba34a300a1aa4296f7826f0ad740f36eef6d18205b1118227c285acef158b4093dd541eed76a3492240be48e89fa54cad77b020631413a8b562e655289f94191bc462b71ddf0b41a034ca1c291aa4feb0148207e2ea0d5409e801dcec151b0a5a220ac43b8be70c8c92d6eb4f9c6f44bf0fd3487c5d007ba8ddd8bbbca51fb3c679ffc0a493392039f32e7272f173e71d4a2a5f001f999dd9523c79ca3e32c99260b20f1e960a830bd7ed81d891c316c8851b3470c64b7fb15d7ebdb8d09399e74f"}},
+},
+};
diff --git a/src/test/include.am b/src/test/include.am
@@ -162,6 +162,7 @@ src_test_test_SOURCES += \
src/test/test_crypto.c \
src/test/test_crypto_ope.c \
src/test/test_crypto_rng.c \
+ src/test/test_crypto_cgo.c \
src/test/test_data.c \
src/test/test_dir.c \
src/test/test_dirauth_ports.c \
@@ -382,6 +383,7 @@ noinst_HEADERS+= \
src/test/example_extrainfo.inc \
src/test/failing_routerdescs.inc \
src/test/ed25519_vectors.inc \
+ src/test/cgo_vectors.inc \
src/test/test_descriptors.inc \
src/test/test_hs_descriptor.inc \
src/test/vote_descriptors.inc
diff --git a/src/test/test.c b/src/test/test.c
@@ -629,6 +629,7 @@ struct testgroup_t testgroups[] = {
#endif
{ "crypto/pem/", pem_tests },
{ "crypto/rng/", crypto_rng_tests },
+ { "crypto/cgo/", crypto_cgo_tests },
{ "dir/", dir_tests },
{ "dir/auth/ports/", dirauth_port_tests },
{ "dir/auth/process_descs/", process_descs_tests },
diff --git a/src/test/test.h b/src/test/test.h
@@ -122,6 +122,7 @@ extern struct testcase_t controller_tests[];
extern struct testcase_t crypto_ope_tests[];
extern struct testcase_t crypto_openssl_tests[];
extern struct testcase_t crypto_rng_tests[];
+extern struct testcase_t crypto_cgo_tests[];
extern struct testcase_t crypto_tests[];
extern struct testcase_t dirauth_port_tests[];
extern struct testcase_t dir_handle_get_tests[];
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
@@ -6,6 +6,8 @@
#include "orconfig.h"
#define CRYPTO_CURVE25519_PRIVATE
#define CRYPTO_RAND_PRIVATE
+#define USE_AES_RAW
+#define TOR_AES_PRIVATE
#include "core/or/or.h"
#include "test/test.h"
#include "lib/crypt_ops/aes.h"
@@ -21,6 +23,7 @@
#include "lib/crypt_ops/crypto_init.h"
#include "ed25519_vectors.inc"
#include "test/log_test_helpers.h"
+#include "ext/polyval/polyval.h"
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
@@ -3188,6 +3191,223 @@ test_crypto_failure_modes(void *arg)
;
}
+static void
+test_crypto_polyval(void *arg)
+{
+ (void)arg;
+ polyval_t pv;
+ uint8_t key[16];
+ uint8_t input[48];
+ uint8_t output[16];
+ uint8_t output2[16];
+ char *mem_op_hex_tmp=NULL;
+
+ // From RFC 8452
+ const char *key_hex = "25629347589242761d31f826ba4b757b";
+ const char *input_hex =
+ "4f4f95668c83dfb6401762bb2d01a262"
+ "d1a24ddd2721d006bbe45f20d3c9f362";
+ memset(input, 0, sizeof(input));
+ base16_decode((char*)key,sizeof(key), key_hex, strlen(key_hex));
+ base16_decode((char*)input,sizeof(input), input_hex, strlen(input_hex));
+
+ // Two blocks, directly.
+ polyval_init(&pv, key);
+ polyval_add_block(&pv, input);
+ polyval_add_block(&pv, input+16);
+ polyval_get_tag(&pv, output);
+ test_memeq_hex(output, "f7a3b47b846119fae5b7866cf5e5b77e");
+ // Two blocks, as a string.
+ polyval_reset(&pv);
+ polyval_add_zpad(&pv, input, 32);
+ polyval_get_tag(&pv, output);
+ test_memeq_hex(output, "f7a3b47b846119fae5b7866cf5e5b77e");
+
+ // Now make sure that zero-padding works.
+ input[32] = 77;
+ polyval_reset(&pv);
+ polyval_add_block(&pv, input);
+ polyval_add_block(&pv, input+16);
+ polyval_add_block(&pv, input+32);
+ polyval_get_tag(&pv, output);
+
+ polyval_reset(&pv);
+ polyval_add_zpad(&pv, input, 33);
+ polyval_get_tag(&pv, output2);
+ tt_mem_op(output, OP_EQ, output2, 16);
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_aes_raw_one(int keybits,
+ const char *key_hex,
+ const char *plaintext_hex,
+ const char *ciphertext_hex)
+{
+ aes_raw_t *enc = NULL;
+ aes_raw_t *dec = NULL;
+ uint8_t key[32]; // max key size.
+ uint8_t pt[16], ct[16], block[16];
+ tt_int_op(keybits, OP_EQ, strlen(key_hex) * 8 / 2);
+ base16_decode((char*)key, sizeof(key), key_hex, strlen(key_hex));
+ base16_decode((char*)pt, sizeof(pt), plaintext_hex, strlen(plaintext_hex));
+ base16_decode((char*)ct, sizeof(ct), ciphertext_hex, strlen(ciphertext_hex));
+
+ enc = aes_raw_new(key, keybits, true);
+ dec = aes_raw_new(key, keybits, false);
+ memcpy(block, pt, sizeof(pt));
+ aes_raw_encrypt(enc, block);
+ tt_mem_op(block, OP_EQ, ct, 16);
+ aes_raw_decrypt(dec, block);
+ tt_mem_op(block, OP_EQ, pt, 16);
+
+ done:
+ aes_raw_free(enc);
+ aes_raw_free(dec);
+}
+
+static void
+test_crypto_aes_raw(void *arg)
+{
+ (void)arg;
+
+#define T test_aes_raw_one
+
+ /* From https://csrc.nist.gov/CSRC/media/Projects/
+ Cryptographic-Algorithm-Validation-Program/documents/aes/AESAVS.pdf */
+ const char *z128 =
+ "00000000000000000000000000000000";
+ const char *z192 =
+ "00000000000000000000000000000000"
+ "0000000000000000";
+ const char *z256 =
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000";
+
+ T(128, z128,
+ "f34481ec3cc627bacd5dc3fb08f273e6",
+ "0336763e966d92595a567cc9ce537f5e");
+ T(192, z192,
+ "1b077a6af4b7f98229de786d7516b639",
+ "275cfc0413d8ccb70513c3859b1d0f72");
+ T(256, z256,
+ "014730f80ac625fe84f026c60bfd547d",
+ "5c9d844ed46f9885085e5d6a4f94c7d7");
+ T(128,
+ "10a58869d74be5a374cf867cfb473859", z128,
+ "6d251e6944b051e04eaa6fb4dbf78465");
+ T(192,
+ "e9f065d7c13573587f7875357dfbb16c53489f6a4bd0f7cd", z128,
+ "0956259c9cd5cfd0181cca53380cde06");
+ T(256,
+ "c47b0294dbbbee0fec4757f22ffeee35"
+ "87ca4730c3d33b691df38bab076bc558", z128,
+ "46f2fb342d6f0ab477476fc501242c5f");
+
+#undef T
+}
+
+static void
+test_crypto_aes_raw_ctr_equiv(void *arg)
+{
+ (void) arg;
+ size_t buflen = 65536;
+ uint8_t *buf = tor_malloc_zero(buflen);
+ aes_cnt_cipher_t *c = NULL;
+ aes_raw_t *c_raw = NULL;
+
+ const uint8_t iv[16];
+ const uint8_t key[16];
+
+ // Simple case, IV with zero offset.
+ for (int i = 0; i < 32; ++i) {
+ crypto_rand((char*)iv, sizeof(iv));
+ crypto_rand((char*)key, sizeof(key));
+ c = aes_new_cipher(key, iv, 128);
+ c_raw = aes_raw_new(key, 128, true);
+
+ aes_crypt_inplace(c, (char*)buf, buflen);
+ aes_raw_counter_xor(c_raw, iv, 0, buf, buflen);
+ tt_assert(fast_mem_is_zero((char*)buf, buflen));
+
+ aes_cipher_free(c);
+ aes_raw_free(c_raw);
+ }
+ // Trickier case, IV with offset == 31.
+ for (int i = 0; i < 32; ++i) {
+ crypto_rand((char*)iv, sizeof(iv));
+ crypto_rand((char*)key, sizeof(key));
+ c = aes_new_cipher(key, iv, 128);
+ c_raw = aes_raw_new(key, 128, true);
+
+ aes_crypt_inplace(c, (char*)buf, buflen);
+ size_t off = 31*16;
+ aes_raw_counter_xor(c_raw, iv, 31, buf + off, buflen - off);
+ tt_assert(fast_mem_is_zero((char*)buf + off, buflen - off));
+
+ aes_cipher_free(c);
+ aes_raw_free(c_raw);
+ }
+
+ done:
+ aes_cipher_free(c);
+ aes_raw_free(c_raw);
+ tor_free(buf);
+}
+
+/* Make sure that our IV addition code is correct.
+ *
+ * We test this function separately to make sure we handle corner cases well;
+ * the corner cases are rare enough that we shouldn't expect to see them in
+ * randomized testing.
+ */
+static void
+test_crypto_aes_cnt_iv_manip(void *arg)
+{
+ (void)arg;
+ uint8_t buf[16];
+ uint8_t expect[16];
+ int n;
+#define T(pre, off, post) STMT_BEGIN { \
+ n = base16_decode((char*)buf, sizeof(buf), \
+ (pre), strlen(pre)); \
+ tt_int_op(n, OP_EQ, sizeof(buf)); \
+ n = base16_decode((char*)expect, sizeof(expect), \
+ (post), strlen(post)); \
+ tt_int_op(n, OP_EQ, sizeof(expect)); \
+ aes_ctr_add_iv_offset(buf, (off)); \
+ tt_mem_op(buf, OP_EQ, expect, 16); \
+ } STMT_END
+
+ T("00000000000000000000000000000000", 0x4032,
+ "00000000000000000000000000004032");
+ T("0000000000000000000000000000ffff", 0x4032,
+ "00000000000000000000000000014031");
+ // We focus on "31" here because that's what CGO uses.
+ T("000000000000000000000000ffffffe0", 31,
+ "000000000000000000000000ffffffff");
+ T("000000000000000000000000ffffffe1", 31,
+ "00000000000000000000000100000000");
+ T("0000000100000000ffffffffffffffe0", 31,
+ "0000000100000000ffffffffffffffff");
+ T("0000000100000000ffffffffffffffe1", 31,
+ "00000001000000010000000000000000");
+ T("0000000ffffffffffffffffffffffff0", 31,
+ "0000001000000000000000000000000f");
+ T("ffffffffffffffffffffffffffffffe0", 31,
+ "ffffffffffffffffffffffffffffffff");
+ T("ffffffffffffffffffffffffffffffe1", 31,
+ "00000000000000000000000000000000");
+ T("ffffffffffffffffffffffffffffffe8", 31,
+ "00000000000000000000000000000007");
+
+#undef T
+ done:
+ ;
+}
+
#ifndef COCCI
#define CRYPTO_LEGACY(name) \
{ #name, test_crypto_ ## name , 0, NULL, NULL }
@@ -3255,5 +3475,9 @@ struct testcase_t crypto_tests[] = {
{ "blake2b", test_crypto_blake2b, 0, NULL, NULL },
{ "hashx", test_crypto_hashx, 0, NULL, NULL },
{ "failure_modes", test_crypto_failure_modes, TT_FORK, NULL, NULL },
+ { "polyval", test_crypto_polyval, 0, NULL, NULL },
+ { "aes_raw", test_crypto_aes_raw, 0, NULL, NULL },
+ { "aes_raw_ctr_equiv", test_crypto_aes_raw_ctr_equiv, 0, NULL, NULL },
+ { "aes_cnt_iv_manip", test_crypto_aes_cnt_iv_manip, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_crypto_cgo.c b/src/test/test_crypto_cgo.c
@@ -0,0 +1,642 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2021, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define RELAY_CRYPTO_CGO_PRIVATE
+#define USE_AES_RAW
+
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "test/test.h"
+#include "lib/cc/compat_compiler.h"
+#include "lib/crypt_ops/aes.h"
+#include "ext/polyval/polyval.h"
+#include "core/crypto/relay_crypto_cgo.h"
+#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/crypt_ops/crypto_util.h"
+#include "core/or/cell_st.h"
+
+#include "test/cgo_vectors.inc"
+
+static const int AESBITS[] = { 128, 192, 256 };
+
+static void
+test_crypto_cgo_et_roundtrip(void *arg)
+{
+ (void)arg;
+ uint8_t key[32 + 16]; // max
+ uint8_t tweak_h[16];
+ uint8_t tweak_x_r[493];
+ uint8_t block[16], block_orig[16];
+ cgo_et_t et1, et2;
+ memset(&et1, 0, sizeof(et1));
+ memset(&et2, 0, sizeof(et2));
+
+ et_tweak_t tweak = {
+ .uiv = {
+ .h = tweak_h,
+ .cmd = 7,
+ },
+ .x_r = tweak_x_r,
+ };
+
+ for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) {
+ const int aesbits = AESBITS[bi];
+
+ for (int i = 0; i < 16; ++i) {
+ crypto_rand((char*)key, sizeof(key));
+ crypto_rand((char*)tweak_h, sizeof(tweak_h));
+ crypto_rand((char*)tweak_x_r, sizeof(tweak_x_r));
+ crypto_rand((char*)block_orig, sizeof(block_orig));
+ memcpy(block, block_orig, 16);
+ cgo_et_init(&et1, aesbits, true, key);
+ cgo_et_init(&et2, aesbits, false, key);
+
+ // encrypt-then-decrypt should round-trip.
+ cgo_et_encrypt(&et1, tweak, block);
+ tt_mem_op(block, OP_NE, block_orig, 16);
+ cgo_et_decrypt(&et2, tweak, block);
+ tt_mem_op(block, OP_EQ, block_orig, 16);
+
+ // decrypt-then-encrypt should round-trip.
+ cgo_et_decrypt(&et2, tweak, block);
+ tt_mem_op(block, OP_NE, block_orig, 16);
+ cgo_et_encrypt(&et1, tweak, block);
+ tt_mem_op(block, OP_EQ, block_orig, 16);
+
+ cgo_et_clear(&et1);
+ cgo_et_clear(&et2);
+ }
+ }
+ done:
+ cgo_et_clear(&et1);
+ cgo_et_clear(&et2);
+}
+
+static void
+test_crypto_cgo_uiv_roundtrip(void *arg)
+{
+ (void)arg;
+ uint8_t key[64 + 32]; // max
+ uint8_t tweak_h[16];
+ uint8_t cell[509], cell_orig[509];
+ cgo_uiv_t uiv1, uiv2;
+ memset(&uiv1, 0, sizeof(uiv1));
+ memset(&uiv2, 0, sizeof(uiv2));
+
+ uiv_tweak_t tweak = {
+ .h = tweak_h,
+ .cmd = 4,
+ };
+
+ for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) {
+ const int aesbits = AESBITS[bi];
+
+ for (int i = 0; i < 16; ++i) {
+ crypto_rand((char*)key, sizeof(key));
+ crypto_rand((char*)tweak_h, sizeof(tweak_h));
+ crypto_rand((char*)cell_orig, sizeof(cell_orig));
+ memcpy(cell, cell_orig, sizeof(cell_orig));
+
+ cgo_uiv_init(&uiv1, aesbits, true, key);
+ cgo_uiv_init(&uiv2, aesbits, false, key);
+
+ // encrypt-then-decrypt should round-trip.
+ cgo_uiv_encrypt(&uiv1, tweak, cell);
+ tt_mem_op(cell, OP_NE, cell_orig, sizeof(cell));
+ cgo_uiv_decrypt(&uiv2, tweak, cell);
+ tt_mem_op(cell, OP_EQ, cell_orig, sizeof(cell));
+
+ // decrypt-then-encrypt should round-trip.
+ cgo_uiv_decrypt(&uiv2, tweak, cell);
+ tt_mem_op(cell, OP_NE, cell_orig, sizeof(cell));
+ cgo_uiv_encrypt(&uiv1, tweak, cell);
+ tt_mem_op(cell, OP_EQ, cell_orig, sizeof(cell));
+
+ cgo_uiv_clear(&uiv1);
+ cgo_uiv_clear(&uiv2);
+ }
+ }
+ done:
+ cgo_uiv_clear(&uiv1);
+ cgo_uiv_clear(&uiv2);
+}
+
+#define UNHEX(out,inp) STMT_BEGIN { \
+ size_t inplen = strlen(inp); \
+ tt_int_op(sizeof(out), OP_EQ, inplen / 2); \
+ int r = base16_decode((char*)(out), sizeof(out), inp, inplen); \
+ tt_int_op(r, OP_EQ, sizeof(out)); \
+ } STMT_END
+
+#define UNHEX2(out,inp1,inp2) STMT_BEGIN { \
+ tor_free(unhex_tmp); \
+ tor_asprintf(&unhex_tmp, "%s%s", inp1, inp2); \
+ UNHEX(out, unhex_tmp); \
+ } STMT_END
+
+static void
+test_crypto_cgo_et_testvec(void *arg)
+{
+ (void)arg;
+ cgo_et_t et;
+ memset(&et, 0, sizeof(et));
+
+ for (int i = 0; i < (int)ARRAY_LENGTH(ET_TESTVECS); ++i) {
+ const struct et_testvec *tv = &ET_TESTVECS[i];
+ uint8_t keys[32];
+ uint8_t tweaks[16 + 1 + 493];
+ uint8_t block[16], expect[16];
+ UNHEX(keys, tv->keys);
+ UNHEX(tweaks, tv->tweaks);
+ UNHEX(block, tv->block);
+ UNHEX(expect, tv->expect);
+
+ et_tweak_t tweak = {
+ .uiv = {
+ .h = tweaks,
+ .cmd = tweaks[16],
+ },
+ .x_r = tweaks + 17,
+ };
+
+ cgo_et_init(&et, 128, tv->encrypt, keys);
+ if (tv->encrypt) {
+ cgo_et_encrypt(&et, tweak, block);
+ } else {
+ cgo_et_decrypt(&et, tweak, block);
+ }
+ cgo_et_clear(&et);
+
+ tt_mem_op(block, OP_EQ, expect, 16);
+ }
+
+ done:
+ cgo_et_clear(&et);
+}
+
+static void
+test_crypto_cgo_prf_testvec(void *arg)
+{
+ (void)arg;
+ cgo_prf_t prf;
+ memset(&prf, 0, sizeof(prf));
+
+ for (int i = 0; i < (int)ARRAY_LENGTH(PRF_TESTVECS); ++i) {
+ const struct prf_testvec *tv = &PRF_TESTVECS[i];
+ uint8_t keys[32];
+ uint8_t input[16];
+ uint8_t expect_t0[493];
+ uint8_t expect_t1[80];
+ uint8_t output[493]; // max
+ UNHEX(keys, tv->keys);
+ UNHEX(input, tv->input);
+
+ cgo_prf_init(&prf, 128, keys);
+ if (tv->t == 0) {
+ UNHEX(expect_t0, tv->expect);
+ memset(output, 0, sizeof(output));
+ cgo_prf_xor_t0(&prf, input, output);
+ tt_mem_op(output, OP_EQ, expect_t0, PRF_T0_DATA_LEN);
+ } else {
+ tt_int_op(tv->t, OP_EQ, 1);
+ UNHEX(expect_t1, tv->expect);
+ cgo_prf_gen_t1(&prf, input, output, sizeof(expect_t1));
+ tt_mem_op(output, OP_EQ, expect_t1, sizeof(expect_t1));
+ }
+ cgo_prf_clear(&prf);
+ }
+ done:
+ cgo_prf_clear(&prf);
+}
+
+static void
+test_crypto_cgo_uiv_testvec(void *arg)
+{
+ (void)arg;
+ cgo_uiv_t uiv;
+ memset(&uiv, 0, sizeof(uiv));
+
+ for (int i = 0; i < (int)ARRAY_LENGTH(UIV_TESTVECS); ++i) {
+ const struct uiv_testvec *tv = &UIV_TESTVECS[i];
+ uint8_t keys[64];
+ uint8_t tweaks[17];
+ uint8_t x_l[16], x_r[493];
+ uint8_t y_l[16], y_r[493];
+ uint8_t cell[509];
+ UNHEX(keys, tv->keys);
+ UNHEX(tweaks, tv->tweaks);
+ UNHEX(x_l, tv->x_l);
+ UNHEX(x_r, tv->x_r);
+ UNHEX(y_l, tv->y.y_l);
+ UNHEX(y_r, tv->y.y_r);
+
+ uiv_tweak_t tweak = {
+ .h = tweaks,
+ .cmd = tweaks[16]
+ };
+ memcpy(cell, x_l, 16);
+ memcpy(cell+16, x_r, 493);
+
+ cgo_uiv_init(&uiv, 128, tv->encrypt, keys);
+ if (tv->encrypt) {
+ cgo_uiv_encrypt(&uiv, tweak, cell);
+ } else {
+ cgo_uiv_decrypt(&uiv, tweak, cell);
+ }
+ cgo_uiv_clear(&uiv);
+
+ tt_mem_op(cell, OP_EQ, y_l, 16);
+ tt_mem_op(cell+16, OP_EQ, y_r, 493);
+ }
+
+ done:
+ cgo_uiv_clear(&uiv);
+}
+
+static void
+test_crypto_cgo_uiv_update_testvec(void *arg)
+{
+ (void)arg;
+ cgo_uiv_t uiv;
+ cgo_uiv_t uiv2;
+ memset(&uiv, 0, sizeof(uiv));
+ memset(&uiv2, 0, sizeof(uiv2));
+
+ uint8_t tw[16];
+ memset(tw, 42, sizeof(tw));
+ uiv_tweak_t tweak = {
+ .h = tw,
+ .cmd = 42
+ };
+
+ for (int i = 0; i < (int)ARRAY_LENGTH(UIV_UPDATE_TESTVECS); ++i) {
+ const struct uiv_update_testvec *tv = &UIV_UPDATE_TESTVECS[i];
+ uint8_t keys[64];
+ uint8_t nonce[16];
+ uint8_t new_keys[64];
+ uint8_t new_nonce[16];
+ UNHEX(keys, tv->keys);
+ UNHEX(nonce, tv->nonce);
+ UNHEX(new_keys, tv->output.new_keys);
+ UNHEX(new_nonce, tv->output.new_nonce);
+
+ cgo_uiv_init(&uiv, 128, true, keys);
+ cgo_uiv_update(&uiv, 128, true, nonce);
+ // Make sure that the recorded keys are what we expect.
+ tt_mem_op(uiv.uiv_keys_, OP_EQ, new_keys, 64);
+ tt_mem_op(nonce, OP_EQ, new_nonce, 16);
+
+ // Construct a new UIV from these keys and make sure it acts like this one.
+ uint8_t cell[509], cell2[509];
+ crypto_rand((char*)cell, sizeof(cell));
+ memcpy(cell2, cell, 509);
+ cgo_uiv_init(&uiv2, 128, true, uiv.uiv_keys_);
+ cgo_uiv_encrypt(&uiv, tweak, cell);
+ cgo_uiv_encrypt(&uiv2, tweak, cell2);
+ tt_mem_op(cell, OP_EQ, cell2, 509);
+
+ cgo_uiv_clear(&uiv);
+ cgo_uiv_clear(&uiv2);
+ }
+ done:
+ cgo_uiv_clear(&uiv);
+ cgo_uiv_clear(&uiv2);
+}
+
+static void
+test_crypto_cgo_fwd(void *arg)
+{
+ (void)arg;
+
+ #define N_HOPS 3
+ uint8_t key_material[N_HOPS][112]; // max.
+ cgo_crypt_t *client[N_HOPS];
+ cgo_crypt_t *relays[N_HOPS];
+
+ memset(client, 0, sizeof(client));
+ memset(relays, 0, sizeof(relays));
+
+ for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) {
+ const int aesbits = AESBITS[bi];
+
+ size_t klen = cgo_key_material_len(aesbits);
+ tt_uint_op(klen, OP_LE, sizeof(key_material[0]));
+ crypto_rand((char*)&key_material, sizeof(key_material));
+ for (int i = 0; i < N_HOPS; ++i) {
+ client[i] = cgo_crypt_new(CGO_MODE_CLIENT_FORWARD,
+ aesbits, key_material[i], klen);
+ relays[i] = cgo_crypt_new(CGO_MODE_RELAY_FORWARD,
+ aesbits, key_material[i], klen);
+ }
+ for (int trial = 0; trial < 64; ++trial) {
+ int target_hop = crypto_rand_int(3);
+ cell_t cell, cell_orig;
+ uint8_t tag_client[CGO_TAG_LEN];
+ const uint8_t *tagp = NULL;
+
+ memset(&cell, 0, sizeof(cell));
+ if (crypto_rand_int(2) == 0) {
+ cell.command = CELL_RELAY;
+ } else {
+ cell.command = CELL_RELAY_EARLY;
+ }
+ crypto_rand((char*) cell.payload+CGO_TAG_LEN,
+ sizeof(cell.payload)-CGO_TAG_LEN);
+ memcpy(&cell_orig, &cell, sizeof(cell));
+
+ // First the client encrypts the cell...
+ cgo_crypt_client_originate(client[target_hop], &cell, &tagp);
+ tt_assert(tagp);
+ memcpy(tag_client, tagp, CGO_TAG_LEN);
+ for (int i = target_hop - 1; i >= 0; --i) {
+ cgo_crypt_client_forward(client[i], &cell);
+ }
+
+ // Now the relays handle the cell...
+ bool cell_recognized = false;
+ for (int i = 0; i < N_HOPS; ++i) {
+ tagp = NULL;
+ cgo_crypt_relay_forward(relays[i], &cell, &tagp);
+ if (tagp) {
+ tt_int_op(i, OP_EQ, target_hop);
+ tt_mem_op(tagp, OP_EQ, tag_client, CGO_TAG_LEN);
+ cell_recognized = true;
+ break;
+ }
+ }
+ tt_assert(cell_recognized);
+ tt_int_op(cell.command, OP_EQ, cell_orig.command);
+ tt_mem_op(cell.payload + CGO_TAG_LEN, OP_EQ,
+ cell_orig.payload + CGO_TAG_LEN,
+ sizeof(cell.payload) - CGO_TAG_LEN);
+ }
+ for (int i = 0; i < N_HOPS; ++i) {
+ cgo_crypt_free(client[i]);
+ cgo_crypt_free(relays[i]);
+ }
+ }
+
+ done:
+ for (int i = 0; i < N_HOPS; ++i) {
+ cgo_crypt_free(client[i]);
+ cgo_crypt_free(relays[i]);
+ }
+#undef N_HOPS
+}
+
+static void
+test_crypto_cgo_rev(void *arg)
+{
+ (void)arg;
+
+ #define N_HOPS 3
+ uint8_t key_material[N_HOPS][112]; // max.
+ cgo_crypt_t *client[N_HOPS];
+ cgo_crypt_t *relays[N_HOPS];
+
+ memset(client, 0, sizeof(client));
+ memset(relays, 0, sizeof(relays));
+
+ for (int bi = 0; bi < (int) ARRAY_LENGTH(AESBITS); ++bi) {
+ const int aesbits = AESBITS[bi];
+
+ size_t klen = cgo_key_material_len(aesbits);
+ tt_uint_op(klen, OP_LE, sizeof(key_material[0]));
+ crypto_rand((char*)&key_material, sizeof(key_material));
+ for (int i = 0; i < N_HOPS; ++i) {
+ client[i] = cgo_crypt_new(CGO_MODE_CLIENT_BACKWARD,
+ aesbits, key_material[i], klen);
+ relays[i] = cgo_crypt_new(CGO_MODE_RELAY_BACKWARD,
+ aesbits, key_material[i], klen);
+ }
+ for (int trial = 0; trial < 64; ++trial) {
+ int origin_hop = crypto_rand_int(3);
+ cell_t cell, cell_orig;
+ uint8_t tag_relay[CGO_TAG_LEN];
+ const uint8_t *tagp = NULL;
+
+ memset(&cell, 0, sizeof(cell));
+ cell.command = CELL_RELAY;
+ crypto_rand((char*) cell.payload+CGO_TAG_LEN,
+ sizeof(cell.payload)-CGO_TAG_LEN);
+ memcpy(&cell_orig, &cell, sizeof(cell));
+
+ // First the specified relay encrypts the cell...
+ cgo_crypt_relay_originate(relays[origin_hop], &cell, &tagp);
+ tt_assert(tagp);
+ memcpy(tag_relay, tagp, CGO_TAG_LEN);
+ for (int i = origin_hop - 1; i >= 0; --i) {
+ cgo_crypt_relay_backward(relays[i], &cell);
+ }
+
+ // Now the client handles the cell.
+ bool cell_recognized = false;
+ for (int i = 0; i < N_HOPS; ++i) {
+ tagp = NULL;
+ cgo_crypt_client_backward(client[i], &cell, &tagp);
+ if (tagp) {
+ tt_int_op(i, OP_EQ, origin_hop);
+ tt_mem_op(tagp, OP_EQ, tag_relay, CGO_TAG_LEN);
+ cell_recognized = true;
+ break;
+ }
+ }
+ tt_assert(cell_recognized);
+ tt_int_op(cell.command, OP_EQ, cell_orig.command);
+ tt_mem_op(cell.payload + CGO_TAG_LEN, OP_EQ,
+ cell_orig.payload + CGO_TAG_LEN,
+ sizeof(cell.payload) - CGO_TAG_LEN);
+ }
+ for (int i = 0; i < N_HOPS; ++i) {
+ cgo_crypt_free(client[i]);
+ cgo_crypt_free(relays[i]);
+ }
+ }
+
+ done:
+ for (int i = 0; i < N_HOPS; ++i) {
+ cgo_crypt_free(client[i]);
+ cgo_crypt_free(relays[i]);
+ }
+#undef N_HOPS
+}
+
+static void
+test_crypto_cgo_relay_testvec(void *arg)
+{
+ (void)arg;
+ char *unhex_tmp = NULL;
+ cgo_crypt_t *cgo = NULL;
+ for (int i = 0; i < (int)ARRAY_LENGTH(CGO_RELAY_TESTVECS); ++i) {
+ const struct cgo_relay_testvec *tv = &CGO_RELAY_TESTVECS[i];
+ const int aesbits = 128;
+ uint8_t keys[80], expect_keys[80], expect_tprime[CGO_TAG_LEN], cmd[1];
+ cell_t cell;
+ cell_t expect_cell;
+ tt_int_op(sizeof(keys), OP_EQ, cgo_key_material_len(aesbits));
+ UNHEX2(keys, tv->state_in.keys, tv->state_in.nonce);
+ cgo_mode_t mode =
+ tv->inbound ? CGO_MODE_RELAY_BACKWARD : CGO_MODE_RELAY_FORWARD;
+ cgo = cgo_crypt_new(mode, aesbits, keys, sizeof(keys));
+ tt_assert(cgo);
+ UNHEX(cgo->tprime, tv->state_in.tprime);
+ memset(&cell, 0, sizeof(cell));
+ UNHEX(cmd, tv->cmd);
+ cell.command = cmd[0];
+ UNHEX2(cell.payload, tv->tag, tv->msg);
+
+ memset(&expect_cell, 0, sizeof(expect_cell));
+ expect_cell.command = cell.command;
+ UNHEX2(expect_cell.payload,
+ tv->output.result.t_out, tv->output.result.msg_out);
+ UNHEX2(expect_keys,
+ tv->output.state.keys, tv->output.state.nonce);
+ UNHEX(expect_tprime, tv->output.state.tprime);
+
+ if (tv->inbound) {
+ cgo_crypt_relay_backward(cgo, &cell);
+ } else {
+ const uint8_t *tagp = NULL;
+ cgo_crypt_relay_forward(cgo, &cell, &tagp);
+ tt_ptr_op(tagp, OP_EQ, NULL);
+ }
+
+ tt_mem_op(cell.payload, OP_EQ, expect_cell.payload, sizeof(cell.payload));
+ tt_mem_op(cgo->uiv.uiv_keys_, OP_EQ, expect_keys, 64);
+ tt_mem_op(cgo->nonce, OP_EQ, expect_keys + 64, 16);
+ tt_mem_op(cgo->tprime, OP_EQ, expect_tprime, 16);
+
+ cgo_crypt_free(cgo);
+ }
+ done:
+ tor_free(unhex_tmp);
+ cgo_crypt_free(cgo);
+}
+
+static void
+test_crypto_cgo_relay_originate_testvec(void *arg)
+{
+ (void)arg;
+ char *unhex_tmp = NULL;
+ cgo_crypt_t *cgo = NULL;
+ for (int i = 0; i < (int)ARRAY_LENGTH(CGO_RELAY_ORIGINATE_TESTVECS); ++i) {
+ const struct cgo_relay_originate_testvec *tv =
+ &CGO_RELAY_ORIGINATE_TESTVECS[i];
+ const int aesbits = 128;
+ uint8_t keys[80], expect_keys[80], expect_tprime[CGO_TAG_LEN], cmd[1];
+ cell_t cell;
+ cell_t expect_cell;
+ tt_int_op(sizeof(keys), OP_EQ, cgo_key_material_len(aesbits));
+ UNHEX2(keys, tv->state_in.keys, tv->state_in.nonce);
+ cgo = cgo_crypt_new(CGO_MODE_RELAY_BACKWARD, aesbits, keys, sizeof(keys));
+ tt_assert(cgo);
+ UNHEX(cgo->tprime, tv->state_in.tprime);
+ memset(&cell, 0, sizeof(cell));
+ UNHEX(cmd, tv->cmd);
+ cell.command = cmd[0];
+ UNHEX2(cell.payload, "00000000000000000000000000000000", tv->msg);
+
+ memset(&expect_cell, 0, sizeof(expect_cell));
+ expect_cell.command = cell.command;
+ UNHEX2(expect_cell.payload,
+ tv->output.result.t_out, tv->output.result.msg_out);
+ UNHEX2(expect_keys,
+ tv->output.state.keys, tv->output.state.nonce);
+ UNHEX(expect_tprime, tv->output.state.tprime);
+
+ const uint8_t *tagp = NULL;
+ cgo_crypt_relay_originate(cgo, &cell, &tagp);
+ tt_ptr_op(tagp, OP_NE, NULL);
+
+ tt_mem_op(cell.payload, OP_EQ, expect_cell.payload, sizeof(cell.payload));
+ tt_mem_op(cgo->uiv.uiv_keys_, OP_EQ, expect_keys, 64);
+ tt_mem_op(cgo->nonce, OP_EQ, expect_keys + 64, 16);
+ tt_mem_op(cgo->tprime, OP_EQ, expect_tprime, 16);
+
+ cgo_crypt_free(cgo);
+ }
+ done:
+ tor_free(unhex_tmp);
+ cgo_crypt_free(cgo);
+}
+
+static void
+test_crypto_cgo_client_originate_testvec(void *arg)
+{
+ (void) arg;
+ char *unhex_tmp = NULL;
+ cgo_crypt_t *cgo[3] = { NULL, NULL, NULL };
+ for (int tv_i = 0; tv_i < (int)ARRAY_LENGTH(CGO_CLIENT_ORIGINATE_TESTVECS);
+ ++tv_i) {
+ const struct cgo_client_originate_testvec *tv =
+ &CGO_CLIENT_ORIGINATE_TESTVECS[tv_i];
+ const int aesbits = 128;
+ uint8_t keys[80], expect_keys[80], expect_tprime[CGO_TAG_LEN], cmd[1];
+ cell_t cell;
+ cell_t expect_cell;
+ for (int i = 0; i < 3; ++i) {
+ tt_int_op(sizeof(keys), OP_EQ, cgo_key_material_len(aesbits));
+ UNHEX2(keys, tv->state_in[i].keys, tv->state_in[i].nonce);
+ cgo[i] = cgo_crypt_new(CGO_MODE_CLIENT_FORWARD,
+ aesbits, keys, sizeof(keys));
+ tt_assert(cgo[i]);
+ UNHEX(cgo[i]->tprime, tv->state_in[i].tprime);
+ }
+
+ memset(&cell, 0, sizeof(cell));
+ UNHEX(cmd, tv->cmd);
+ cell.command = cmd[0];
+ UNHEX2(cell.payload, "00000000000000000000000000000000", tv->msg);
+
+ memset(&expect_cell, 0, sizeof(expect_cell));
+ expect_cell.command = cell.command;
+ UNHEX2(expect_cell.payload,
+ tv->output.result.t_out, tv->output.result.msg_out);
+
+ tt_int_op(tv->target_hop, OP_GE, 1); // Hop is 0-indexed.
+ int target_hop = tv->target_hop - 1;
+ const uint8_t *tagp = NULL;
+ cgo_crypt_client_originate(cgo[target_hop], &cell, &tagp);
+ tt_ptr_op(tagp, OP_NE, NULL);
+ for (int i = target_hop - 1; i >= 0; --i) {
+ cgo_crypt_client_forward(cgo[i], &cell);
+ }
+ tt_mem_op(cell.payload, OP_EQ, expect_cell.payload, sizeof(cell.payload));
+
+ for (int i = 0; i < 3; ++i) {
+ UNHEX2(expect_keys,
+ tv->output.state[i].keys, tv->output.state[i].nonce);
+ UNHEX(expect_tprime, tv->output.state[i].tprime);
+
+ tt_mem_op(cgo[i]->uiv.uiv_keys_, OP_EQ, expect_keys, 64);
+ tt_mem_op(cgo[i]->nonce, OP_EQ, expect_keys + 64, 16);
+ tt_mem_op(cgo[i]->tprime, OP_EQ, expect_tprime, 16);
+ }
+
+ for (int i = 0; i < 3; ++i)
+ cgo_crypt_free(cgo[i]);
+ }
+ done:
+ tor_free(unhex_tmp);
+ for (int i = 0; i < 3; ++i)
+ cgo_crypt_free(cgo[i]);
+}
+
+struct testcase_t crypto_cgo_tests[] = {
+ { "et_roundtrip", test_crypto_cgo_et_roundtrip, 0, NULL, NULL },
+ { "et_testvec", test_crypto_cgo_et_testvec, 0, NULL, NULL },
+ { "prf_testvec", test_crypto_cgo_prf_testvec, 0, NULL, NULL },
+ { "uiv_roundtrip", test_crypto_cgo_uiv_roundtrip, 0, NULL, NULL },
+ { "uiv_testvec", test_crypto_cgo_uiv_testvec, 0, NULL, NULL },
+ { "uiv_update_testvec", test_crypto_cgo_uiv_update_testvec, 0, NULL, NULL },
+ { "cgo_fwd", test_crypto_cgo_fwd, 0, NULL, NULL, },
+ { "cgo_rev", test_crypto_cgo_rev, 0, NULL, NULL, },
+ { "cgo_relay_testvec", test_crypto_cgo_relay_testvec, 0, NULL, NULL },
+ { "cgo_relay_originate_testvec", test_crypto_cgo_relay_originate_testvec,
+ 0, NULL, NULL },
+ { "cgo_client_originate_testvec", test_crypto_cgo_client_originate_testvec,
+ 0, NULL, NULL },
+ END_OF_TESTCASES
+};