├── python ├── MANIFEST.in ├── .gitignore ├── examples │ ├── 3hashtdh.py │ ├── tpdkg_test.py │ └── toprf-update.py ├── setup.py ├── README.md └── pyoprf │ └── noisexk.py ├── zephyr ├── module.yml ├── Kconfig └── CMakeLists.txt ├── src ├── noise_xk │ ├── .gitignore │ ├── include │ │ ├── karmel │ │ │ ├── minimal │ │ │ │ ├── Makefile.include │ │ │ │ ├── libkrmllib.def │ │ │ │ ├── LowStar_Endianness.h │ │ │ │ ├── Makefile.basic │ │ │ │ ├── fstar_uint128_struct_endianness.h │ │ │ │ ├── FStar_UInt128.h │ │ │ │ ├── fstar_uint128_gcc64.h │ │ │ │ ├── FStar_UInt_8_16_32_64.h │ │ │ │ └── FStar_UInt128_Verified.h │ │ │ ├── krml │ │ │ │ ├── internal │ │ │ │ │ ├── wasmsupport.h │ │ │ │ │ ├── builtin.h │ │ │ │ │ ├── callconv.h │ │ │ │ │ ├── compat.h │ │ │ │ │ ├── debug.h │ │ │ │ │ └── types.h │ │ │ │ ├── c_endianness.h │ │ │ │ ├── fstar_int.h │ │ │ │ └── lowstar_endianness.h │ │ │ └── README.txt │ │ ├── noise_private.h │ │ └── Noise_XK.h │ ├── example │ │ ├── authorized_keys │ │ └── makefile │ ├── README.md │ └── makefile ├── tests │ ├── fuzz-tp-dkg │ │ ├── .gitignore │ │ ├── README.txt │ │ ├── tpdkg_msg_parser.py │ │ ├── msg0.c │ │ ├── peer-start.c │ │ └── makefile │ ├── fuzz-toprf-update │ │ ├── .gitignore │ │ ├── README.txt │ │ ├── toprf_update_msg_parser.py │ │ └── makefile │ ├── README.md │ ├── .gitignore │ ├── test.c │ ├── toprf.c │ ├── testvecs2h.py │ ├── dkg.c │ ├── makefile │ ├── allocations.c │ └── mpmult.c ├── utils.h ├── utils.c ├── aux_ │ ├── crypto_kdf_hkdf_sha256.h │ └── kdf_hkdf_sha256.c ├── dkg-vss.h ├── dkg-vss.c ├── oprf.h ├── mpmult.h ├── makefile └── toprf.h ├── .gitignore ├── liboprf.pc ├── .github └── workflows │ ├── python-app.yml │ └── codeql-analysis.yml ├── README.md ├── misc └── attack.c └── LICENSE /python/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include *.py 3 | -------------------------------------------------------------------------------- /zephyr/module.yml: -------------------------------------------------------------------------------- 1 | build: 2 | cmake: zephyr 3 | kconfig: zephyr/Kconfig 4 | -------------------------------------------------------------------------------- /python/.gitignore: -------------------------------------------------------------------------------- 1 | pyoprf.egg-info 2 | pyoprf/__pycache__ 3 | build 4 | dist 5 | -------------------------------------------------------------------------------- /src/noise_xk/.gitignore: -------------------------------------------------------------------------------- 1 | liboprf-noiseXK.a 2 | liboprf-noiseXK.so 3 | liboprf-noiseXK.so.0 4 | xk-ex 5 | *.o 6 | -------------------------------------------------------------------------------- /src/tests/fuzz-tp-dkg/.gitignore: -------------------------------------------------------------------------------- 1 | fuzz-bin 2 | fuzz-dump 3 | in 4 | out 5 | fuzz-complog 6 | fuzz-bin-asan 7 | fuzz-bin-asan-peer 8 | fuzz-bin-peer 9 | fuzz-complog-peer 10 | fuzz-dump-peer 11 | -------------------------------------------------------------------------------- /src/tests/fuzz-toprf-update/.gitignore: -------------------------------------------------------------------------------- 1 | fuzz-bin 2 | fuzz-dump 3 | in 4 | out 5 | fuzz-complog 6 | fuzz-bin-asan 7 | fuzz-bin-asan-peer 8 | fuzz-bin-peer 9 | fuzz-complog-peer 10 | fuzz-dump-peer 11 | -------------------------------------------------------------------------------- /src/tests/README.md: -------------------------------------------------------------------------------- 1 | # IRTF/CFRG testvectors 2 | 3 | these tests verify the test vectors from the IRTF/CFRG as per: 4 | 5 | https://github.com/cfrg/draft-irtf-cfrg-voprf/blob/main/draft-irtf-cfrg-voprf.md#oprf-mode 6 | -------------------------------------------------------------------------------- /zephyr/Kconfig: -------------------------------------------------------------------------------- 1 | # Kconfig - liboprf configuration options 2 | 3 | menuconfig LIBOPRF 4 | bool "liboprf OPRF library" 5 | depends on LIBSODIUM 6 | help 7 | This option enables the liboprf cryptographic library. 8 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/minimal/Makefile.include: -------------------------------------------------------------------------------- 1 | USER_TARGET=libkrmllib.a 2 | USER_CFLAGS= 3 | USER_C_FILES=fstar_uint128.c 4 | ALL_C_FILES= 5 | ALL_H_FILES=FStar_UInt128.h FStar_UInt_8_16_32_64.h LowStar_Endianness.h 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | liboprf*.a 2 | *.o 3 | .arch 4 | bench 5 | *.pdf 6 | matrices 7 | liboprf.so 8 | dkg 9 | thmult 10 | toprf 11 | tuokms 12 | uokms 13 | attack 14 | tp-dkg 15 | python/tests/__pycache__/ 16 | src/liboprf-corrupt-dkg.so 17 | src/liboprf.pc 18 | -------------------------------------------------------------------------------- /src/tests/.gitignore: -------------------------------------------------------------------------------- 1 | cfrg_oprf_test_vector_decl.h 2 | cfrg_oprf_test_vectors.h 3 | tv1 4 | tv2 5 | tp-dkg 6 | tp-dkg-corrupt 7 | stp-dkg 8 | stp-dkg-corrupt 9 | mpmult 10 | toprf-update 11 | toprf-update-corrupt 12 | ft-mult 13 | update-poc 14 | allocations 15 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/krml/internal/wasmsupport.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 2 | Licensed under the Apache 2.0 License. */ 3 | 4 | /* This file is automatically included when compiling with -wasm -d force-c */ 5 | #define WasmSupport_check_buffer_size(X) 6 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/minimal/libkrmllib.def: -------------------------------------------------------------------------------- 1 | LIBRARY libkrmllib 2 | 3 | EXPORTS 4 | FStar_UInt64_eq_mask 5 | FStar_UInt64_gte_mask 6 | FStar_UInt32_eq_mask 7 | FStar_UInt32_gte_mask 8 | FStar_UInt16_eq_mask 9 | FStar_UInt16_gte_mask 10 | FStar_UInt8_eq_mask 11 | FStar_UInt8_gte_mask 12 | -------------------------------------------------------------------------------- /liboprf.pc: -------------------------------------------------------------------------------- 1 | includedir=${prefix}/include 2 | 3 | Name: liboprf 4 | Description: implementation of OPRF (RFC9497) including (updatable) threshold variant 5 | Version: 0.7.1 6 | Cflags: -I${includedir}/oprf -I${includedir}/oprf/noiseXK/ -I${includedir}/oprf/noiseXK/karmel -I${includedir}/oprf/noiseXK/karmel/minimal 7 | Libs: -loprf 8 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/README.txt: -------------------------------------------------------------------------------- 1 | contains snapshot of e5620ceb7c8a4996520d693f597872806dc0a1d3 2 | from https://github.com/project-everest/hacl-star 3 | 4 | cp -r $(HACL_ROOT)/dist/karamel/krmllib/dist/minimal karmel 5 | cp -r $(HACL_ROOT)/dist/karamel/include/krml karmel/ 6 | cp -r ${HACL_ROOT}/dist/karamel/include karmel 7 | -------------------------------------------------------------------------------- /src/noise_xk/example/authorized_keys: -------------------------------------------------------------------------------- 1 | cWGtl4rxhY8S1uFh2Gfyi4d4B1BBoxKXpX5oAqsn3SQ= stf 2 | wLjHJ6njZIpaAuxQ2mK1OjLhYkHu0GGjm/HFfSi5iyM= alice 3 | auL719iakN0Uh9X1XSjsNgmMSYrbLUQHRJmjKuuqRHc= robert 4 | LvujMt01+k/1YQ19tIyLXdnqZlabtyPQv8+EZLKeBVA= rob 5 | kQH8j5UPJLcQfDEDGYS3NavVobgiov9dHVZ2v5JMGgo= robby 6 | NHBPri2k+EhTY+RKaKAlTXpxuQ7mKSxeRZ1stVeDLy0= robbie 7 | pN7KA3MPHU4Y9tmMcgsWjhYUuz1Kalk6KtAasr17+2w= bobbie 8 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/krml/c_endianness.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 2 | Licensed under the Apache 2.0 License. */ 3 | 4 | #ifndef __KRML_ENDIAN_H 5 | #define __KRML_ENDIAN_H 6 | 7 | #ifdef __GNUC__ 8 | #warning "c_endianness.h is deprecated, include lowstar_endianness.h instead" 9 | #endif 10 | 11 | #include "lowstar_endianness.h" 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/noise_xk/README.md: -------------------------------------------------------------------------------- 1 | libsodiumized version of `XK_25519_ChaChaPoly_BLAKE2b` extracted from 2 | https://github.com/Inria-Prosecco/noise-star 3 | git revision `38ad46c4e1adc048f8b9002c2265a96b961eb702` 4 | 5 | karmel directory contains the necessary includes 6 | https://github.com/project-everest/hacl-star 7 | git version `e5620ceb7c8a4996520d693f597872806dc0a1d3` 8 | 9 | see noise-star.patch for all changes 10 | -------------------------------------------------------------------------------- /src/tests/fuzz-tp-dkg/README.txt: -------------------------------------------------------------------------------- 1 | fuzz tp-dkg using AFL++ 2 | 3 | to fuzz step x (x:=1..9) of the TP run 4 | 5 | STEP=x make clean fuzz 6 | 7 | to fuzz using asan 8 | 9 | STEP=x make clean fuzz-asan 10 | 11 | to fuzz the peers step x: 12 | 13 | STEP=x make clean fuzz-peer 14 | 15 | to fuzz using asan: 16 | 17 | STEP=x make clean fuzz-asan-peer 18 | 19 | note: for some fuzz targets there cannot be any complaints 20 | -------------------------------------------------------------------------------- /src/tests/fuzz-toprf-update/README.txt: -------------------------------------------------------------------------------- 1 | fuzz tp-dkg using AFL++ 2 | 3 | to fuzz step x (x:=1..9) of the TP run 4 | 5 | STEP=x make clean fuzz 6 | 7 | to fuzz using asan 8 | 9 | STEP=x make clean fuzz-asan 10 | 11 | to fuzz the peers step x: 12 | 13 | STEP=x make clean fuzz-peer 14 | 15 | to fuzz using asan: 16 | 17 | STEP=x make clean fuzz-asan-peer 18 | 19 | note: for some fuzz targets there cannot be any complaints 20 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/krml/internal/builtin.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 2 | Licensed under the Apache 2.0 License. */ 3 | 4 | #ifndef __KRML_BUILTIN_H 5 | #define __KRML_BUILTIN_H 6 | 7 | /* For alloca, when using KaRaMeL's -falloca */ 8 | #if (defined(_WIN32) || defined(_WIN64)) 9 | # include 10 | #elif (defined(sun)) 11 | # include 12 | #endif 13 | 14 | /* If some globals need to be initialized before the main, then karamel will 15 | * generate and try to link last a function with this type: */ 16 | void krmlinit_globals(void); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef TOPRF_UTILS_H 2 | #define TOPRF_UTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | extern int liboprf_debug; 9 | extern FILE* liboprf_log_file; 10 | 11 | #define RED "\x1b[0;31m" 12 | #define NORMAL "\x1b[0m" 13 | #define GREEN "\x1b[0;32m" 14 | 15 | #ifdef UNIT_TEST 16 | void debian_rng_scalar(uint8_t *scalar); 17 | #endif //UNIT_TEST 18 | 19 | void dump(const uint8_t *p, const size_t len, const char* msg, ...); 20 | void fail(char* msg, ...); 21 | 22 | #ifndef htonll 23 | uint64_t htonll(uint64_t n); 24 | #endif 25 | 26 | #ifndef ntohll 27 | uint64_t ntohll(uint64_t n); 28 | #endif 29 | 30 | #endif // TOPRF_UTILS_H 31 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/minimal/LowStar_Endianness.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 3 | Licensed under the Apache 2.0 License. 4 | */ 5 | 6 | 7 | #ifndef __LowStar_Endianness_H 8 | #define __LowStar_Endianness_H 9 | 10 | #include 11 | #include 12 | #include "krml/internal/compat.h" 13 | #include "krml/lowstar_endianness.h" 14 | #include "krml/internal/types.h" 15 | #include "krml/internal/target.h" 16 | 17 | static inline void store128_le(uint8_t *x0, FStar_UInt128_uint128 x1); 18 | 19 | static inline FStar_UInt128_uint128 load128_le(uint8_t *x0); 20 | 21 | static inline void store128_be(uint8_t *x0, FStar_UInt128_uint128 x1); 22 | 23 | static inline FStar_UInt128_uint128 load128_be(uint8_t *x0); 24 | 25 | 26 | #define __LowStar_Endianness_H_DEFINED 27 | #endif 28 | -------------------------------------------------------------------------------- /src/tests/fuzz-tp-dkg/tpdkg_msg_parser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | from construct import * 5 | 6 | tpdkg_msg = Struct( 7 | "signature" / Array(64, Byte), 8 | "msgno" / Int8ub, 9 | "size" / Int32ub, 10 | "sender" / Int8ub, 11 | "to" / Int8ub, 12 | "ts" / Timestamp(Int64ub, 1., 1970), 13 | "data" / Array(this.size - 79, Byte), 14 | ) 15 | 16 | messages = GreedyRange(tpdkg_msg) 17 | 18 | with open(sys.argv[1], 'rb') as fd: 19 | raw = fd.read() 20 | 21 | while len(raw) > 0: 22 | print(raw[:83].hex()) 23 | try: 24 | msg = tpdkg_msg.parse(raw) 25 | print(f"{str(msg.ts)[:-6]} msgno: {msg.msgno}, len: {msg.size}, from: {msg.sender}, to: {msg.to:x}, data {bytes(msg.data).hex()}") 26 | raw = raw[msg.size:] 27 | except: 28 | print(raw[65:69].hex()) 29 | raw = raw[83:] 30 | -------------------------------------------------------------------------------- /src/tests/fuzz-tp-dkg/msg0.c: -------------------------------------------------------------------------------- 1 | #include "tp-dkg.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // gcc -o tpdkg-msg0 msg0.c -I.. -I../noise_xk/include -I../noise_xk/include/karmel -I../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf 8 | 9 | #define tpdkg_freshness_TIMEOUT 10 10 | 11 | int main(void) { 12 | uint8_t n=3, t=2; 13 | uint8_t peer_lt_pks[crypto_sign_PUBLICKEYBYTES]; 14 | // only known by corresponding peer 15 | uint8_t peer_lt_sks[crypto_sign_SECRETKEYBYTES]; 16 | crypto_sign_keypair(peer_lt_pks, peer_lt_sks); 17 | 18 | TP_DKG_TPState tp; 19 | uint8_t msg0[tpdkg_msg0_SIZE]; 20 | int ret = tpdkg_start_tp(&tp, tpdkg_freshness_TIMEOUT, n, t, "proto test", 10, sizeof msg0, (TP_DKG_Message*) &msg0); 21 | if(0!=ret) return ret; 22 | write(1, msg0, tpdkg_msg0_SIZE); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /python/examples/3hashtdh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from pyoprf import keygen, create_shares, blind, evaluate, unblind, thresholdmult 4 | from pysodium import randombytes, crypto_core_ristretto255_from_hash, crypto_generichash, crypto_core_ristretto255_add 5 | 6 | k = keygen() 7 | shares = create_shares(k, 5, 3) 8 | 9 | zero_shares = create_shares(bytes([0]*32), 5, 3) 10 | 11 | r, alpha = blind(b"test") 12 | 13 | ssid_S = randombytes(32) 14 | betas = [] 15 | for ki, zi in zip(shares,zero_shares): 16 | h2 = evaluate( 17 | zi[1:], 18 | crypto_core_ristretto255_from_hash(crypto_generichash(ssid_S + alpha, outlen=64)), 19 | ) 20 | beta = evaluate(ki[1:], alpha) 21 | betas.append(ki[:1]+crypto_core_ristretto255_add(beta, h2)) 22 | 23 | # normal 2hashdh(k,"test") 24 | beta = evaluate(k, alpha) 25 | Nt0 = unblind(r, beta) 26 | print(Nt0) 27 | beta = thresholdmult(betas[:3]) 28 | Nt1 = unblind(r, beta) 29 | print(Nt1) 30 | assert Nt0 == Nt1 31 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/krml/internal/callconv.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 2 | Licensed under the Apache 2.0 License. */ 3 | 4 | #ifndef __KRML_CALLCONV_H 5 | #define __KRML_CALLCONV_H 6 | 7 | /******************************************************************************/ 8 | /* Some macros to ease compatibility (TODO: move to miTLS) */ 9 | /******************************************************************************/ 10 | 11 | /* We want to generate __cdecl safely without worrying about it being undefined. 12 | * When using MSVC, these are always defined. When using MinGW, these are 13 | * defined too. They have no meaning for other platforms, so we define them to 14 | * be empty macros in other situations. */ 15 | #ifndef _MSC_VER 16 | #ifndef __cdecl 17 | #define __cdecl 18 | #endif 19 | #ifndef __stdcall 20 | #define __stdcall 21 | #endif 22 | #ifndef __fastcall 23 | #define __fastcall 24 | #endif 25 | #endif 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/tests/fuzz-toprf-update/toprf_update_msg_parser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | from construct import * 5 | 6 | dkg_msg = Struct( 7 | "signature" / Array(64, Byte), 8 | "type" / Int8ub, 9 | "version" / Int8ub, 10 | "msgno" / Int8ub, 11 | "size" / Int32ub, 12 | "sender" / Int8ub, 13 | "to" / Int8ub, 14 | "ts" / Timestamp(Int64ub, 1., 1970), 15 | "sessionid" / Array(32, Byte), 16 | "data" / Array(this.size - 113, Byte), 17 | ) 18 | 19 | messages = GreedyRange(dkg_msg) 20 | 21 | with open(sys.argv[1], 'rb') as fd: 22 | raw = fd.read() 23 | 24 | while len(raw) > 0: 25 | print(raw[:113].hex()) 26 | try: 27 | msg = dkg_msg.parse(raw) 28 | print(f"{str(msg.ts)[:-6]} type: {msg.type}, version: {msg.version}, msgno: {msg.msgno}, len: {msg.size}, from: {msg.sender}, to: {msg.to:x}\nsessionid: {bytes(msg.sessionid).hex()}\ndata: {bytes(msg.data).hex()}") 29 | raw = raw[msg.size:] 30 | except: 31 | print(raw[67:71].hex()) 32 | raw = raw[113:] 33 | -------------------------------------------------------------------------------- /src/noise_xk/example/makefile: -------------------------------------------------------------------------------- 1 | LDFLAGS=-lsodium -loprf-noiseXK 2 | SOURCES=xk-ex.c ../../utils.c 3 | 4 | INCLUDES=-I../.. -I../include -I ../include/karmel -I ../include/karmel/minimal 5 | CFLAGS ?= -Wall -Wextra -Werror -std=c11 -Wno-unused-variable \ 6 | -Wno-unknown-warning-option -Wno-unused-but-set-variable \ 7 | -Wno-unused-parameter -Wno-infinite-recursion -fPIC \ 8 | -g -fwrapv -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM \ 9 | -O2 -fstack-protector-strong -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \ 10 | -fasynchronous-unwind-tables -fpic -Werror=format-security \ 11 | -Werror=implicit-function-declaration -Wl,-z,defs -Wl,-z,relro \ 12 | -ftrapv -Wl,-z,noexecstack 13 | 14 | ARCH := $(shell uname -m) 15 | ifeq ($(ARCH),x86_64) 16 | CFLAGS+=-fcf-protection=full 17 | endif 18 | ifeq ($(ARCH),parisc64) 19 | else ifeq ($(ARCH),parisc64) 20 | else 21 | CFLAGS+=-fstack-clash-protection 22 | endif 23 | 24 | all: xk-ex 25 | 26 | xk-ex: $(SOURCES) 27 | $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LDFLAGS) -L.. 28 | 29 | AR ?= ar 30 | 31 | test: xk-ex 32 | LD_LIBRARY_PATH=.. ./xk-ex 33 | 34 | clean: 35 | rm -rf *.o xk-ex 36 | -------------------------------------------------------------------------------- /zephyr/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt for liboprf integration with Zephyr 2 | 3 | if(CONFIG_LIBOPRF) 4 | # Create a Zephyr library for the platform-specific adaptations 5 | zephyr_library_named(oprf_zephyr) 6 | 7 | # Define source directories 8 | set(LIBOPRF_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..) 9 | set(LIBOPRF_SRC_DIR ${LIBOPRF_DIR}/src) 10 | 11 | # Build liboprf directly (no external build process) 12 | #zephyr_library_named(oprf) 13 | 14 | # Add necessary includes 15 | zephyr_include_directories( 16 | ${LIBOPRF_DIR}/src 17 | ${LIBOPRF_DIR}/src/noise_xk/include 18 | ${LIBOPRF_DIR}/src/noise_xk/include/karmel 19 | ${LIBOPRF_DIR}/src/noise_xk/include/karmel/minimal 20 | ) 21 | 22 | # Make the includes available to applications 23 | zephyr_library_include_directories( 24 | ${LIBOPRF_DIR}/src 25 | ${LIBOPRF_DIR}/src/noise_xk/include 26 | ${LIBOPRF_DIR}/src/noise_xk/include/karmel 27 | ${LIBOPRF_DIR}/src/noise_xk/include/karmel/minimal 28 | ) 29 | 30 | FILE(GLOB lib_sources 31 | ${LIBOPRF_SRC_DIR}/*.c 32 | ${LIBOPRF_SRC_DIR}/noise_xk/src/*.c) 33 | # Add all necessary source files 34 | zephyr_library_sources(${lib_sources}) 35 | 36 | zephyr_compile_definitions(NO_TIME) 37 | endif() 38 | -------------------------------------------------------------------------------- /src/tests/fuzz-tp-dkg/peer-start.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tp-dkg.h" 4 | 5 | // afl-clang-fast -o peer-start peer-start.c -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf 6 | 7 | __AFL_FUZZ_INIT(); 8 | 9 | int main() { 10 | 11 | // anything else here, e.g. command line arguments, initialization, etc. 12 | uint8_t peer_lt_sks[32]={250}; 13 | TP_DKG_PeerState peer; 14 | 15 | #ifdef __AFL_HAVE_MANUAL_CONTROL 16 | __AFL_INIT(); 17 | #endif 18 | 19 | unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; // must be after __AFL_INIT 20 | // and before __AFL_LOOP! 21 | 22 | while (__AFL_LOOP(10000)) { 23 | 24 | int len = __AFL_FUZZ_TESTCASE_LEN; // don't use the macro directly in a 25 | // call! 26 | 27 | if (len < sizeof(TP_DKG_Message)) continue; // check for a required/useful minimum input length 28 | 29 | /* Setup function call, e.g. struct target *tmp = libtarget_init() */ 30 | /* Call function to be fuzzed, e.g.: */ 31 | tpdkg_start_peer(&peer, 10, peer_lt_sks, (TP_DKG_Message*) buf); 32 | 33 | /* Reset state. e.g. libtarget_free(tmp) */ 34 | } 35 | 36 | return 0; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # SPDX-FileCopyrightText: 2023, Marsiske Stefan 4 | # SPDX-License-Identifier: LGPL-3.0-or-later 5 | 6 | import os 7 | from setuptools import setup, find_packages 8 | 9 | 10 | # Utility function to read the README file. 11 | # Used for the long_description. It's nice, because now 1) we have a top level 12 | # README file and 2) it's easier to type in the README file than to put a raw 13 | # string in below ... 14 | def read(fname): 15 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 16 | 17 | setup(name = 'pyoprf', 18 | version = '0.9.0', 19 | description = 'python bindings for liboprf', 20 | license = "LGPLv3", 21 | author = 'Stefan Marsiske', 22 | author_email = 'toprf@ctrlc.hu', 23 | url = 'https://github.com/stef/liboprf/python', 24 | long_description=read('README.md'), 25 | long_description_content_type="text/markdown", 26 | packages=find_packages(), 27 | install_requires = ("pysodium", "SecureString", "pyserial", "pyudev", "ble_serial", "pyserial-asyncio"), 28 | classifiers = ["Development Status :: 4 - Beta", 29 | "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)", 30 | "Topic :: Security :: Cryptography", 31 | "Topic :: Security", 32 | ], 33 | #ext_modules = [liboprf], 34 | ) 35 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/krml/internal/compat.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 2 | Licensed under the Apache 2.0 License. */ 3 | 4 | #ifndef KRML_COMPAT_H 5 | #define KRML_COMPAT_H 6 | 7 | #include 8 | 9 | /* A series of macros that define C implementations of types that are not Low*, 10 | * to facilitate porting programs to Low*. */ 11 | 12 | typedef struct { 13 | uint32_t length; 14 | const char *data; 15 | } FStar_Bytes_bytes; 16 | 17 | typedef int32_t Prims_pos, Prims_nat, Prims_nonzero, Prims_int, 18 | krml_checked_int_t; 19 | 20 | #define RETURN_OR(x) \ 21 | do { \ 22 | int64_t __ret = x; \ 23 | if (__ret < INT32_MIN || INT32_MAX < __ret) { \ 24 | KRML_HOST_PRINTF( \ 25 | "Prims.{int,nat,pos} integer overflow at %s:%d\n", __FILE__, \ 26 | __LINE__); \ 27 | KRML_HOST_EXIT(252); \ 28 | } \ 29 | return (int32_t)__ret; \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /.github/workflows/python-app.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | name: Python application 5 | 6 | on: 7 | push: 8 | branches: [ "master" ] 9 | pull_request: 10 | branches: [ "master" ] 11 | 12 | permissions: 13 | contents: read 14 | 15 | jobs: 16 | build: 17 | 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Set up Python 3.10 23 | uses: actions/setup-python@v3 24 | with: 25 | python-version: "3.10" 26 | - name: Install dependencies 27 | run: | 28 | python -m pip install --upgrade pip 29 | pip install flake8 pytest 30 | sudo apt update 31 | sudo apt install -y libsodium-dev pkgconf # build-essential git 32 | pip install python/ pysodium SecureString 33 | cd src 34 | sudo PREFIX=/usr make install 35 | cd .. 36 | - name: Lint with flake8 37 | run: | 38 | # stop the build if there are Python syntax errors or undefined names 39 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 40 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 41 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 42 | - name: Test with pytest 43 | run: | 44 | pytest -s -v python/tests/test.py 45 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [master] 9 | schedule: 10 | - cron: '0 3 * * 2' 11 | 12 | jobs: 13 | analyze: 14 | name: Analyze 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v4 20 | 21 | # Initializes the CodeQL tools for scanning. 22 | - name: Initialize CodeQL 23 | uses: github/codeql-action/init@v3 24 | # Override language selection by uncommenting this and choosing your languages 25 | # with: 26 | # languages: go, javascript, csharp, python, cpp, java 27 | 28 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 29 | # If this step fails, then you should remove it and run the build manually (see below) 30 | #- name: Autobuild 31 | # uses: github/codeql-action/autobuild@v1 32 | 33 | # ℹ️ Command-line programs to run using the OS shell. 34 | # 📚 https://git.io/JvXDl 35 | 36 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 37 | # and modify them (or add more) to build your code if your project 38 | # uses a compiled language 39 | 40 | - run: | 41 | sudo apt update 42 | sudo apt install -y libsodium-dev pkgconf # build-essential git 43 | # main liboprf 44 | cd src 45 | make test 46 | 47 | - name: Perform CodeQL Analysis 48 | uses: github/codeql-action/analyze@v3 49 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/minimal/Makefile.basic: -------------------------------------------------------------------------------- 1 | # A basic Makefile that KaRaMeL copies in the output directory; this is not 2 | # guaranteed to work and will only work well for very simple projects. This 3 | # Makefile uses: 4 | # - the custom C files passed to your krml invocation 5 | # - the custom C flags passed to your krml invocation 6 | # - the -o option passed to your krml invocation 7 | 8 | include Makefile.include 9 | 10 | ifeq (,$(KRML_HOME)) 11 | $(error please define KRML_HOME to point to the root of your KaRaMeL git checkout) 12 | endif 13 | 14 | CFLAGS += -I. -I $(KRML_HOME)/include -I $(KRML_HOME)/krmllib/dist/minimal 15 | CFLAGS += -Wall -Wextra -Werror -std=c11 \ 16 | -Wno-unknown-warning-option \ 17 | -Wno-infinite-recursion \ 18 | -g -fwrapv -D_BSD_SOURCE -D_DEFAULT_SOURCE 19 | ifeq ($(OS),Windows_NT) 20 | CFLAGS += -D__USE_MINGW_ANSI_STDIO 21 | else 22 | CFLAGS += -fPIC 23 | endif 24 | CFLAGS += $(USER_CFLAGS) 25 | 26 | SOURCES += $(ALL_C_FILES) $(USER_C_FILES) 27 | ifneq (,$(BLACKLIST)) 28 | SOURCES := $(filter-out $(BLACKLIST),$(SOURCES)) 29 | endif 30 | OBJS += $(patsubst %.c,%.o,$(SOURCES)) 31 | 32 | all: $(USER_TARGET) 33 | 34 | $(USER_TARGET): $(OBJS) 35 | 36 | AR ?= ar 37 | 38 | %.a: 39 | $(AR) cr $@ $^ 40 | 41 | %.exe: 42 | $(CC) $(CFLAGS) -o $@ $^ $(KRML_HOME)/krmllib/dist/generic/libkrmllib.a 43 | 44 | %.so: 45 | $(CC) $(CFLAGS) -shared -o $@ $^ 46 | 47 | %.d: %.c 48 | @set -e; rm -f $@; \ 49 | $(CC) -MM -MG $(CFLAGS) $< > $@.$$$$; \ 50 | sed 's,\($(notdir $*)\)\.o[ :]*,$(dir $@)\1.o $@ : ,g' < $@.$$$$ > $@; \ 51 | rm -f $@.$$$$ 52 | 53 | include $(patsubst %.c,%.d,$(SOURCES)) 54 | 55 | clean: 56 | rm -rf *.o *.d $(USER_TARGET) 57 | -------------------------------------------------------------------------------- /src/tests/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "cfrg_oprf_test_vectors.h" 5 | #include "../oprf.h" 6 | #include "../utils.h" 7 | 8 | extern int liboprf_debug; 9 | 10 | int main(void) { 11 | liboprf_debug = 1; 12 | int res; 13 | 14 | uint8_t r[crypto_core_ristretto255_SCALARBYTES]; 15 | uint8_t blinded[crypto_core_ristretto255_BYTES]; 16 | 17 | res = oprf_Blind(input, input_len, r, blinded); 18 | if(res) return 1; 19 | if(memcmp(blinded, blinded_element, blindedelement_len)!=0) { 20 | fail("calulated Blinded Element is not expected value:"); 21 | dump(blinded, sizeof(blinded), "calculated: "); 22 | dump(blinded_element, blindedelement_len, "expected: "); 23 | return 1; 24 | } 25 | 26 | uint8_t Z[crypto_core_ristretto255_BYTES]; 27 | res = oprf_Evaluate(sks, blinded, Z); 28 | if(res) { 29 | fprintf(stderr,"oprf_Evaluate returned error\n"); 30 | return 1; 31 | } 32 | if(memcmp(Z, evaluationelement, evaluationelement_len)!=0) { 33 | fail("calulated Evaluation Element is not expected value:"); 34 | dump(Z, sizeof(Z), "calculated: "); 35 | dump(evaluationelement, evaluationelement_len, "expected: "); 36 | return 1; 37 | } 38 | 39 | uint8_t N[crypto_core_ristretto255_BYTES]; 40 | res = oprf_Unblind(r, Z, N); 41 | if(res) { 42 | fprintf(stderr,"oprf_Unblind returned error\n"); 43 | return 1; 44 | } 45 | uint8_t rwd[OPRF_BYTES]; 46 | res = oprf_Finalize(input, input_len, N, rwd); 47 | if(res) { 48 | fprintf(stderr,"oprf_Finalize returned error\n"); 49 | return 1; 50 | } 51 | if(memcmp(rwd, output, output_len)!=0) { 52 | fail("calulated output is not expected value:"); 53 | dump(rwd, sizeof(rwd), "calculated: "); 54 | dump(output, output_len, "expected: "); 55 | return 1; 56 | } 57 | 58 | printf("all ok\n"); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/minimal/fstar_uint128_struct_endianness.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 2 | Licensed under the Apache 2.0 License. */ 3 | 4 | #ifndef FSTAR_UINT128_STRUCT_ENDIANNESS_H 5 | #define FSTAR_UINT128_STRUCT_ENDIANNESS_H 6 | 7 | /* Hand-written implementation of endianness-related uint128 functions 8 | * for the extracted uint128 implementation */ 9 | 10 | /* Access 64-bit fields within the int128. */ 11 | #define HIGH64_OF(x) ((x)->high) 12 | #define LOW64_OF(x) ((x)->low) 13 | 14 | /* A series of definitions written using pointers. */ 15 | 16 | inline static void load128_le_(uint8_t *b, uint128_t *r) { 17 | LOW64_OF(r) = load64_le(b); 18 | HIGH64_OF(r) = load64_le(b + 8); 19 | } 20 | 21 | inline static void store128_le_(uint8_t *b, uint128_t *n) { 22 | store64_le(b, LOW64_OF(n)); 23 | store64_le(b + 8, HIGH64_OF(n)); 24 | } 25 | 26 | inline static void load128_be_(uint8_t *b, uint128_t *r) { 27 | HIGH64_OF(r) = load64_be(b); 28 | LOW64_OF(r) = load64_be(b + 8); 29 | } 30 | 31 | inline static void store128_be_(uint8_t *b, uint128_t *n) { 32 | store64_be(b, HIGH64_OF(n)); 33 | store64_be(b + 8, LOW64_OF(n)); 34 | } 35 | 36 | #ifndef KRML_NOSTRUCT_PASSING 37 | 38 | inline static uint128_t load128_le(uint8_t *b) { 39 | uint128_t r; 40 | load128_le_(b, &r); 41 | return r; 42 | } 43 | 44 | inline static void store128_le(uint8_t *b, uint128_t n) { 45 | store128_le_(b, &n); 46 | } 47 | 48 | inline static uint128_t load128_be(uint8_t *b) { 49 | uint128_t r; 50 | load128_be_(b, &r); 51 | return r; 52 | } 53 | 54 | inline static void store128_be(uint8_t *b, uint128_t n) { 55 | store128_be_(b, &n); 56 | } 57 | 58 | #else /* !defined(KRML_STRUCT_PASSING) */ 59 | 60 | # define print128 print128_ 61 | # define load128_le load128_le_ 62 | # define store128_le store128_le_ 63 | # define load128_be load128_be_ 64 | # define store128_be store128_be_ 65 | 66 | #endif /* KRML_STRUCT_PASSING */ 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #if (defined UNIT_TEST || defined UNITTEST_CORRUPT) 7 | int liboprf_debug = 1; 8 | #else 9 | int liboprf_debug = 0; 10 | #endif 11 | FILE *liboprf_log_file=NULL; 12 | 13 | #ifdef UNIT_TEST 14 | void debian_rng_scalar(uint8_t *scalar) { 15 | static int warned=0; 16 | static uint8_t rng_i[4]={1,0,0,0}; 17 | if(!warned) { 18 | fprintf(stderr, "\x1b[0;31mWARNING! This version of liboprf DKG is compiled with a *NON* random generator for UNIT_TESTS\x1b[0m\n"); 19 | warned=1; 20 | } 21 | memset(scalar,0,crypto_core_ristretto255_SCALARBYTES); 22 | sodium_increment(rng_i,4); 23 | memcpy(scalar,rng_i,4); 24 | //static uint16_t rng_i=0; 25 | //uint16_t tmp[64 / sizeof(uint16_t)]; 26 | //for(unsigned j=0;j<(64/ sizeof(uint16_t));j++) { 27 | // tmp[j]=rng_i++; 28 | //} 29 | //crypto_core_ristretto255_scalar_reduce(scalar,(uint8_t*)tmp); 30 | } 31 | #endif 32 | 33 | void __attribute__((visibility("hidden"))) dump(const uint8_t *p, const size_t len, const char* msg, ...) { 34 | FILE* lf = stderr; 35 | if(!liboprf_debug) return; 36 | if(liboprf_log_file!=NULL) lf = liboprf_log_file; 37 | va_list args; 38 | va_start(args, msg); 39 | vfprintf(lf, msg, args); 40 | va_end(args); 41 | fprintf(lf," "); 42 | for(size_t i=0;i 59 | uint64_t __attribute__((visibility("hidden"))) htonll(uint64_t n) { 60 | #if __BYTE_ORDER == __BIG_ENDIAN 61 | return n; 62 | #else 63 | return (((uint64_t)htonl((uint32_t)n)) << 32) + htonl((uint32_t) (n >> 32)); 64 | #endif 65 | } 66 | #endif // htonll 67 | 68 | #ifndef ntohll 69 | uint64_t __attribute__((visibility("hidden"))) ntohll(uint64_t n) { 70 | #if __BYTE_ORDER == __BIG_ENDIAN 71 | return n; 72 | #else 73 | return (((uint64_t)ntohl((uint32_t)n)) << 32) + ntohl((uint32_t)(n >> 32)); 74 | #endif 75 | } 76 | #endif // ntohll 77 | -------------------------------------------------------------------------------- /src/noise_xk/include/noise_private.h: -------------------------------------------------------------------------------- 1 | #ifndef noise_xk_private_h 2 | #define noise_xk_private_h 3 | #include 4 | #include "XK.h" 5 | 6 | #undef Noise_XK_init_state_t_s 7 | typedef struct Noise_XK_init_state_t_s { 8 | Noise_XK_init_state_t_tags tag; 9 | union { 10 | struct { 11 | uint32_t step; 12 | uint8_t *cipher_key; 13 | uint8_t *chaining_key; 14 | uint8_t *h; 15 | uint8_t *spriv; 16 | uint8_t *spub; 17 | uint8_t *epriv; 18 | uint8_t *epub; 19 | uint8_t *rs; 20 | uint8_t *re; 21 | } case_IMS_Handshake; 22 | struct { 23 | uint8_t *h; 24 | bool recv_transport_message; 25 | uint8_t *send_key; 26 | uint64_t send_nonce; 27 | uint8_t *receive_key; 28 | uint64_t receive_nonce; 29 | } case_IMS_Transport; 30 | } val; 31 | } Noise_XK_init_state_t; 32 | 33 | #undef Noise_XK_resp_state_t_s 34 | typedef struct Noise_XK_resp_state_t_s { 35 | Noise_XK_init_state_t_tags tag; 36 | union { 37 | struct { 38 | uint32_t step; 39 | uint8_t *cipher_key; 40 | uint8_t *chaining_key; 41 | uint8_t *h; 42 | uint8_t *spriv; 43 | uint8_t *spub; 44 | uint8_t *epriv; 45 | uint8_t *epub; 46 | uint8_t *rs; 47 | uint8_t *re; 48 | } case_IMS_Handshake; 49 | struct { 50 | uint8_t *h; 51 | uint8_t *send_key; 52 | uint64_t send_nonce; 53 | uint8_t *receive_key; 54 | uint64_t receive_nonce; 55 | } case_IMS_Transport; 56 | } val; 57 | } Noise_XK_resp_state_t; 58 | 59 | #undef Noise_XK_session_t_s 60 | typedef struct Noise_XK_session_t_s { 61 | Noise_XK_session_t_tags tag; 62 | union { 63 | struct { 64 | Noise_XK_init_state_t state; 65 | uint32_t id; 66 | Noise_XK_noise_string *info; 67 | uint8_t *spriv; 68 | uint8_t *spub; 69 | uint32_t pid; 70 | Noise_XK_noise_string *pinfo; 71 | Noise_XK_device_t *dv; 72 | } case_DS_Initiator; 73 | struct { 74 | Noise_XK_resp_state_t state; 75 | uint32_t id; 76 | Noise_XK_noise_string *info; 77 | uint8_t *spriv; 78 | uint8_t *spub; 79 | uint32_t pid; 80 | Noise_XK_noise_string *pinfo; 81 | Noise_XK_device_t *dv; 82 | } case_DS_Responder; 83 | } val; 84 | } Noise_XK_session_t; 85 | 86 | #endif // noise_xk_private_h 87 | -------------------------------------------------------------------------------- /src/aux_/crypto_kdf_hkdf_sha256.h: -------------------------------------------------------------------------------- 1 | #ifndef crypto_kdf_hkdf_sha256_H 2 | #define crypto_kdf_hkdf_sha256_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | //#include "crypto_kdf.h" 10 | //#include "crypto_auth_hmacsha256.h" 11 | //#include "export.h" 12 | 13 | #ifdef __cplusplus 14 | # ifdef __GNUC__ 15 | # pragma GCC diagnostic ignored "-Wlong-long" 16 | # endif 17 | extern "C" { 18 | #endif 19 | 20 | #define crypto_kdf_hkdf_sha256_KEYBYTES crypto_auth_hmacsha256_BYTES 21 | SODIUM_EXPORT 22 | size_t crypto_kdf_hkdf_sha256_keybytes(void); 23 | 24 | #define crypto_kdf_hkdf_sha256_BYTES_MIN 0U 25 | SODIUM_EXPORT 26 | size_t crypto_kdf_hkdf_sha256_bytes_min(void); 27 | 28 | #define crypto_kdf_hkdf_sha256_BYTES_MAX (0xff * crypto_auth_hmacsha256_BYTES) 29 | SODIUM_EXPORT 30 | size_t crypto_kdf_hkdf_sha256_bytes_max(void); 31 | 32 | SODIUM_EXPORT 33 | int crypto_kdf_hkdf_sha256_extract(unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES], 34 | const unsigned char *salt, size_t salt_len, 35 | const unsigned char *ikm, size_t ikm_len) 36 | __attribute__ ((nonnull(4))); 37 | 38 | SODIUM_EXPORT 39 | void crypto_kdf_hkdf_sha256_keygen(unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES]); 40 | 41 | SODIUM_EXPORT 42 | int crypto_kdf_hkdf_sha256_expand(unsigned char *out, size_t out_len, 43 | const char *ctx, size_t ctx_len, 44 | const unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES]) 45 | __attribute__ ((nonnull(1))); 46 | 47 | /* ------------------------------------------------------------------------- */ 48 | 49 | typedef struct crypto_kdf_hkdf_sha256_state { 50 | crypto_auth_hmacsha256_state st; 51 | } crypto_kdf_hkdf_sha256_state; 52 | 53 | SODIUM_EXPORT 54 | size_t crypto_kdf_hkdf_sha256_statebytes(void); 55 | 56 | SODIUM_EXPORT 57 | int crypto_kdf_hkdf_sha256_extract_init(crypto_kdf_hkdf_sha256_state *state, 58 | const unsigned char *salt, size_t salt_len) 59 | __attribute__ ((nonnull(1))); 60 | 61 | SODIUM_EXPORT 62 | int crypto_kdf_hkdf_sha256_extract_update(crypto_kdf_hkdf_sha256_state *state, 63 | const unsigned char *ikm, size_t ikm_len) 64 | __attribute__ ((nonnull)); 65 | 66 | SODIUM_EXPORT 67 | int crypto_kdf_hkdf_sha256_extract_final(crypto_kdf_hkdf_sha256_state *state, 68 | unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES]) 69 | __attribute__ ((nonnull)); 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/krml/fstar_int.h: -------------------------------------------------------------------------------- 1 | #ifndef __FSTAR_INT_H 2 | #define __FSTAR_INT_H 3 | 4 | #include "internal/types.h" 5 | 6 | /* 7 | * Arithmetic Shift Right operator 8 | * 9 | * In all C standards, a >> b is implementation-defined when a has a signed 10 | * type and a negative value. See e.g. 6.5.7 in 11 | * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2310.pdf 12 | * 13 | * GCC, MSVC, and Clang implement a >> b as an arithmetic shift. 14 | * 15 | * GCC: https://gcc.gnu.org/onlinedocs/gcc-9.1.0/gcc/Integers-implementation.html#Integers-implementation 16 | * MSVC: https://docs.microsoft.com/en-us/cpp/cpp/left-shift-and-right-shift-operators-input-and-output?view=vs-2019#right-shifts 17 | * Clang: tested that Clang 7, 8 and 9 compile this to an arithmetic shift 18 | * 19 | * We implement arithmetic shift right simply as >> in these compilers 20 | * and bail out in others. 21 | */ 22 | 23 | #if !(defined(_MSC_VER) || defined(__GNUC__) || (defined(__clang__) && (__clang_major__ >= 7))) 24 | 25 | static inline 26 | int8_t FStar_Int8_shift_arithmetic_right(int8_t a, uint32_t b) { 27 | do { 28 | KRML_HOST_EPRINTF("Could not identify compiler so could not provide an implementation of signed arithmetic shift right.\n"); 29 | KRML_HOST_EXIT(255); 30 | } while (0); 31 | } 32 | 33 | static inline 34 | int16_t FStar_Int16_shift_arithmetic_right(int16_t a, uint32_t b) { 35 | do { 36 | KRML_HOST_EPRINTF("Could not identify compiler so could not provide an implementation of signed arithmetic shift right.\n"); 37 | KRML_HOST_EXIT(255); 38 | } while (0); 39 | } 40 | 41 | static inline 42 | int32_t FStar_Int32_shift_arithmetic_right(int32_t a, uint32_t b) { 43 | do { 44 | KRML_HOST_EPRINTF("Could not identify compiler so could not provide an implementation of signed arithmetic shift right.\n"); 45 | KRML_HOST_EXIT(255); 46 | } while (0); 47 | } 48 | 49 | static inline 50 | int64_t FStar_Int64_shift_arithmetic_right(int64_t a, uint32_t b) { 51 | do { 52 | KRML_HOST_EPRINTF("Could not identify compiler so could not provide an implementation of signed arithmetic shift right.\n"); 53 | KRML_HOST_EXIT(255); 54 | } while (0); 55 | } 56 | 57 | #else 58 | 59 | static inline 60 | int8_t FStar_Int8_shift_arithmetic_right(int8_t a, uint32_t b) { 61 | return (a >> b); 62 | } 63 | 64 | static inline 65 | int16_t FStar_Int16_shift_arithmetic_right(int16_t a, uint32_t b) { 66 | return (a >> b); 67 | } 68 | 69 | static inline 70 | int32_t FStar_Int32_shift_arithmetic_right(int32_t a, uint32_t b) { 71 | return (a >> b); 72 | } 73 | 74 | static inline 75 | int64_t FStar_Int64_shift_arithmetic_right(int64_t a, uint32_t b) { 76 | return (a >> b); 77 | } 78 | 79 | #endif /* !(defined(_MSC_VER) ... ) */ 80 | 81 | #endif /* __FSTAR_INT_H */ 82 | -------------------------------------------------------------------------------- /src/noise_xk/makefile: -------------------------------------------------------------------------------- 1 | PREFIX?=/usr/local 2 | LIBS=-lsodium 3 | SOURCES=src/Noise_XK.c src/XK.c 4 | INCLUDES= -Iinclude -I include/karmel -I include/karmel/minimal 5 | CFLAGS ?= -Wall -Wextra -Werror -std=c11 -Wno-unused-variable \ 6 | -Wno-unknown-warning-option -Wno-unused-but-set-variable \ 7 | -Wno-unused-parameter -Wno-infinite-recursion -fpic \ 8 | -fwrapv -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM \ 9 | -O2 -fstack-protector-strong -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \ 10 | -fasynchronous-unwind-tables -fpic \ 11 | -Werror=format-security -Werror=implicit-function-declaration \ 12 | -ftrapv 13 | CC?=gcc 14 | 15 | SOEXT?=so 16 | STATICEXT?=a 17 | SOVER=0 18 | 19 | UNAME := $(if $(UNAME),$(UNAME),$(shell uname -s)) 20 | ARCH := $(if $(ARCH),$(ARCH),$(shell uname -m)) 21 | ifeq ($(UNAME),Darwin) 22 | SOEXT=dylib 23 | SOFLAGS=-Wl,-install_name,$(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(SOEXT) 24 | else 25 | ifeq ($(UNAME),Linux) 26 | CFLAGS += -Wl,--error-unresolved-symbols -Wl,-z,defs -Wl,-z,relro -Wl,-z,noexecstack 27 | SOEXT=so 28 | SOFLAGS=-Wl,-soname,liboprf-noiseXK.$(SOEXT).$(SOVER) 29 | endif 30 | ifeq ($(ARCH),x86_64) 31 | CFLAGS+=-fcf-protection=full 32 | endif 33 | ifeq ($(ARCH),parisc64) 34 | else ifeq ($(ARCH),parisc64) 35 | else ifeq ($(ARCH),armv7-a) 36 | else 37 | CFLAGS+=-fstack-clash-protection 38 | endif 39 | endif 40 | 41 | OBJS += $(patsubst %.c,%.o,$(SOURCES)) 42 | 43 | android: CFLAGS+=-I$(SODIUM) -I$(SODIUM)/sodium 44 | android: LDFLAGS+=-L. 45 | android: liboprf-noiseXK.$(SOEXT) 46 | 47 | all: liboprf-noiseXK.$(STATICEXT) liboprf-noiseXK.$(SOEXT) 48 | 49 | AR ?= ar 50 | 51 | %.$(STATICEXT): $(OBJS) 52 | $(AR) rcs $@ $^ 53 | 54 | %.$(SOEXT): $(OBJS) 55 | $(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -shared $(SOFLAGS) $(INCLUDES) -o $@ $^ $(LDFLAGS) $(LIBS) 56 | 57 | clean: 58 | rm -rf *.so *.a src/*.o 59 | make -C example clean 60 | 61 | liboprf-noiseXK.$(SOEXT).$(SOVER): liboprf-noiseXK.$(SOEXT) 62 | ln -sf $^ $@ 63 | 64 | install: $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(SOEXT) $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(STATICEXT) $(DESTDIR)$(PREFIX)/include/oprf/noiseXK 65 | 66 | uninstall: $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(SOEXT) $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(STATICEXT) $(DESTDIR)$(PREFIX)/include/oprf/noiseXK 67 | rm -rf $^ 68 | 69 | $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(SOEXT): liboprf-noiseXK.$(SOEXT) 70 | mkdir -p $(DESTDIR)$(PREFIX)/lib/ 71 | cp $< $@.$(SOVER) 72 | ln -sf $@.$(SOVER) $@ 73 | 74 | $(DESTDIR)$(PREFIX)/lib/liboprf-noiseXK.$(STATICEXT): liboprf-noiseXK.$(STATICEXT) 75 | mkdir -p $(DESTDIR)$(PREFIX)/lib/ 76 | cp $< $@ 77 | 78 | $(DESTDIR)$(PREFIX)/include/oprf/noiseXK: include 79 | cp -r $< $@ 80 | 81 | test: liboprf-noiseXK.$(SOEXT).$(SOVER) 82 | make -C example test 83 | 84 | %.o: %.c 85 | $(CC) $(CPPFLAGS) $(CFLAGS) -fPIC $(INCLUDES) -c $< -o $@ 86 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/minimal/FStar_UInt128.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 3 | Licensed under the Apache 2.0 License. 4 | */ 5 | 6 | 7 | #ifndef __FStar_UInt128_H 8 | #define __FStar_UInt128_H 9 | 10 | #include 11 | #include 12 | #include "krml/internal/compat.h" 13 | #include "krml/lowstar_endianness.h" 14 | #include "krml/internal/types.h" 15 | #include "krml/internal/target.h" 16 | 17 | static inline FStar_UInt128_uint128 18 | FStar_UInt128_add(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 19 | 20 | static inline FStar_UInt128_uint128 21 | FStar_UInt128_add_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 22 | 23 | static inline FStar_UInt128_uint128 24 | FStar_UInt128_add_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 25 | 26 | static inline FStar_UInt128_uint128 27 | FStar_UInt128_sub(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 28 | 29 | static inline FStar_UInt128_uint128 30 | FStar_UInt128_sub_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 31 | 32 | static inline FStar_UInt128_uint128 33 | FStar_UInt128_sub_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 34 | 35 | static inline FStar_UInt128_uint128 36 | FStar_UInt128_logand(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 37 | 38 | static inline FStar_UInt128_uint128 39 | FStar_UInt128_logxor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 40 | 41 | static inline FStar_UInt128_uint128 42 | FStar_UInt128_logor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 43 | 44 | static inline FStar_UInt128_uint128 FStar_UInt128_lognot(FStar_UInt128_uint128 a); 45 | 46 | static inline FStar_UInt128_uint128 47 | FStar_UInt128_shift_left(FStar_UInt128_uint128 a, uint32_t s); 48 | 49 | static inline FStar_UInt128_uint128 50 | FStar_UInt128_shift_right(FStar_UInt128_uint128 a, uint32_t s); 51 | 52 | static inline bool FStar_UInt128_eq(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 53 | 54 | static inline bool FStar_UInt128_gt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 55 | 56 | static inline bool FStar_UInt128_lt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 57 | 58 | static inline bool FStar_UInt128_gte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 59 | 60 | static inline bool FStar_UInt128_lte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 61 | 62 | static inline FStar_UInt128_uint128 63 | FStar_UInt128_eq_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 64 | 65 | static inline FStar_UInt128_uint128 66 | FStar_UInt128_gte_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b); 67 | 68 | static inline FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t a); 69 | 70 | static inline uint64_t FStar_UInt128_uint128_to_uint64(FStar_UInt128_uint128 a); 71 | 72 | static inline FStar_UInt128_uint128 FStar_UInt128_mul32(uint64_t x, uint32_t y); 73 | 74 | static inline FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x, uint64_t y); 75 | 76 | 77 | #define __FStar_UInt128_H_DEFINED 78 | #endif 79 | -------------------------------------------------------------------------------- /src/tests/fuzz-toprf-update/makefile: -------------------------------------------------------------------------------- 1 | STEP?=3 2 | N?=9 3 | T?=4 4 | 5 | includes=-I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal 6 | defines=-D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -DUNIT_TEST -DUNITTEST_CORRUPT 7 | libs=-lsodium -loprf -loprf-noiseXK 8 | src=../../dkg-vss.c ../../dkg.c ../../toprf-update.c ../toprf-update.c ../../mpmult.c ../../utils.c ../../toprf.c 9 | 10 | SODIUM_NEWER_THAN_1_0_18 := $(shell pkgconf --atleast-version=1.0.19 libsodium; echo $$?) 11 | ifeq ($(SODIUM_NEWER_THAN_1_0_18),1) 12 | includes+= -I../../aux_ 13 | src+=../../aux_/kdf_hkdf_sha256.c 14 | else 15 | defines+= -DHAVE_SODIUM_HKDF=1 16 | endif 17 | 18 | in/tc0: fuzz-dump 19 | ./fuzz-dump $(N) $(T) $(STEP) in/tc0 20 | 21 | in/tc0p: fuzz-dump-peer 22 | ./fuzz-dump-peer $(N) $(T) $(STEP) in/tc0p 23 | 24 | fuzz-dump: $(src) 25 | gcc $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -DFUZZ_DUMP -DUNITTEST $(includes) $(defines) $(LDFLAGS) $(libs) -fno-omit-frame-pointer 26 | 27 | fuzz-dump-peer: $(src) 28 | gcc $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -DFUZZ_DUMP -DFUZZ_PEER -DUNITTEST $(includes) $(defines) $(LDFLAGS) $(libs) -fno-omit-frame-pointer 29 | 30 | fuzz-complog: $(src) 31 | AFL_USE_ASAN=1 AFL_LLVM_CMPLOG=1 afl-clang-lto -O2 -march=native -o $@ $^ -DUNITTEST $(includes) $(defines) $(libs) -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 32 | 33 | fuzz-complog-peer: $(src) 34 | AFL_USE_ASAN=1 AFL_LLVM_CMPLOG=1 afl-clang-lto -O2 -march=native -o $@ $^ -DFUZZ_PEER -DUNITTEST $(includes) $(defines) $(libs) -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 35 | 36 | fuzz-bin-asan: $(src) 37 | AFL_USE_ASAN=1 afl-clang-lto -O2 -march=native -o $@ $^ -DUNITTEST $(includes) $(defines) $(libs) -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 38 | 39 | fuzz-bin-asan-peer: $(src) 40 | AFL_USE_ASAN=1 afl-clang-lto -O2 -march=native -o $@ $^ -DFUZZ_PEER -DUNITTEST $(includes) $(defines) $(libs) -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 41 | 42 | fuzz-bin: $(src) 43 | afl-clang-lto -o $@ $^ -DUNITTEST $(includes) $(defines) $(libs) -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 44 | 45 | fuzz-bin-peer: $(src) 46 | afl-clang-lto -o $@ $^ -DFUZZ_PEER -DUNITTEST $(includes) $(defines) $(libs) -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 47 | 48 | fuzz-asan: in/tc0 fuzz-bin fuzz-bin-asan fuzz-complog 49 | afl-fuzz -c ./fuzz-complog -i in -o out -- ./fuzz-bin-asan $(N) $(T) $(STEP) 50 | 51 | fuzz-asan-peer: in/tc0p fuzz-bin-peer fuzz-bin-asan-peer fuzz-complog-peer 52 | afl-fuzz -c ./fuzz-complog-peer -i in -o out -- ./fuzz-bin-asan-peer $(N) $(T) $(STEP) 53 | 54 | fuzz: in/tc0 fuzz-bin fuzz-bin-asan fuzz-complog 55 | afl-fuzz -c ./fuzz-complog -i in -o out -- ./fuzz-bin $(N) $(T) $(STEP) 56 | 57 | fuzz-peer: in/tc0p fuzz-bin-peer fuzz-bin-asan-peer fuzz-complog-peer 58 | afl-fuzz -c ./fuzz-complog-peer -i in -o out -- ./fuzz-bin-peer $(N) $(T) $(STEP) 59 | 60 | clean: 61 | rm -rf fuzz-complog fuzz-bin fuzz-dump in/* out fuzz-bin-asan-peer fuzz-bin-peer fuzz-complog-peer fuzz-dump-peer 62 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/krml/internal/debug.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 2 | Licensed under the Apache 2.0 License. */ 3 | 4 | #ifndef __KRML_DEBUG_H 5 | #define __KRML_DEBUG_H 6 | 7 | #include 8 | 9 | #include "krml/internal/target.h" 10 | 11 | /******************************************************************************/ 12 | /* Debugging helpers - intended only for KaRaMeL developers */ 13 | /******************************************************************************/ 14 | 15 | /* In support of "-wasm -d force-c": we might need this function to be 16 | * forward-declared, because the dependency on WasmSupport appears very late, 17 | * after SimplifyWasm, and sadly, after the topological order has been done. */ 18 | void WasmSupport_check_buffer_size(uint32_t s); 19 | 20 | /* A series of GCC atrocities to trace function calls (karamel's [-d c-calls] 21 | * option). Useful when trying to debug, say, Wasm, to compare traces. */ 22 | /* clang-format off */ 23 | #ifdef __GNUC__ 24 | #define KRML_FORMAT(X) _Generic((X), \ 25 | uint8_t : "0x%08" PRIx8, \ 26 | uint16_t: "0x%08" PRIx16, \ 27 | uint32_t: "0x%08" PRIx32, \ 28 | uint64_t: "0x%08" PRIx64, \ 29 | int8_t : "0x%08" PRIx8, \ 30 | int16_t : "0x%08" PRIx16, \ 31 | int32_t : "0x%08" PRIx32, \ 32 | int64_t : "0x%08" PRIx64, \ 33 | default : "%s") 34 | 35 | #define KRML_FORMAT_ARG(X) _Generic((X), \ 36 | uint8_t : X, \ 37 | uint16_t: X, \ 38 | uint32_t: X, \ 39 | uint64_t: X, \ 40 | int8_t : X, \ 41 | int16_t : X, \ 42 | int32_t : X, \ 43 | int64_t : X, \ 44 | default : "unknown") 45 | /* clang-format on */ 46 | 47 | # define KRML_DEBUG_RETURN(X) \ 48 | ({ \ 49 | __auto_type _ret = (X); \ 50 | KRML_HOST_PRINTF("returning: "); \ 51 | KRML_HOST_PRINTF(KRML_FORMAT(_ret), KRML_FORMAT_ARG(_ret)); \ 52 | KRML_HOST_PRINTF(" \n"); \ 53 | _ret; \ 54 | }) 55 | #endif 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/noise_xk/include/Noise_XK.h: -------------------------------------------------------------------------------- 1 | /** This file was automatically generated */ 2 | 3 | 4 | #ifndef __Noise_XK_H 5 | #define __Noise_XK_H 6 | #include 7 | #include "krml/internal/target.h" 8 | #include "krml/internal/types.h" 9 | 10 | #ifndef WITH_HACL 11 | #include 12 | #else // WITH_SODIUM 13 | #include "Hacl.h" 14 | #endif // WITH_SODIUM 15 | 16 | #define Noise_XK_CSuccess 0 17 | #define Noise_XK_CIncorrect_transition 1 18 | #define Noise_XK_CPremessage 2 19 | #define Noise_XK_CNo_key 3 20 | #define Noise_XK_CAlready_key 4 21 | #define Noise_XK_CRs_rejected_by_policy 5 22 | #define Noise_XK_CRs_not_certified 6 23 | #define Noise_XK_CAlready_peer 7 24 | #define Noise_XK_CPeer_conflict 8 25 | #define Noise_XK_CUnknown_peer_id 9 26 | #define Noise_XK_CInput_size 10 27 | #define Noise_XK_CDH_error 11 28 | #define Noise_XK_CDecrypt_error 12 29 | #define Noise_XK_CSaturated_nonce 13 30 | #define Noise_XK_CEphemeral_generation 14 31 | #define Noise_XK_CSecurity_level 15 32 | 33 | typedef uint8_t Noise_XK_error_code; 34 | 35 | bool Noise_XK_lbytes_eq(uint32_t len, uint8_t *b1, uint8_t *b2); 36 | 37 | typedef struct Noise_XK_sized_buffer_s 38 | { 39 | uint32_t size; 40 | uint8_t *buffer; 41 | } 42 | Noise_XK_sized_buffer; 43 | 44 | uint64_t Noise_XK_bytes_to_nonce(uint8_t *n8); 45 | 46 | #define Noise_XK_Handshake_read 0 47 | #define Noise_XK_Handshake_write 1 48 | #define Noise_XK_Transport 2 49 | 50 | typedef uint8_t Noise_XK_status; 51 | 52 | typedef uint8_t *Noise_XK_noise_string; 53 | 54 | typedef Noise_XK_noise_string *Noise_XK_hstring; 55 | 56 | Noise_XK_error_code Noise_XK_dh_secret_to_public(uint8_t *dest, uint8_t *priv); 57 | 58 | Noise_XK_error_code Noise_XK_dh(uint8_t *dest, uint8_t *priv, uint8_t *pub); 59 | 60 | void 61 | Noise_XK_aead_encrypt( 62 | uint8_t *key, 63 | uint64_t nonce, 64 | uint32_t aad_len, 65 | uint8_t *aad, 66 | uint32_t plen, 67 | uint8_t *plain, 68 | uint8_t *cipher 69 | ); 70 | 71 | Noise_XK_error_code 72 | Noise_XK_aead_decrypt( 73 | uint8_t *key, 74 | uint64_t nonce, 75 | uint32_t aad_len, 76 | uint8_t *aad, 77 | uint32_t plen, 78 | uint8_t *plain, 79 | uint8_t *cipher 80 | ); 81 | 82 | void Noise_XK_hash(uint8_t *output, uint32_t inlen, uint8_t *input); 83 | 84 | void Noise_XK_mix_hash(uint8_t *hash1, uint32_t inlen, uint8_t *input); 85 | 86 | void 87 | Noise_XK_hmac(uint8_t *output, uint32_t keylen, uint8_t *key, uint32_t datalen, uint8_t *data); 88 | 89 | void 90 | Noise_XK_kdf( 91 | uint8_t *hash1, 92 | uint32_t keylen, 93 | uint8_t *key, 94 | uint8_t *dst1, 95 | uint8_t *dst2, 96 | uint8_t *dst3 97 | ); 98 | 99 | void Noise_XK_mix_psk(uint8_t *psk, uint8_t *st_cs_k, uint8_t *st_ck, uint8_t *st_h); 100 | 101 | void 102 | Noise_XK_encrypt_and_hash( 103 | uint32_t msg_len, 104 | uint8_t *msg, 105 | uint8_t *cipher, 106 | uint8_t *st_cs_k, 107 | uint8_t *st_h, 108 | uint64_t nonce 109 | ); 110 | 111 | Noise_XK_error_code 112 | Noise_XK_decrypt_and_hash( 113 | uint32_t msg_len, 114 | uint8_t *msg, 115 | uint8_t *cipher, 116 | uint8_t *st_cs_k, 117 | uint8_t *st_h, 118 | uint64_t nonce 119 | ); 120 | 121 | Noise_XK_error_code 122 | Noise_XK_mix_dh(uint8_t *sec, uint8_t *pub, uint8_t *cipher_key, uint8_t *ck, uint8_t *hash1); 123 | 124 | 125 | #define __Noise_XK_H_DEFINED 126 | #endif 127 | -------------------------------------------------------------------------------- /src/tests/toprf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../oprf.h" 5 | #include "../toprf.h" 6 | 7 | int main(void) { 8 | // setup 9 | // todo use dkg 10 | const unsigned peers = 3, threshold = 2; 11 | uint8_t k[crypto_core_ristretto255_SCALARBYTES]; 12 | crypto_core_ristretto255_scalar_random(k); 13 | // split k into shares 14 | uint8_t shares[peers][TOPRF_Share_BYTES]; 15 | toprf_create_shares(k, peers, threshold, shares); 16 | 17 | // start the OPRF 18 | const uint8_t password[8]="password"; 19 | uint8_t r[crypto_core_ristretto255_SCALARBYTES]; 20 | uint8_t alpha[crypto_core_ristretto255_BYTES]; 21 | // we blind once 22 | if(oprf_Blind(password, sizeof password, r, alpha)) return 1; 23 | // until here all is like with the non-threshold version 24 | 25 | // calculate points of shares 26 | // this really happens at each peer separately 27 | uint8_t xresps[peers][TOPRF_Part_BYTES]; 28 | for(size_t i=0;i 8 | #include 9 | #include 10 | #include 11 | 12 | /* Types which are either abstract, meaning that have to be implemented in C, or 13 | * which are models, meaning that they are swapped out at compile-time for 14 | * hand-written C types (in which case they're marked as noextract). */ 15 | 16 | typedef uint64_t FStar_UInt64_t, FStar_UInt64_t_; 17 | typedef int64_t FStar_Int64_t, FStar_Int64_t_; 18 | typedef uint32_t FStar_UInt32_t, FStar_UInt32_t_; 19 | typedef int32_t FStar_Int32_t, FStar_Int32_t_; 20 | typedef uint16_t FStar_UInt16_t, FStar_UInt16_t_; 21 | typedef int16_t FStar_Int16_t, FStar_Int16_t_; 22 | typedef uint8_t FStar_UInt8_t, FStar_UInt8_t_; 23 | typedef int8_t FStar_Int8_t, FStar_Int8_t_; 24 | 25 | /* Only useful when building krmllib, because it's in the dependency graph of 26 | * FStar.Int.Cast. */ 27 | typedef uint64_t FStar_UInt63_t, FStar_UInt63_t_; 28 | typedef int64_t FStar_Int63_t, FStar_Int63_t_; 29 | 30 | typedef double FStar_Float_float; 31 | typedef uint32_t FStar_Char_char; 32 | typedef FILE *FStar_IO_fd_read, *FStar_IO_fd_write; 33 | 34 | typedef void *FStar_Dyn_dyn; 35 | 36 | typedef const char *C_String_t, *C_String_t_, *C_Compat_String_t, *C_Compat_String_t_; 37 | 38 | typedef int exit_code; 39 | typedef FILE *channel; 40 | 41 | typedef unsigned long long TestLib_cycles; 42 | 43 | typedef uint64_t FStar_Date_dateTime, FStar_Date_timeSpan; 44 | 45 | /* Now Prims.string is no longer illegal with the new model in LowStar.Printf; 46 | * it's operations that produce Prims_string which are illegal. Bring the 47 | * definition into scope by default. */ 48 | typedef const char *Prims_string; 49 | 50 | #if (defined(_MSC_VER) && defined(_M_X64) && !defined(__clang__)) 51 | #define IS_MSVC64 1 52 | #endif 53 | 54 | /* This code makes a number of assumptions and should be refined. In particular, 55 | * it assumes that: any non-MSVC amd64 compiler supports int128. Maybe it would 56 | * be easier to just test for defined(__SIZEOF_INT128__) only? */ 57 | #if (defined(__x86_64__) || \ 58 | defined(__x86_64) || \ 59 | defined(__aarch64__) || \ 60 | (defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)) || \ 61 | defined(__s390x__) || \ 62 | (defined(_MSC_VER) && defined(_M_X64) && defined(__clang__)) || \ 63 | (defined(__mips__) && defined(__LP64__)) || \ 64 | (defined(__riscv) && __riscv_xlen == 64) || \ 65 | defined(__SIZEOF_INT128__)) 66 | #define HAS_INT128 1 67 | #endif 68 | 69 | /* The uint128 type is a special case since we offer several implementations of 70 | * it, depending on the compiler and whether the user wants the verified 71 | * implementation or not. */ 72 | #if !defined(KRML_VERIFIED_UINT128) && defined(IS_MSVC64) 73 | # include 74 | typedef __m128i FStar_UInt128_uint128; 75 | #elif !defined(KRML_VERIFIED_UINT128) && defined(HAS_INT128) 76 | typedef unsigned __int128 FStar_UInt128_uint128; 77 | #else 78 | typedef struct FStar_UInt128_uint128_s { 79 | uint64_t low; 80 | uint64_t high; 81 | } FStar_UInt128_uint128; 82 | #endif 83 | 84 | /* The former is defined once, here (otherwise, conflicts for test-c89. The 85 | * latter is for internal use. */ 86 | typedef FStar_UInt128_uint128 FStar_UInt128_t, uint128_t; 87 | 88 | #include "krml/lowstar_endianness.h" 89 | 90 | #endif 91 | 92 | /* Avoid a circular loop: if this header is included via FStar_UInt8_16_32_64, 93 | * then don't bring the uint128 definitions into scope. */ 94 | #ifndef __FStar_UInt_8_16_32_64_H 95 | 96 | #if !defined(KRML_VERIFIED_UINT128) && defined(IS_MSVC64) 97 | #include "fstar_uint128_msvc.h" 98 | #elif !defined(KRML_VERIFIED_UINT128) && defined(HAS_INT128) 99 | #include "fstar_uint128_gcc64.h" 100 | #else 101 | #include "FStar_UInt128_Verified.h" 102 | #include "fstar_uint128_struct_endianness.h" 103 | #endif 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /src/tests/fuzz-tp-dkg/makefile: -------------------------------------------------------------------------------- 1 | STEP?=6 2 | N?=3 3 | T?=2 4 | 5 | #in/msg0: msg0 6 | # ./msg0 >in/msg0 7 | # 8 | #msg0: msg0.c 9 | # gcc -o msg0 msg0.c -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf 10 | # 11 | #peer-start: peer-start.c ../../tp-dkg.c 12 | # afl-clang-lto -std=c11 -o peer-start peer-start.c ../../tp-dkg.c -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK 13 | # 14 | #fuzz-ps: peer-star 15 | # afl-fuzz -i in -o out ./peer-start 16 | 17 | in/tc0: fuzz-dump 18 | ./fuzz-dump $(N) $(T) $(STEP) in/tc0 19 | 20 | in/tc0p: fuzz-dump-peer 21 | ./fuzz-dump-peer $(N) $(T) $(STEP) in/tc0p 22 | 23 | fuzz-dump: ../../tp-dkg.c ../tp-dkg.c 24 | gcc $(CPPFLAGS) $(CFLAGS) -g -o fuzz-dump ../../tp-dkg.c ../tp-dkg.c -DFUZZ_DUMP -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM $(LDFLAGS) -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer 25 | 26 | fuzz-dump-peer: ../../tp-dkg.c ../tp-dkg.c 27 | gcc $(CPPFLAGS) $(CFLAGS) -g -o fuzz-dump-peer ../../tp-dkg.c ../tp-dkg.c -DFUZZ_DUMP -DFUZZ_PEER -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM $(LDFLAGS) -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer 28 | 29 | fuzz-complog: ../../tp-dkg.c ../tp-dkg.c 30 | AFL_USE_ASAN=1 AFL_LLVM_CMPLOG=1 afl-clang-lto -o fuzz-complog ../../tp-dkg.c ../tp-dkg.c -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 31 | 32 | fuzz-complog-peer: ../../tp-dkg.c ../tp-dkg.c 33 | AFL_USE_ASAN=1 AFL_LLVM_CMPLOG=1 afl-clang-lto -o fuzz-complog-peer ../../tp-dkg.c ../tp-dkg.c -DFUZZ_PEER -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 34 | 35 | fuzz-bin-asan: ../../tp-dkg.c ../tp-dkg.c 36 | AFL_USE_ASAN=1 afl-clang-lto -o fuzz-bin-asan ../../tp-dkg.c ../tp-dkg.c -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 37 | 38 | fuzz-bin-asan-peer: ../../tp-dkg.c ../tp-dkg.c 39 | AFL_USE_ASAN=1 afl-clang-lto -o fuzz-bin-asan-peer ../../tp-dkg.c ../tp-dkg.c -DFUZZ_PEER -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 40 | 41 | fuzz-bin: ../../tp-dkg.c ../tp-dkg.c 42 | afl-clang-lto -o fuzz-bin ../../tp-dkg.c ../tp-dkg.c -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 43 | 44 | fuzz-bin-peer: ../../tp-dkg.c ../tp-dkg.c 45 | afl-clang-lto -o fuzz-bin-peer ../../tp-dkg.c ../tp-dkg.c -DFUZZ_PEER -DUNITTEST -I../.. -I../../noise_xk/include -I../../noise_xk/include/karmel -I../../noise_xk/include/karmel/minimal -D_BSD_SOURCE -D_DEFAULT_SOURCE -DWITH_SODIUM -lsodium -loprf -loprf-noiseXK -fno-omit-frame-pointer -fsanitize-memory-track-origins=2 46 | 47 | fuzz-asan: in/tc0 fuzz-bin fuzz-bin-asan fuzz-complog 48 | afl-fuzz -c ./fuzz-complog -i in -o out -- ./fuzz-bin-asan $(N) $(T) $(STEP) 49 | 50 | fuzz-asan-peer: in/tc0 fuzz-bin-peer fuzz-bin-asan-peer fuzz-complog-peer 51 | afl-fuzz -c ./fuzz-complog-peer -i in -o out -- ./fuzz-bin-asan-peer $(N) $(T) $(STEP) 52 | 53 | fuzz: in/tc0 fuzz-bin fuzz-bin-asan fuzz-complog 54 | afl-fuzz -c ./fuzz-complog -i in -o out -- ./fuzz-bin $(N) $(T) $(STEP) 55 | 56 | fuzz-peer: in/tc0p fuzz-bin-peer fuzz-bin-asan-peer fuzz-complog-peer 57 | afl-fuzz -c ./fuzz-complog-peer -i in -o out -- ./fuzz-bin-peer $(N) $(T) $(STEP) 58 | 59 | clean: 60 | rm -rf fuzz-complog fuzz-bin fuzz-dump in/* out 61 | -------------------------------------------------------------------------------- /python/examples/tpdkg_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Test for TP DKG wrapper of pyoprf/liboprf 5 | 6 | SPDX-FileCopyrightText: 2024, Marsiske Stefan 7 | SPDX-License-Identifier: LGPL-3.0-or-later 8 | 9 | Copyright (c) 2024, Marsiske Stefan. 10 | All rights reserved. 11 | 12 | This file is part of liboprf. 13 | 14 | liboprf is free software: you can redistribute it and/or 15 | modify it under the terms of the GNU Lesser General Public License 16 | as published by the Free Software Foundation, either version 3 of 17 | the License, or (at your option) any later version. 18 | 19 | liboprf is distributed in the hope that it will be 20 | useful, but WITHOUT ANY WARRANTY; without even the implied 21 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 22 | See the GNU Lesser General Public License for more details. 23 | 24 | You should have received a copy of the GNU Lesser General Public License 25 | along with liboprf. If not, see . 26 | 27 | """ 28 | 29 | import pyoprf, pysodium, ctypes 30 | 31 | n = 5 32 | t = 3 33 | ts_epsilon = 5 34 | 35 | # enable verbose logging for tp-dkg 36 | libc = ctypes.cdll.LoadLibrary('libc.so.6') 37 | cstderr = ctypes.c_void_p.in_dll(libc, 'stderr') 38 | log_file = ctypes.c_void_p.in_dll(pyoprf.liboprf,'log_file') 39 | log_file.value = cstderr.value 40 | 41 | # create some long-term keypairs 42 | peer_lt_pks = [] 43 | peer_lt_sks = [] 44 | for _ in range(n): 45 | pk, sk = pysodium.crypto_sign_keypair() 46 | peer_lt_pks.append(pk) 47 | peer_lt_sks.append(sk) 48 | 49 | # initialize the TP and get the first message 50 | tp, msg0 = pyoprf.tpdkg_start_tp(n, t, ts_epsilon, "pyoprf tpdkg test", peer_lt_pks) 51 | 52 | print(f"n: {pyoprf.tpdkg_tpstate_n(tp)}, t: {pyoprf.tpdkg_tpstate_t(tp)}, sid: {bytes(c for c in pyoprf.tpdkg_tpstate_sessionid(tp)).hex()}") 53 | 54 | # initialize all peers with the 1st message from TP 55 | 56 | peers=[] 57 | for i in range(n): 58 | peer = pyoprf.tpdkg_peer_start(ts_epsilon, peer_lt_sks[i], msg0) 59 | peers.append(peer) 60 | 61 | for i in range(n): 62 | assert(pyoprf.tpdkg_peerstate_sessionid(peers[i]) == pyoprf.tpdkg_tpstate_sessionid(tp)) 63 | assert(peer_lt_sks[i] == pyoprf.tpdkg_peerstate_lt_sk(peers[i])) 64 | 65 | peer_msgs = [] 66 | while pyoprf.tpdkg_tp_not_done(tp): 67 | ret, sizes = pyoprf.tpdkg_tp_input_sizes(tp) 68 | # peer_msgs = (recv(size) for size in sizes) 69 | msgs = b''.join(peer_msgs) 70 | 71 | cur_step = pyoprf.tpdkg_tpstate_step(tp) 72 | try: 73 | tp_out = pyoprf.tpdkg_tp_next(tp, msgs) 74 | #print(f"tp: msg[{tp[0].step}]: {tp_out.raw.hex()}") 75 | except Exception as e: 76 | cheaters, cheats = pyoprf.tpdkg_get_cheaters(tp) 77 | print(f"Warning during the distributed key generation the peers misbehaved: {sorted(cheaters)}") 78 | for k, v in cheats: 79 | print(f"\tmisbehaving peer: {k} was caught: {v}") 80 | raise ValueError(f"{e} | tp step {cur_step}") 81 | 82 | peer_msgs = [] 83 | while(len(b''.join(peer_msgs))==0 and pyoprf.tpdkg_peer_not_done(peers[0])): 84 | for i in range(n): 85 | if(len(tp_out)>0): 86 | msg = pyoprf.tpdkg_tp_peer_msg(tp, tp_out, i) 87 | #print(f"tp -> peer[{i+1}] {msg.hex()}") 88 | else: 89 | msg = '' 90 | out = pyoprf.tpdkg_peer_next(peers[i], msg) 91 | if(len(out)>0): 92 | peer_msgs.append(out) 93 | #print(f"peer[{i+1}] -> tp {peer_msgs[-1].hex()}") 94 | tp_out = '' 95 | 96 | # we are done, let's check the shares 97 | 98 | shares = [pyoprf.tpdkg_peerstate_share(peers[i]) for i in range(n)] 99 | for i, share in enumerate(shares): 100 | print(f"share[{i+1}] {share.hex()}") 101 | 102 | v0 = pyoprf.thresholdmult([bytes([i+1])+pysodium.crypto_scalarmult_ristretto255_base(shares[i][1:]) for i in (0,1,2)]) 103 | v1 = pyoprf.thresholdmult([bytes([i+1])+pysodium.crypto_scalarmult_ristretto255_base(shares[i][1:]) for i in (2,0,3)]) 104 | assert v0 == v1 105 | v2 = pyoprf.thresholdmult([bytes([i+1])+pysodium.crypto_scalarmult_ristretto255_base(shares[i][1:]) for i in (2,1,4)]) 106 | assert v0 == v2 107 | 108 | secret = pyoprf.dkg_reconstruct(shares[:t]) 109 | #print("secret", secret.hex()) 110 | assert v0 == pysodium.crypto_scalarmult_ristretto255_base(secret) 111 | 112 | # clean up allocated buffers 113 | for i in range(n): 114 | pyoprf.tpdkg_peer_free(peers[i]) 115 | -------------------------------------------------------------------------------- /src/aux_/kdf_hkdf_sha256.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "sodium/crypto_auth_hmacsha256.h" 5 | #include "sodium/crypto_kdf.h" 6 | #include "crypto_kdf_hkdf_sha256.h" 7 | #include "sodium/randombytes.h" 8 | #include "sodium/utils.h" 9 | 10 | int 11 | crypto_kdf_hkdf_sha256_extract_init(crypto_kdf_hkdf_sha256_state *state, 12 | const unsigned char *salt, size_t salt_len) 13 | { 14 | return crypto_auth_hmacsha256_init(&state->st, salt, salt_len); 15 | } 16 | 17 | int 18 | crypto_kdf_hkdf_sha256_extract_update(crypto_kdf_hkdf_sha256_state *state, 19 | const unsigned char *ikm, size_t ikm_len) 20 | { 21 | return crypto_auth_hmacsha256_update(&state->st, ikm, ikm_len); 22 | } 23 | 24 | int 25 | crypto_kdf_hkdf_sha256_extract_final(crypto_kdf_hkdf_sha256_state *state, 26 | unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES]) 27 | { 28 | crypto_auth_hmacsha256_final(&state->st, prk); 29 | sodium_memzero(state, sizeof *state); 30 | 31 | return 0; 32 | } 33 | 34 | int 35 | crypto_kdf_hkdf_sha256_extract( 36 | unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES], 37 | const unsigned char *salt, size_t salt_len, const unsigned char *ikm, 38 | size_t ikm_len) 39 | { 40 | crypto_kdf_hkdf_sha256_state state; 41 | 42 | crypto_kdf_hkdf_sha256_extract_init(&state, salt, salt_len); 43 | crypto_kdf_hkdf_sha256_extract_update(&state, ikm, ikm_len); 44 | 45 | return crypto_kdf_hkdf_sha256_extract_final(&state, prk); 46 | } 47 | 48 | void 49 | crypto_kdf_hkdf_sha256_keygen(unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES]) 50 | { 51 | randombytes_buf(prk, crypto_kdf_hkdf_sha256_KEYBYTES); 52 | } 53 | 54 | int 55 | crypto_kdf_hkdf_sha256_expand(unsigned char *out, size_t out_len, 56 | const char *ctx, size_t ctx_len, 57 | const unsigned char prk[crypto_kdf_hkdf_sha256_KEYBYTES]) 58 | { 59 | crypto_auth_hmacsha256_state st; 60 | unsigned char tmp[crypto_auth_hmacsha256_BYTES]; 61 | size_t i; 62 | size_t left; 63 | unsigned char counter = 1U; 64 | 65 | if (out_len > crypto_kdf_hkdf_sha256_BYTES_MAX) { 66 | errno = EINVAL; 67 | return -1; 68 | } 69 | for (i = (size_t) 0U; i + crypto_auth_hmacsha256_BYTES <= out_len; 70 | i += crypto_auth_hmacsha256_BYTES) { 71 | crypto_auth_hmacsha256_init(&st, prk, crypto_kdf_hkdf_sha256_KEYBYTES); 72 | if (i != (size_t) 0U) { 73 | crypto_auth_hmacsha256_update(&st, 74 | &out[i - crypto_auth_hmacsha256_BYTES], 75 | crypto_auth_hmacsha256_BYTES); 76 | } 77 | crypto_auth_hmacsha256_update(&st, 78 | (const unsigned char *) ctx, ctx_len); 79 | crypto_auth_hmacsha256_update(&st, &counter, (size_t) 1U); 80 | crypto_auth_hmacsha256_final(&st, &out[i]); 81 | counter++; 82 | } 83 | if ((left = out_len & (crypto_auth_hmacsha256_BYTES - 1U)) != (size_t) 0U) { 84 | crypto_auth_hmacsha256_init(&st, prk, crypto_kdf_hkdf_sha256_KEYBYTES); 85 | if (i != (size_t) 0U) { 86 | crypto_auth_hmacsha256_update(&st, 87 | &out[i - crypto_auth_hmacsha256_BYTES], 88 | crypto_auth_hmacsha256_BYTES); 89 | } 90 | crypto_auth_hmacsha256_update(&st, 91 | (const unsigned char *) ctx, ctx_len); 92 | crypto_auth_hmacsha256_update(&st, &counter, (size_t) 1U); 93 | crypto_auth_hmacsha256_final(&st, tmp); 94 | memcpy(&out[i], tmp, left); 95 | sodium_memzero(tmp, sizeof tmp); 96 | } 97 | sodium_memzero(&st, sizeof st); 98 | 99 | return 0; 100 | } 101 | 102 | size_t 103 | crypto_kdf_hkdf_sha256_keybytes(void) 104 | { 105 | return crypto_kdf_hkdf_sha256_KEYBYTES; 106 | } 107 | 108 | size_t 109 | crypto_kdf_hkdf_sha256_bytes_min(void) 110 | { 111 | return crypto_kdf_hkdf_sha256_BYTES_MIN; 112 | } 113 | 114 | size_t 115 | crypto_kdf_hkdf_sha256_bytes_max(void) 116 | { 117 | return crypto_kdf_hkdf_sha256_BYTES_MAX; 118 | } 119 | 120 | size_t crypto_kdf_hkdf_sha256_statebytes(void) 121 | { 122 | return sizeof(crypto_kdf_hkdf_sha256_state); 123 | } 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # liboprf 2 | 3 | ## Overview 4 | 5 | liboprf is a library for Oblivious Pseudorandom Functions (OPRFs), including support for Threshold OPRFs. It is designed to make advanced cryptographic protocols easy to integrate across applications. 6 | 7 | ## What is an OPRF? 8 | 9 | An Oblivious Pseudorandom Function (OPRF) is a two-party cryptographic primitive involving a sender and receiver who jointly compute a function, `F`, in such a way that: 10 | - The sender holds a secret key `k` 11 | - The receiver provides an input `x` 12 | - The receiver learns `F(k, x)` but nothing about `k` 13 | - The sender learns nothing about `x` or `F(k, x)` 14 | 15 | OPRFs are the foundation for many privacy-preserving protocols including: 16 | - Password-based authentication without exposing passwords 17 | - Private set intersection, which allows two parties to find the intersection of their private sets without revealing the full sets 18 | - Privacy-preserving information retrieval, allowing users to get specific information from a database without revealing what information is being retrieved 19 | 20 | ## Features 21 | 22 | ### Basic OPRF 23 | liboprf implements the basic OPRF(ristretto255, SHA-512) variant from the [IRTF CFRG Draft](https://github.com/cfrg/draft-irtf-cfrg-voprf/), "Oblivious Pseudorandom Functions (OPRFs) using Prime-Order Groups". 24 | 25 | ### Threshold OPRF 26 | liboprf implements a threshold OPRF variant based on [Krawczyk et al. (2017)](https://eprint.iacr.org/2017/363) which is compatible with the [CFRG OPRF(ristretto255, SHA-512) variant](#basic-oprf). A threshold implementation distributes trust among multiple servers, requiring a minimum number (threshold) to cooperate for operation. It uses Distributed Key Generation (DKG) protocols, as described below, to distribute secret key shares among multiple servers. 27 | 28 | ### 3hashTDH 29 | This library also implements the 3hashTDH from [Gu, Jarecki, Kedzior, Nazarian, Xu (2024)](https://eprint.iacr.org/2024/1455) "Threshold PAKE with Security against Compromise of all Servers". This implementation is compatible with the aforementioned [IRTF CFRG OPRF(ristretto255, SHA-512)](#basic-oprf) variant. 30 | 31 | ### Distributed Key Generation (DKG) 32 | For the [threshold OPRF](#threshold-oprf), liboprf provides: 33 | 34 | - **Trusted Party DKG**: An implementation based on Joint Feldman DKG (JF-DKG) from the paper "[Secure Distributed Key Generation for Discrete-Log Based Cryptosystems](https://link.springer.com/article/10.1007/s00145-006-0347-3)" by R. Gennaro, S. Jarecki, Hugo Krawczyk & T. Rabin. 35 | 36 | - **Semi-trusted DKG**: Implements Fast-Track Joint Verifiable Secret Sharing (FT-Joint-DL-VSS) described in R. Gennaro, M. O. Rabin, and T. Rabin, "[Simplified VSS and fast-track multiparty computations with applications to threshold cryptography](https://dl.acm.org/doi/10.1145/277697.277716)" In B. A. Coan and Y. Afek, editors, 17th ACM PODC, pages 101–111. ACM, June/July 1998. 37 | 38 | ### Threshold OPRF Updates 39 | To update a threshold OPRF instantiation, liboprf contains multi-party multiplication described in R. Gennaro, M. O. Rabin, and T. Rabin, "[Simplified VSS and fast-track multiparty computations with applications to threshold cryptography](https://dl.acm.org/doi/10.1145/277697.277716)" In B. A. Coan and Y. Afek, editors, 17th ACM PODC, pages 101–111. ACM, June/July 1998. 40 | 41 | ## Installation 42 | 43 | ### Dependencies 44 | - **libsodium**: You must install [libsodium](https://github.com/jedisct1/libsodium) first. libsodium is a cryptographic library that provides a range of cryptographic operations including encryption, decryption, digital signatures, and secure password hashing. 45 | - **pkgconf**: Needed for building the library. 46 | 47 | ### Building from source 48 | 49 | ```bash 50 | git clone https://github.com/stef/liboprf.git 51 | cd liboprf/src 52 | make 53 | sudo make install 54 | ``` 55 | 56 | ### Python Wrapper 57 | A Python wrapper, `pyoprf`, is provided. Look at [its README](/python/README.md) for installation and usage instructions. 58 | 59 | 60 | ## Funding 61 | 62 | This project is funded through [NGI0 Entrust](https://nlnet.nl/entrust), a fund 63 | established by [NLnet](https://nlnet.nl) with financial support from the 64 | European Commission's [Next Generation Internet](https://ngi.eu) program. Learn 65 | more at the [NLnet project page](https://nlnet.nl/project/ThresholdOPRF). 66 | 67 | [NLnet foundation logo](https://nlnet.nl) 68 | [NGI Zero Logo](https://nlnet.nl/entrust) 69 | -------------------------------------------------------------------------------- /misc/attack.c: -------------------------------------------------------------------------------- 1 | // # SPDX-FileCopyrightText: 2024, Marsiske Stefan 2 | // # SPDX-License-Identifier: GPL-3.0-or-later 3 | 4 | // build with 5 | // $ gcc -Wall -O3 attack.c -o attack -loprf -lsodium 6 | // then run: 7 | // $ ./attack test 8 | 9 | #include // memcmp 10 | #include // f?printf 11 | #include // uint8_t 12 | #include // va_list, va_start, va_end 13 | #include 14 | #include 15 | 16 | static const uint8_t k[crypto_core_ristretto255_SCALARBYTES] = {1}; 17 | 18 | void dump(const uint8_t *p, const size_t len, const char* msg, ...) { 19 | va_list args; 20 | va_start(args, msg); 21 | vfprintf(stderr,msg, args); 22 | va_end(args); 23 | fprintf(stderr,"\t"); 24 | for(size_t i=0;ibeta\n", exec); 31 | printf("usage: cat rwd | %s guess password\n", exec); 32 | return ret; 33 | } 34 | 35 | static int tamper(const uint8_t alpha[crypto_core_ristretto255_BYTES], 36 | uint8_t beta[crypto_core_ristretto255_BYTES]) { 37 | puts("tampering"); 38 | dump(k, sizeof k, "k"); 39 | if(0!=crypto_scalarmult_ristretto255(beta, k, alpha)) { 40 | fputs("failed to tamper with k\nabort.\n", stderr); 41 | return 1; 42 | } 43 | return 0; 44 | } 45 | 46 | static int guess(uint8_t rwd[OPRF_BYTES], const uint8_t *pwd, const size_t pwd_len) { 47 | //fputs("[1] hashing to group...", stdout); 48 | uint8_t h0pwd[crypto_core_ristretto255_BYTES]={0}; 49 | if(0!=voprf_hash_to_group(pwd, pwd_len, h0pwd)) { 50 | fputs("failed to hash to group\nabort\n", stderr); 51 | return 1; 52 | } 53 | 54 | // tamper(h0pwd, h0pwd) 55 | 56 | uint8_t rwd_[OPRF_BYTES]; 57 | if(0!=oprf_Finalize(pwd, pwd_len, h0pwd, rwd_)) { 58 | fputs("failed to finalize OPRF\nabort\n", stderr); 59 | return 1; 60 | } 61 | 62 | if(memcmp(rwd,rwd_, OPRF_BYTES)!=0) return -1; 63 | 64 | return 0; 65 | } 66 | 67 | static int test(void) { 68 | // regular OPRF flow on the client 69 | const uint8_t password[] = "Exploitability of this is low, OPRFs are still cool"; 70 | uint8_t alpha[crypto_core_ristretto255_BYTES]={0}; 71 | uint8_t r[crypto_core_ristretto255_SCALARBYTES]={0}; 72 | if(0!=oprf_Blind(password, sizeof password, r, alpha)) { 73 | fputs("failed to blind password\nabort\n", stderr); 74 | return 1; 75 | } 76 | //dump(r, sizeof r, "r"); 77 | 78 | // we tamper with beta 79 | uint8_t beta[crypto_core_ristretto255_BYTES]={0}; 80 | dump(alpha, sizeof alpha, "alpha"); 81 | tamper(alpha, beta); 82 | dump(beta, sizeof beta, "beta"); 83 | 84 | // regular OPRF flow on the client 85 | uint8_t N[crypto_core_ristretto255_BYTES]={0}; 86 | int x = oprf_Unblind(r, beta, N); 87 | if(0!=x) { 88 | fputs("failed to unblind beta\nabort\n", stderr); 89 | return 1; 90 | } 91 | uint8_t rwd[OPRF_BYTES]; 92 | if(0!=oprf_Finalize(password, sizeof password, N, rwd)) { 93 | fputs("failed to finalize OPRF\nabort\n", stderr); 94 | return 1; 95 | } 96 | 97 | // we "intercept" the oprf output and guess candidate inputs 98 | 99 | fprintf(stderr, "guess(\"%s\") = %d\n", password, guess(rwd, password, sizeof password-1)); 100 | fprintf(stderr, "guess(\"%s\") = %d\n", password, guess(rwd, password, sizeof password)); 101 | 102 | return 0; 103 | } 104 | 105 | int main(const int argc, const char** argv) { 106 | if(argc<2) { 107 | return usage(argv[0], 0); 108 | } 109 | if(memcmp(argv[1],"tamper",7)==0) { 110 | uint8_t alpha[crypto_core_ristretto255_BYTES]; 111 | if(fread(alpha, 1, 32, stdin) != 32) { 112 | fputs("failed to read point\nabort.\n", stderr); 113 | return 1; 114 | } 115 | 116 | uint8_t beta[crypto_core_ristretto255_BYTES]; 117 | if(0!=tamper(alpha, beta)) { 118 | return 1; 119 | }; 120 | fwrite(beta, 1, sizeof beta, stdout); 121 | return 0; 122 | } 123 | if(memcmp(argv[1],"guess",6)==0) { 124 | if(argc<3) { 125 | return usage(argv[0], 1); 126 | } 127 | uint8_t rwd[OPRF_BYTES]; 128 | if(fread(rwd, 1, OPRF_BYTES, stdin) != OPRF_BYTES) { 129 | fputs("failed to read rwd\nabort.\n", stderr); 130 | return 1; 131 | } 132 | return guess(rwd, (uint8_t*) argv[2], strlen(argv[2])); 133 | } 134 | if(memcmp(argv[1],"test",5)==0) { 135 | return test(); 136 | } 137 | 138 | return usage(argv[0], 1); 139 | } 140 | -------------------------------------------------------------------------------- /src/tests/testvecs2h.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json, sys 4 | from itertools import zip_longest # for Python 3.x 5 | 6 | def split_by_n(iterable, n): 7 | return zip_longest(*[iter(iterable)]*n, fillvalue='') 8 | 9 | # src: ht 10 | vectors = """ 11 | { 12 | "groupDST": "48617368546f47726f75702d4f50524656312d002d72697374726574746f3235352d534841353132", 13 | "hash": "SHA512", 14 | "identifier": "ristretto255-SHA512", 15 | "keyInfo": "74657374206b6579", 16 | "mode": 0, 17 | "seed": "a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3", 18 | "skSm": "5ebcea5ee37023ccb9fc2d2019f9d7737be85591ae8652ffa9ef0f4d37063b0e", 19 | "vectors": [ 20 | { 21 | "Batch": 1, 22 | "Blind": "64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f6706", 23 | "BlindedElement": "609a0ae68c15a3cf6903766461307e5c8bb2f95e7e6550e1ffa2dc99e412803c", 24 | "EvaluationElement": "7ec6578ae5120958eb2db1745758ff379e77cb64fe77b0b2d8cc917ea0869c7e", 25 | "Input": "00", 26 | "Output": "527759c3d9366f277d8c6020418d96bb393ba2afb20ff90df23fb7708264e2f3ab9135e3bd69955851de4b1f9fe8a0973396719b7912ba9ee8aa7d0b5e24bcf6" 27 | }, 28 | { 29 | "Batch": 1, 30 | "Blind": "64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f6706", 31 | "BlindedElement": "da27ef466870f5f15296299850aa088629945a17d1f5b7f5ff043f76b3c06418", 32 | "EvaluationElement": "b4cbf5a4f1eeda5a63ce7b77c7d23f461db3fcab0dd28e4e17cecb5c90d02c25", 33 | "Input": "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a", 34 | "Output": "f4a74c9c592497375e796aa837e907b1a045d34306a749db9f34221f7e750cb4f2a6413a6bf6fa5e19ba6348eb673934a722a7ede2e7621306d18951e7cf2c73" 35 | } 36 | ] 37 | } 38 | """ 39 | 40 | def toC(k, v): 41 | print(f"#define {k.lower()}_len {len(v)//2}") 42 | print( 43 | f"const uint8_t {k.lower()}[{k.lower()}_len] = {{\n %s}};\n" % ",\n ".join( 44 | (", ".join((c for c in line if c)) for line in split_by_n( 45 | (f"0x{x[0]}{x[1]}" for x in split_by_n(v,2)) 46 | ,8)) 47 | )) 48 | 49 | vex = json.loads(vectors) 50 | print("// this file has been automatically generated using testvecs2h.py") 51 | 52 | if sys.argv[1] == 'cfrg_oprf_test_vectors.h': 53 | # run this if there is a change in the values of the test vectors 54 | # ./testvecs2h.py >cfrg_oprf_test_vectors.h 55 | 56 | print("#ifndef cfrg_test_vectors_h\n#define cfrg_test_vectors_h\n") 57 | print("#include \n") 58 | 59 | toC("sks", vex['skSm']) 60 | 61 | for tc in range(2): 62 | for k, v in vex['vectors'][tc].items(): 63 | if k == "Batch": continue 64 | print(f"#define tc{tc}_{k.lower()}_len {len(v)//2}") 65 | print( 66 | f"const uint8_t tc{tc}_{k.lower()}[tc{tc}_{k.lower()}_len] = {{\n %s}};\n" % ",\n ".join( 67 | (", ".join((c for c in line if c)) for line in split_by_n( 68 | (f"0x{x[0]}{x[1]}" for x in split_by_n(v,2)) 69 | ,8)) 70 | )) 71 | 72 | elif sys.argv[1] == 'cfrg_oprf_test_vector_decl.h': 73 | # only run this code below if there is a change in the keys of the test vectors 74 | # ./testvecs2h.py >cfrg_oprf_test_vector_decl.h 75 | 76 | print("#ifndef cfrg_test_vector_decl_h\n#define cfrg_test_vector_decl_h\n") 77 | print("#include \n") 78 | for tc in range(2): 79 | for k, v in vex['vectors'][tc].items(): 80 | if k == "Batch": continue 81 | print(f"#define tc{tc}_{k.lower()}_len {len(v)//2}") 82 | print(f"extern const uint8_t tc{tc}_{k.lower()}[tc{tc}_{k.lower()}_len];\n") 83 | else: 84 | sys.exit(-1) 85 | 86 | print(""" 87 | #if(TC==0) 88 | #define input tc0_input 89 | #define input_len tc0_input_len 90 | #define blind_registration tc0_blind 91 | #define blind_login tc0_blind 92 | #define blind_len tc0_blind_len 93 | #define blinded_element tc0_blindedelement 94 | #define blindedelement_len tc0_blindedelement_len 95 | #define evaluationelement tc0_evaluationelement 96 | #define evaluationelement_len tc0_evaluationelement_len 97 | #define output tc0_output 98 | #define output_len tc0_output_len 99 | #else 100 | #define input tc1_input 101 | #define input_len tc1_input_len 102 | #define blind_registration tc1_blind 103 | #define blind_login tc1_blind 104 | #define blind_len tc1_blind_len 105 | #define blinded_element tc1_blindedelement 106 | #define blindedelement_len tc1_blindedelement_len 107 | #define evaluationelement tc1_evaluationelement 108 | #define evaluationelement_len tc1_evaluationelement_len 109 | #define output tc1_output 110 | #define output_len tc1_output_len 111 | #endif""") 112 | print("#endif") 113 | -------------------------------------------------------------------------------- /src/tests/dkg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "dkg.h" 3 | #include "toprf.h" 4 | #include "utils.h" 5 | 6 | extern int liboprf_debug; 7 | 8 | typedef struct { 9 | uint8_t index; 10 | uint8_t value[crypto_core_ristretto255_BYTES]; 11 | } __attribute((packed)) TOPRF_Part; 12 | 13 | static void topart(TOPRF_Part *r, const TOPRF_Share *s) { 14 | r->index=s->index; 15 | crypto_scalarmult_ristretto255_base(r->value, s->value); 16 | } 17 | 18 | static int test_dkg_start(const uint8_t n, 19 | const uint8_t a[crypto_core_ristretto255_SCALARBYTES], 20 | const TOPRF_Share shares[n]) { 21 | const size_t response_len = 3; 22 | uint8_t responses[response_len][TOPRF_Part_BYTES]; 23 | uint8_t result[crypto_scalarmult_ristretto255_BYTES]; 24 | uint8_t v[crypto_scalarmult_ristretto255_BYTES]; 25 | 26 | topart((TOPRF_Part *) responses[0], &shares[4]); 27 | topart((TOPRF_Part *) responses[1], &shares[2]); 28 | topart((TOPRF_Part *) responses[2], &shares[0]); 29 | 30 | if(toprf_thresholdmult(response_len, responses, result)) return 1; 31 | 32 | crypto_scalarmult_ristretto255_base(v, a); 33 | 34 | if(memcmp(v,result,sizeof v)!=0) { 35 | fprintf(stderr,"\e[0;31mmeh!\e[0m\n"); 36 | dump(v,sizeof v, "v"); 37 | dump(result,sizeof v, "r"); 38 | return 1; 39 | } 40 | return 0; 41 | } 42 | 43 | static int test_dkg_finish(const uint8_t n, const TOPRF_Share shares[n]) { 44 | const size_t response_len = 3; 45 | uint8_t responses[response_len][TOPRF_Part_BYTES]; 46 | uint8_t v0[crypto_scalarmult_ristretto255_BYTES]={0}; 47 | uint8_t v1[crypto_scalarmult_ristretto255_BYTES]={0}; 48 | 49 | //dump((uint8_t*) &shares[4], sizeof(TOPRF_Share), "&shares[4][0] "); 50 | topart((TOPRF_Part *) responses[0], &shares[4]); 51 | topart((TOPRF_Part *) responses[1], &shares[2]); 52 | topart((TOPRF_Part *) responses[2], &shares[0]); 53 | //topart((TOPRF_Part *) responses[3], &shares[1][0]); 54 | //topart((TOPRF_Part *) responses[4], &shares[3][0]); 55 | if(toprf_thresholdmult(response_len, responses, v0)) return 1; 56 | dump(v0,sizeof v0, "v0 "); 57 | 58 | topart((TOPRF_Part *) responses[0], &shares[3]); 59 | topart((TOPRF_Part *) responses[1], &shares[1]); 60 | topart((TOPRF_Part *) responses[2], &shares[0]); 61 | //topart((TOPRF_Part *) responses[3], &shares[2][0]); 62 | //topart((TOPRF_Part *) responses[4], &shares[4][0]); 63 | if(toprf_thresholdmult(response_len, responses, v1)) return 1; 64 | dump(v1,sizeof v1, "v1 "); 65 | 66 | if(memcmp(v0,v1,sizeof v1)!=0) { 67 | fprintf(stderr,"\e[0;31mfailed to verify shares from dkg_finish!\e[0m\n"); 68 | return 1; 69 | } 70 | return 0; 71 | } 72 | 73 | int main(void) { 74 | liboprf_debug = 1; 75 | uint8_t n=5, threshold=3; 76 | uint8_t commitments[n][threshold][crypto_core_ristretto255_BYTES]; 77 | TOPRF_Share shares[n][n]; 78 | 79 | for(int i=0;i 19 | #include 20 | #include "dkg.h" 21 | 22 | /** 23 | * @brief Generator for the VSS scheme 24 | * 25 | * This generator was derived by hashing the fixed string 26 | * "DKG Generator H on ristretto255" into the Ristretto255 group. 27 | */ 28 | extern const uint8_t H[crypto_core_ristretto255_BYTES]; 29 | 30 | /** 31 | * @brief Creates shares of a secret with commitments 32 | * 33 | * @param[in] n The number of participants 34 | * @param[in] threshold The minimum number of shares needed to reconstruct the secret 35 | * @param[in] secret The secret to share 36 | * @param[out] commitments Array of commitments to shares, one for each participant 37 | * @param[out] shares Array of generated shares (each has secret and blinding shares) 38 | * @param[out] blind The blinding factor used for the commitment to the secret 39 | * 40 | * @return 0 on success, non-zero on error 41 | */ 42 | int dkg_vss_share(const uint8_t n, 43 | const uint8_t threshold, 44 | const uint8_t secret[crypto_core_ristretto255_SCALARBYTES], 45 | uint8_t commitments[n][crypto_core_ristretto255_BYTES], 46 | TOPRF_Share shares[n][2], 47 | uint8_t blind[crypto_core_ristretto255_SCALARBYTES]); 48 | 49 | /** 50 | * @brief Verifies that a share matches its commitment 51 | * 52 | * @param[in] commitment The commitment to verify against 53 | * @param[in] share The received secret share and its blinding share 54 | * 55 | * @return 0 if the commitment is valid, non-zero otherwise 56 | */ 57 | int dkg_vss_verify_commitment(const uint8_t commitment[crypto_core_ristretto255_BYTES], 58 | const TOPRF_Share share[2]); 59 | 60 | /** 61 | * @brief Finalizes the DKG VSS protocol for a participant 62 | * 63 | * Combines valid shares from qualified participants to compute the final 64 | * secret share and its corresponding commitment. 65 | * 66 | * @param[in] n The number of participants 67 | * @param[in] qual Array of indices of qualified participants 68 | * @param[in] shares Array of shares received from all participants 69 | * @param[in] self The index of the current participant 70 | * @param[out] share The final secret share and its blinding share 71 | * @param[out] commitment The commitment to the final share 72 | * 73 | * @return 0 on success, non-zero on error 74 | */ 75 | int dkg_vss_finish(const uint8_t n, 76 | const uint8_t qual[n], 77 | const TOPRF_Share shares[n][2], 78 | const uint8_t self, 79 | TOPRF_Share share[2], 80 | uint8_t commitment[crypto_core_ristretto255_BYTES]); 81 | 82 | /** 83 | * @brief Reconstructs a secret from a set of shares 84 | * 85 | * Given at least `t` valid shares, reconstructs the original secret 86 | * and optionally its blinding share. 87 | * 88 | * @param[in] t The threshold (minimum number of shares needed to reconstruct the secret) 89 | * @param[in] x The point at which to evaluate the polynomial (0 for the secret) 90 | * @param[in] shares_len The number of shares provided 91 | * @param[in] shares Array of shares provided for reconstruction 92 | * @param[in] commitments Array of commitments to verify shares 93 | * @param[out] result Buffer to store the reconstructed secret 94 | * @param[out] blind optional Buffer to store the reconstructed blinding factor skipped if NULL 95 | * 96 | * @return 0 on success, non-zero on error 97 | */ 98 | int dkg_vss_reconstruct(const uint8_t t, 99 | const uint8_t x, 100 | const size_t shares_len, 101 | const TOPRF_Share shares[shares_len][2], 102 | const uint8_t commitments[shares_len][crypto_scalarmult_ristretto255_BYTES], 103 | uint8_t result[crypto_scalarmult_ristretto255_SCALARBYTES], 104 | uint8_t blind[crypto_scalarmult_ristretto255_SCALARBYTES]); 105 | 106 | /** 107 | * @brief Creates a Pedersen commitment to a value 108 | * 109 | * Computes C = g^a · h^r where `g` is the base point of the curve, 110 | * `h` is the fixed generator `H`, `a` is the value being committed to, 111 | * and `r` is the blinding factor. 112 | * 113 | * @param[in] a The value to commit to 114 | * @param[in] r The blinding factor 115 | * @param[out] C The resulting commitment 116 | * 117 | * @return 0 on success, non-zero on error 118 | */ 119 | int dkg_vss_commit(const uint8_t a[crypto_core_ristretto255_SCALARBYTES], 120 | const uint8_t r[crypto_core_ristretto255_SCALARBYTES], 121 | uint8_t C[crypto_core_ristretto255_BYTES]); 122 | 123 | #endif // DKG_VSS_H 124 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/minimal/fstar_uint128_gcc64.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 2 | Licensed under the Apache 2.0 License. */ 3 | 4 | /******************************************************************************/ 5 | /* Machine integers (128-bit arithmetic) */ 6 | /******************************************************************************/ 7 | 8 | /* This header contains two things. 9 | * 10 | * First, an implementation of 128-bit arithmetic suitable for 64-bit GCC and 11 | * Clang, i.e. all the operations from FStar.UInt128. 12 | * 13 | * Second, 128-bit operations from C.Endianness (or LowStar.Endianness), 14 | * suitable for any compiler and platform (via a series of ifdefs). This second 15 | * part is unfortunate, and should be fixed by moving {load,store}128_{be,le} to 16 | * FStar.UInt128 to avoid a maze of preprocessor guards and hand-written code. 17 | * */ 18 | 19 | /* This file is used for both the minimal and generic krmllib distributions. As 20 | * such, it assumes that the machine integers have been bundled the exact same 21 | * way in both cases. */ 22 | 23 | #ifndef FSTAR_UINT128_GCC64 24 | #define FSTAR_UINT128_GCC64 25 | 26 | #include "FStar_UInt128.h" 27 | #include "FStar_UInt_8_16_32_64.h" 28 | #include "LowStar_Endianness.h" 29 | 30 | /* GCC + using native unsigned __int128 support */ 31 | 32 | inline static uint128_t load128_le(uint8_t *b) { 33 | uint128_t l = (uint128_t)load64_le(b); 34 | uint128_t h = (uint128_t)load64_le(b + 8); 35 | return (h << 64 | l); 36 | } 37 | 38 | inline static void store128_le(uint8_t *b, uint128_t n) { 39 | store64_le(b, (uint64_t)n); 40 | store64_le(b + 8, (uint64_t)(n >> 64)); 41 | } 42 | 43 | inline static uint128_t load128_be(uint8_t *b) { 44 | uint128_t h = (uint128_t)load64_be(b); 45 | uint128_t l = (uint128_t)load64_be(b + 8); 46 | return (h << 64 | l); 47 | } 48 | 49 | inline static void store128_be(uint8_t *b, uint128_t n) { 50 | store64_be(b, (uint64_t)(n >> 64)); 51 | store64_be(b + 8, (uint64_t)n); 52 | } 53 | 54 | inline static uint128_t FStar_UInt128_add(uint128_t x, uint128_t y) { 55 | return x + y; 56 | } 57 | 58 | inline static uint128_t FStar_UInt128_mul(uint128_t x, uint128_t y) { 59 | return x * y; 60 | } 61 | 62 | inline static uint128_t FStar_UInt128_add_mod(uint128_t x, uint128_t y) { 63 | return x + y; 64 | } 65 | 66 | inline static uint128_t FStar_UInt128_sub(uint128_t x, uint128_t y) { 67 | return x - y; 68 | } 69 | 70 | inline static uint128_t FStar_UInt128_sub_mod(uint128_t x, uint128_t y) { 71 | return x - y; 72 | } 73 | 74 | inline static uint128_t FStar_UInt128_logand(uint128_t x, uint128_t y) { 75 | return x & y; 76 | } 77 | 78 | inline static uint128_t FStar_UInt128_logor(uint128_t x, uint128_t y) { 79 | return x | y; 80 | } 81 | 82 | inline static uint128_t FStar_UInt128_logxor(uint128_t x, uint128_t y) { 83 | return x ^ y; 84 | } 85 | 86 | inline static uint128_t FStar_UInt128_lognot(uint128_t x) { 87 | return ~x; 88 | } 89 | 90 | inline static uint128_t FStar_UInt128_shift_left(uint128_t x, uint32_t y) { 91 | return x << y; 92 | } 93 | 94 | inline static uint128_t FStar_UInt128_shift_right(uint128_t x, uint32_t y) { 95 | return x >> y; 96 | } 97 | 98 | inline static uint128_t FStar_UInt128_uint64_to_uint128(uint64_t x) { 99 | return (uint128_t)x; 100 | } 101 | 102 | inline static uint64_t FStar_UInt128_uint128_to_uint64(uint128_t x) { 103 | return (uint64_t)x; 104 | } 105 | 106 | inline static uint128_t FStar_UInt128_mul_wide(uint64_t x, uint64_t y) { 107 | return ((uint128_t) x) * y; 108 | } 109 | 110 | inline static uint128_t FStar_UInt128_eq_mask(uint128_t x, uint128_t y) { 111 | uint64_t mask = 112 | FStar_UInt64_eq_mask((uint64_t)(x >> 64), (uint64_t)(y >> 64)) & 113 | FStar_UInt64_eq_mask((uint64_t)x, (uint64_t)y); 114 | return ((uint128_t)mask) << 64 | mask; 115 | } 116 | 117 | inline static uint128_t FStar_UInt128_gte_mask(uint128_t x, uint128_t y) { 118 | uint64_t mask = 119 | (FStar_UInt64_gte_mask(x >> 64, y >> 64) & 120 | ~(FStar_UInt64_eq_mask(x >> 64, y >> 64))) | 121 | (FStar_UInt64_eq_mask(x >> 64, y >> 64) & FStar_UInt64_gte_mask((uint64_t)x, (uint64_t)y)); 122 | return ((uint128_t)mask) << 64 | mask; 123 | } 124 | 125 | inline static uint64_t FStar_UInt128___proj__Mkuint128__item__low(uint128_t x) { 126 | return (uint64_t) x; 127 | } 128 | 129 | inline static uint64_t FStar_UInt128___proj__Mkuint128__item__high(uint128_t x) { 130 | return (uint64_t) (x >> 64); 131 | } 132 | 133 | inline static uint128_t FStar_UInt128_add_underspec(uint128_t x, uint128_t y) { 134 | return x + y; 135 | } 136 | 137 | inline static uint128_t FStar_UInt128_sub_underspec(uint128_t x, uint128_t y) { 138 | return x - y; 139 | } 140 | 141 | inline static bool FStar_UInt128_eq(uint128_t x, uint128_t y) { 142 | return x == y; 143 | } 144 | 145 | inline static bool FStar_UInt128_gt(uint128_t x, uint128_t y) { 146 | return x > y; 147 | } 148 | 149 | inline static bool FStar_UInt128_lt(uint128_t x, uint128_t y) { 150 | return x < y; 151 | } 152 | 153 | inline static bool FStar_UInt128_gte(uint128_t x, uint128_t y) { 154 | return x >= y; 155 | } 156 | 157 | inline static bool FStar_UInt128_lte(uint128_t x, uint128_t y) { 158 | return x <= y; 159 | } 160 | 161 | inline static uint128_t FStar_UInt128_mul32(uint64_t x, uint32_t y) { 162 | return (uint128_t) x * (uint128_t) y; 163 | } 164 | 165 | #endif 166 | -------------------------------------------------------------------------------- /src/tests/makefile: -------------------------------------------------------------------------------- 1 | CFLAGS?= -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \ 2 | -fstack-protector-strong -fasynchronous-unwind-tables -fpic \ 3 | -ftrapv -D_GLIBCXX_ASSERTIONS \ 4 | -Wl,-z,defs -Wl,-z,relro \ 5 | -Wl,-z,noexecstack -Wl,-z,now -fsanitize=signed-integer-overflow \ 6 | -fsanitize-undefined-trap-on-error 7 | CC?=gcc 8 | INCLUDES=-I.. -I../noise_xk/include -I../noise_xk/include/karmel/ -I../noise_xk/include/karmel/minimal/ 9 | 10 | ARCH := $(shell uname -m) 11 | ifeq ($(ARCH),x86_64) 12 | CFLAGS+=-fcf-protection=full 13 | endif 14 | ifeq ($(ARCH),parisc64) 15 | else ifeq ($(ARCH),parisc64) 16 | else 17 | CFLAGS+=-fstack-clash-protection 18 | endif 19 | 20 | SODIUM_NEWER_THAN_1_0_18 := $(shell pkgconf --atleast-version=1.0.19 libsodium; echo $$?) 21 | ifeq ($(SODIUM_NEWER_THAN_1_0_18),1) 22 | CFLAGS+= -I../aux_ 23 | EXTRA_SOURCES+= ../aux_/kdf_hkdf_sha256.c 24 | else 25 | CFLAGS+= -DHAVE_SODIUM_HKDF=1 26 | endif 27 | 28 | all: tv1 tv2 dkg toprf tp-dkg tp-dkg-corrupt mpmult stp-dkg stp-dkg-corrupt toprf-update toprf-update-corrupt 29 | 30 | tv1: test.c cfrg_oprf_test_vectors.h cfrg_oprf_test_vector_decl.h ../oprf.c ../utils.c 31 | $(CC) $(CPPFLAGS) $(CFLAGS) -Wall -g -o tv1 -DCFRG_TEST_VEC=1 -DCFRG_OPRF_TEST_VEC=1 -DTC=0 test.c ../oprf.c ../utils.c -lsodium 32 | 33 | tv2: test.c cfrg_oprf_test_vectors.h cfrg_oprf_test_vector_decl.h ../oprf.c ../utils.c 34 | $(CC) $(CPPFLAGS) $(CFLAGS) -Wall -g -o tv2 -DCFRG_TEST_VEC=1 -DCFRG_OPRF_TEST_VEC=1 -DTC=1 test.c ../oprf.c ../utils.c -lsodium 35 | 36 | toprf: toprf.c 37 | $(CC) $(CPPFLAGS) $(CFLAGS) -g -o toprf toprf.c ../toprf.c ../oprf.c $(EXTRA_SOURCES) -lsodium 38 | 39 | dkg: ../dkg.c ../utils.c dkg.c ../dkg.c ../utils.c ../toprf.c ../oprf.c 40 | $(CC) $(CPPFLAGS) $(CFLAGS) -g $(INCLUDES) -DUNIT_TEST -o dkg dkg.c ../dkg.c ../utils.c ../toprf.c ../oprf.c ../noise_xk/liboprf-noiseXK.a $(LDFLAGS) -lsodium 41 | 42 | tp-dkg: ../tp-dkg.c tp-dkg.c ../tp-dkg.c ../utils.c ../toprf.c ../oprf.c ../dkg.c 43 | $(CC) $(CPPFLAGS) $(CFLAGS) -D_DEFAULT_SOURCE -g -std=c11 $(INCLUDES) -DWITH_SODIUM -DUNITTEST -o tp-dkg tp-dkg.c ../tp-dkg.c ../utils.c ../toprf.c ../oprf.c ../dkg.c ../noise_xk/liboprf-noiseXK.a $(LDFLAGS) -lsodium 44 | 45 | tp-dkg-corrupt: ../tp-dkg.c tp-dkg.c ../tp-dkg.c ../utils.c ../toprf.c ../oprf.c ../dkg.c 46 | $(CC) $(CPPFLAGS) $(CFLAGS) -D_DEFAULT_SOURCE -g -std=c11 $(INCLUDES) -DWITH_SODIUM -DUNITTEST -DUNITTEST_CORRUPT -o tp-dkg-corrupt tp-dkg.c ../tp-dkg.c ../utils.c ../toprf.c ../oprf.c ../dkg.c ../noise_xk/liboprf-noiseXK.a $(LDFLAGS) -lsodium 47 | 48 | stp-dkg: ../dkg-vss.c ../dkg.c ../stp-dkg.c stp-dkg.c ../stp-dkg.h ../mpmult.c ../utils.c ../toprf.c ../oprf.c ../dkg.c 49 | $(CC) $(CPPFLAGS) $(CFLAGS) -Wall -g $(INCLUDES) -DUNIT_TEST -o stp-dkg stp-dkg.c ../dkg-vss.c ../mpmult.c ../utils.c ../toprf.c ../stp-dkg.c ../oprf.c ../dkg.c ../noise_xk/liboprf-noiseXK.a $(LDFLAGS) -lsodium 50 | 51 | stp-dkg-corrupt: ../dkg-vss.c ../dkg.c ../stp-dkg.c stp-dkg.c ../stp-dkg.h ../mpmult.c ../utils.c ../toprf.c ../oprf.c ../dkg.c 52 | $(CC) $(CPPFLAGS) $(CFLAGS) -Wall -g $(INCLUDES) -DUNIT_TEST -DUNITTEST_CORRUPT -o stp-dkg-corrupt stp-dkg.c ../dkg-vss.c ../mpmult.c ../utils.c ../toprf.c ../stp-dkg.c ../oprf.c ../dkg.c ../noise_xk/liboprf-noiseXK.a $(LDFLAGS) -lsodium 53 | 54 | mpmult: ../mpmult.c mpmult.c ../utils.c ../toprf.c ../dkg-vss.c ../oprf.c ../dkg.c 55 | $(CC) $(CPPFLAGS) $(CFLAGS) -Wall -g $(INCLUDES) -DUNIT_TEST -o mpmult mpmult.c ../mpmult.c ../utils.c ../toprf.c ../dkg-vss.c ../oprf.c ../dkg.c ../noise_xk/liboprf-noiseXK.a -lsodium 56 | 57 | update-poc: ../dkg-vss.c ../dkg.c update-poc.c 58 | $(CC) $(CPPFLAGS) $(CFLAGS) -Wall -g $(INCLUDES) -DUNIT_TEST -o update-poc update-poc.c ../dkg-vss.c ../utils.c ../toprf.c ../noise_xk/liboprf-noiseXK.a -lsodium 59 | 60 | ft-mult: ../dkg-vss.c ../dkg.c ft-mult.c ../toprf.c 61 | $(CC) $(CPPFLAGS) $(CFLAGS) -Wall -g $(INCLUDES) -DUNIT_TEST -o ft-mult ft-mult.c ../dkg-vss.c ../utils.c ../toprf.c ../noise_xk/liboprf-noiseXK.a -lsodium 62 | 63 | toprf-update: ../dkg-vss.c ../dkg.c ../toprf-update.c toprf-update.c ../toprf-update.h ../mpmult.c ../oprf.c ../dkg.c $(EXTRA_SOURCES) 64 | $(CC) $(CPPFLAGS) $(CFLAGS) -Wall -g $(INCLUDES) -DUNIT_TEST -o toprf-update toprf-update.c ../dkg-vss.c ../mpmult.c ../utils.c ../toprf.c ../toprf-update.c ../oprf.c ../dkg.c $(EXTRA_SOURCES) ../noise_xk/liboprf-noiseXK.a -lsodium 65 | 66 | toprf-update-corrupt: ../dkg-vss.c ../dkg.c ../toprf-update.c toprf-update.c ../toprf-update.h ../mpmult.c ../utils.c ../oprf.c ../dkg.c $(EXTRA_SOURCES) 67 | $(CC) $(CPPFLAGS) $(CFLAGS) -Wall -g $(INCLUDES) -DUNIT_TEST -DUNITTEST_CORRUPT -o toprf-update-corrupt toprf-update.c ../dkg-vss.c ../mpmult.c ../utils.c ../toprf.c ../toprf-update.c ../oprf.c ../dkg.c $(EXTRA_SOURCES) ../noise_xk/liboprf-noiseXK.a -lsodium 68 | 69 | allocations: allocations.c 70 | $(CC) $(CPPFLAGS) $(CFLAGS) -g -o allocations allocations.c -I.. -I../noise_xk/include -I../noise_xk/include/karmel/ -I../noise_xk/include/karmel/minimal -loprf -loprf-noiseXK 71 | 72 | cfrg_oprf_test_vectors.h: testvecs2h.py 73 | ./testvecs2h.py $@ >$@ 74 | 75 | cfrg_oprf_test_vector_decl.h: testvecs2h.py 76 | ./testvecs2h.py $@ >$@ 77 | 78 | tests: all 79 | ./dkg 80 | ./tv1 81 | ./tv2 82 | ./toprf 83 | (ulimit -s 66000; ./tp-dkg 3 2) 84 | (ulimit -s 66000; ./tp-dkg-corrupt 3 2 || exit 0) 85 | (ulimit -s 1966000; ./stp-dkg 9 4) 86 | (ulimit -s 1966000; ./stp-dkg-corrupt 9 4 || exit 0) 87 | (ulimit -s 1966000; ./toprf-update 9 4) 88 | (ulimit -s 1966000; ./toprf-update-corrupt 9 4) 89 | ./mpmult 90 | 91 | clean: 92 | rm -f cfrg_oprf_test_vector_decl.h cfrg_oprf_test_vectors.h tv1 tv2 tp-dkg dkg toprf mpmult stp-dkg-corrupt stp-dkg update-poc toprf-update toprf-update-corrupt 93 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | # pyoprf 2 | 3 | pyoprf offers Python bindings for the liboprf library, allowing integration of Oblivious Pseudorandom Functions (OPRFs) into Python applications. It provides access to the [features](../README.md#features) of the [liboprf](https://github.com/stef/liboprf) library. 4 | 5 | ## Installation 6 | 7 | ### Prerequisites 8 | 9 | - [liboprf](https://github.com/stef/liboprf): The core library 10 | - [libsodium](https://github.com/jedisct1/libsodium): Required dependency for liboprf 11 | - OpenSSL: For TLS connections between the participants 12 | 13 | ### Installing from PyPI 14 | 15 | ```bash 16 | pip install pyoprf 17 | ``` 18 | 19 | ### Installing from source 20 | 21 | ```bash 22 | git clone https://github.com/stef/liboprf.git 23 | cd liboprf/python 24 | pip install . 25 | ``` 26 | 27 | ## Usage 28 | 29 | For detailed usage examples, refer to the [`test.py`](./tests/test.py) file and the [`examples`](/examples) folder. 30 | 31 | ### Basic Example 32 | Imagine a scenario where a client wants to retrieve data from a server using a password, but doesn't want to reveal the actual password to the server: 33 | 34 | ```python 35 | import pyoprf 36 | 37 | # Basic OPRF evaluation process 38 | # Step 1: Client blinds the input value 39 | input_value = b"password123" 40 | blind_factor, blinded_input = pyoprf.blind(input_value) 41 | 42 | # Step 2: Server generates a key and evaluates the blinded input 43 | server_key = pyoprf.keygen() 44 | server_evaluation = pyoprf.evaluate(server_key, blinded_input) 45 | 46 | # Step 3: Client unblinds the server's response 47 | unblinded_result = pyoprf.unblind(blind_factor, server_evaluation) 48 | 49 | # Step 4: Client finalizes the OPRF computation 50 | final_result = pyoprf.finalize(input_value, unblinded_result) 51 | 52 | print(f"OPRF result: {final_result.hex()}") 53 | 54 | # Verify that repeated evaluations with the same key and input produce the same result 55 | blind_factor2, blinded_input2 = pyoprf.blind(input_value) 56 | server_evaluation2 = pyoprf.evaluate(server_key, blinded_input2) 57 | unblinded_result2 = pyoprf.unblind(blind_factor2, server_evaluation2) 58 | final_result2 = pyoprf.finalize(input_value, unblinded_result2) 59 | 60 | print(f"Verification result: {final_result2.hex()}") 61 | assert final_result == final_result2, "OPRF evaluations should be deterministic for the same input and key" 62 | 63 | # The `final_result` can be used as a key for encryption, authentication token, and more. 64 | # Only client can derive this value without the server learning the password or the final result. 65 | ``` 66 | 67 | ### Threshold Example 68 | Suppose you want to build a password authentication system that distributes trust across multiple servers, so no single server can learn a user's password. The library also supports threshold OPRFs, where multiple servers hold shares of a key: 69 | 70 | ```python 71 | import pyoprf 72 | 73 | # Setting up a threshold OPRF with 3 servers, threshold of 2 74 | # Server setup, which would happen on each server 75 | n = 3 # Total number of servers 76 | t = 2 # The minimum servers needed, also called the threshold 77 | 78 | # Generate a key 79 | key = pyoprf.keygen() 80 | 81 | # Create shares of the key for distributed evaluation 82 | shares = pyoprf.create_shares(key, n, t) 83 | 84 | # On client 85 | input_value = b"password123" 86 | blind_factor, blinded_input = pyoprf.blind(input_value) 87 | 88 | # Each server evaluates the input with its share 89 | evaluations = [] 90 | for i in range(n): 91 | # This evaluation happens on server i 92 | server_evaluation = pyoprf.evaluate(shares[i][1:], blinded_input) 93 | evaluations.append(shares[i][:1] + server_evaluation) 94 | 95 | # Client combines evaluations (need at least t of them) 96 | collected_evaluations = evaluations[:t] # Just use the first t evaluations 97 | combined = pyoprf.thresholdmult(collected_evaluations) 98 | 99 | # Client unblinds the combined result 100 | unblinded = pyoprf.unblind(blind_factor, combined) 101 | 102 | # Finalize to get the OPRF output 103 | final_result = pyoprf.finalize(input_value, unblinded) 104 | print(f"Threshold OPRF result: {final_result.hex()}") 105 | 106 | # Verify that it matches a direct evaluation with the key 107 | server_evaluation = pyoprf.evaluate(key, blinded_input) 108 | unblinded_direct = pyoprf.unblind(blind_factor, server_evaluation) 109 | direct_result = pyoprf.finalize(input_value, unblinded_direct) 110 | print(f"Direct OPRF result: {direct_result.hex()}") 111 | assert final_result == direct_result, "Threshold evaluation should match direct evaluation" 112 | ``` 113 | 114 | ## Troubleshooting 115 | 116 | If you encounter issues, first ensure that libsodium, liboprf and OpenSSL are properly installed. 117 | 118 | ### OpenSSL Header Issues 119 | 120 | If after installing OpenSSL, you get the error `'openssl/crypto.h' file not found`, you might need to provide OpenSSL headers to the compiler. For example, if OpenSSL was installed on Mac using Homebrew: 121 | ``` 122 | export CFLAGS="-I/opt/homebrew/opt/openssl@3/include" 123 | export LDFLAGS="-L/opt/homebrew/opt/openssl@3/lib" 124 | ``` 125 | 126 | ### Library Loading Issues 127 | 128 | When running Python code, you might encounter errors like: 129 | 130 | ``` 131 | OSError: liboprf.so.0: cannot open shared object file: No such file or directory 132 | OSError: liboprf-noiseXK.so.0: cannot open shared object file: No such file or directory 133 | ``` 134 | 135 | To fix this, you can try to install liboprf globally on your system. 136 | 137 | Either by using your distributions package manager: 138 | 139 | ```sh 140 | % sudo apt install liboprf0t64 141 | ``` 142 | 143 | Or install liboprf from source: 144 | 145 | ```sh 146 | cd /path/to/liboprf/src 147 | sudo PREFIX=/usr make install 148 | sudo ldconfig 149 | ``` 150 | 151 | Or by using environment variables, first create symbolic links: 152 | 153 | ```bash 154 | cd /path/to/liboprf/src 155 | ln -s liboprf.so liboprf.so.0 156 | cd noise_xk 157 | ln -s liboprf-noiseXK.so liboprf-noiseXK.so.0 158 | ``` 159 | 160 | Then when running your Python code, use the LD_LIBRARY_PATH environment variable: 161 | 162 | ```bash 163 | LD_LIBRARY_PATH=/path/to/liboprf/src:/path/to/liboprf/src/noise_xk python your_script.py 164 | ``` 165 | 166 | ## Documentation 167 | 168 | For more information on the underlying liboprf functionality, visit the [liboprf documentation](../README.md). 169 | 170 | ## License 171 | 172 | LGPLv3.0+ 173 | -------------------------------------------------------------------------------- /src/dkg-vss.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "toprf.h" 5 | #include "utils.h" 6 | #include "dkg.h" 7 | 8 | // nothing up my sleeve generator H, generated with: 9 | // hash_to_group((uint8_t*)"DKG Generator H on ristretto255", 32, H) 10 | const __attribute__((visibility("hidden"))) uint8_t H[crypto_core_ristretto255_BYTES]= { 11 | 0x66, 0x4e, 0x4c, 0xb5, 0x89, 0x0e, 0xb3, 0xe4, 12 | 0xc0, 0xd5, 0x48, 0x02, 0x74, 0x8a, 0xb2, 0x25, 13 | 0xf9, 0x73, 0xda, 0xe5, 0xc0, 0xef, 0xc1, 0x68, 14 | 0xf4, 0x4d, 0x1b, 0x60, 0x28, 0x97, 0x8f, 0x07}; 15 | 16 | int dkg_vss_commit(const uint8_t a[crypto_core_ristretto255_SCALARBYTES], 17 | const uint8_t r[crypto_core_ristretto255_SCALARBYTES], 18 | uint8_t C[crypto_core_ristretto255_BYTES]) { 19 | // compute commitments 20 | uint8_t X[crypto_core_ristretto255_BYTES]; 21 | uint8_t R[crypto_core_ristretto255_BYTES]; 22 | // x = g^a_ik 23 | crypto_scalarmult_ristretto255_base(X, a); 24 | // r = h^b_ik 25 | if(crypto_scalarmult_ristretto255(R, r, H)) return 1; 26 | // C_ik = x+r 27 | crypto_core_ristretto255_add(C,X,R); 28 | 29 | return 0; 30 | } 31 | 32 | int dkg_vss_share(const uint8_t n, 33 | const uint8_t threshold, 34 | const uint8_t secret[crypto_core_ristretto255_SCALARBYTES], 35 | uint8_t commitments[n][crypto_core_ristretto255_BYTES], 36 | TOPRF_Share shares[n][2], 37 | uint8_t blind[crypto_core_ristretto255_SCALARBYTES]) { 38 | if(threshold==0) return 1; 39 | uint8_t a[threshold][crypto_core_ristretto255_SCALARBYTES]; 40 | uint8_t b[threshold][crypto_core_ristretto255_SCALARBYTES]; 41 | if(secret!=NULL) memcpy(a[0],secret, crypto_core_ristretto255_SCALARBYTES); 42 | for(int k=0;kvalue, crypto_core_ristretto255_SCALARBYTES, "x[%d] ", self); 97 | //dump(x_i->value, crypto_core_ristretto255_SCALARBYTES, "x'[%d] ", self); 98 | if(0!=dkg_vss_commit(share[0].value, share[1].value, commitment)) return 1; 99 | return 0; 100 | } 101 | 102 | static void sort_shares(const int n, uint8_t arr[n], uint8_t indexes[n]) { 103 | for (uint8_t c = 1 ; c <= n - 1; c++) { 104 | uint8_t d = c, t, t1; 105 | while(d > 0 && arr[d] < arr[d-1]) { 106 | t = arr[d]; 107 | t1 = indexes[d]; 108 | arr[d] = arr[d-1]; 109 | indexes[d] = indexes[d-1]; 110 | arr[d-1] = t; 111 | indexes[d-1] = t1; 112 | d--; 113 | } 114 | } 115 | } 116 | 117 | int dkg_vss_reconstruct(const uint8_t t, 118 | const uint8_t x, 119 | const size_t shares_len, 120 | const TOPRF_Share shares[shares_len][2], 121 | const uint8_t commitments[shares_len][crypto_scalarmult_ristretto255_BYTES], 122 | uint8_t result[crypto_scalarmult_ristretto255_SCALARBYTES], 123 | uint8_t blind[crypto_scalarmult_ristretto255_SCALARBYTES]) { 124 | if(shares_len>128) return 1; 125 | uint8_t qual[t]; 126 | uint8_t indexes[t]; 127 | unsigned j=0; 128 | for(uint8_t i=0;i 11 | #include 12 | #include "krml/internal/compat.h" 13 | #include "krml/lowstar_endianness.h" 14 | #include "krml/internal/types.h" 15 | #include "krml/internal/target.h" 16 | 17 | extern krml_checked_int_t FStar_UInt64_n; 18 | 19 | extern bool FStar_UInt64_uu___is_Mk(uint64_t projectee); 20 | 21 | extern krml_checked_int_t FStar_UInt64___proj__Mk__item__v(uint64_t projectee); 22 | 23 | extern krml_checked_int_t FStar_UInt64_v(uint64_t x); 24 | 25 | extern uint64_t FStar_UInt64_uint_to_t(krml_checked_int_t x); 26 | 27 | extern uint64_t FStar_UInt64_zero; 28 | 29 | extern uint64_t FStar_UInt64_one; 30 | 31 | extern uint64_t FStar_UInt64_minus(uint64_t a); 32 | 33 | extern uint32_t FStar_UInt64_n_minus_one; 34 | 35 | static KRML_NOINLINE uint64_t FStar_UInt64_eq_mask(uint64_t a, uint64_t b) 36 | { 37 | uint64_t x = a ^ b; 38 | uint64_t minus_x = ~x + 1ULL; 39 | uint64_t x_or_minus_x = x | minus_x; 40 | uint64_t xnx = x_or_minus_x >> 63U; 41 | return xnx - 1ULL; 42 | } 43 | 44 | static KRML_NOINLINE uint64_t FStar_UInt64_gte_mask(uint64_t a, uint64_t b) 45 | { 46 | uint64_t x = a; 47 | uint64_t y = b; 48 | uint64_t x_xor_y = x ^ y; 49 | uint64_t x_sub_y = x - y; 50 | uint64_t x_sub_y_xor_y = x_sub_y ^ y; 51 | uint64_t q = x_xor_y | x_sub_y_xor_y; 52 | uint64_t x_xor_q = x ^ q; 53 | uint64_t x_xor_q_ = x_xor_q >> 63U; 54 | return x_xor_q_ - 1ULL; 55 | } 56 | 57 | extern Prims_string FStar_UInt64_to_string(uint64_t uu___); 58 | 59 | extern Prims_string FStar_UInt64_to_string_hex(uint64_t uu___); 60 | 61 | extern Prims_string FStar_UInt64_to_string_hex_pad(uint64_t uu___); 62 | 63 | extern uint64_t FStar_UInt64_of_string(Prims_string uu___); 64 | 65 | extern krml_checked_int_t FStar_UInt32_n; 66 | 67 | extern bool FStar_UInt32_uu___is_Mk(uint32_t projectee); 68 | 69 | extern krml_checked_int_t FStar_UInt32___proj__Mk__item__v(uint32_t projectee); 70 | 71 | extern krml_checked_int_t FStar_UInt32_v(uint32_t x); 72 | 73 | extern uint32_t FStar_UInt32_uint_to_t(krml_checked_int_t x); 74 | 75 | extern uint32_t FStar_UInt32_zero; 76 | 77 | extern uint32_t FStar_UInt32_one; 78 | 79 | extern uint32_t FStar_UInt32_minus(uint32_t a); 80 | 81 | extern uint32_t FStar_UInt32_n_minus_one; 82 | 83 | static KRML_NOINLINE uint32_t FStar_UInt32_eq_mask(uint32_t a, uint32_t b) 84 | { 85 | uint32_t x = a ^ b; 86 | uint32_t minus_x = ~x + 1U; 87 | uint32_t x_or_minus_x = x | minus_x; 88 | uint32_t xnx = x_or_minus_x >> 31U; 89 | return xnx - 1U; 90 | } 91 | 92 | static KRML_NOINLINE uint32_t FStar_UInt32_gte_mask(uint32_t a, uint32_t b) 93 | { 94 | uint32_t x = a; 95 | uint32_t y = b; 96 | uint32_t x_xor_y = x ^ y; 97 | uint32_t x_sub_y = x - y; 98 | uint32_t x_sub_y_xor_y = x_sub_y ^ y; 99 | uint32_t q = x_xor_y | x_sub_y_xor_y; 100 | uint32_t x_xor_q = x ^ q; 101 | uint32_t x_xor_q_ = x_xor_q >> 31U; 102 | return x_xor_q_ - 1U; 103 | } 104 | 105 | extern Prims_string FStar_UInt32_to_string(uint32_t uu___); 106 | 107 | extern Prims_string FStar_UInt32_to_string_hex(uint32_t uu___); 108 | 109 | extern Prims_string FStar_UInt32_to_string_hex_pad(uint32_t uu___); 110 | 111 | extern uint32_t FStar_UInt32_of_string(Prims_string uu___); 112 | 113 | extern krml_checked_int_t FStar_UInt16_n; 114 | 115 | extern bool FStar_UInt16_uu___is_Mk(uint16_t projectee); 116 | 117 | extern krml_checked_int_t FStar_UInt16___proj__Mk__item__v(uint16_t projectee); 118 | 119 | extern krml_checked_int_t FStar_UInt16_v(uint16_t x); 120 | 121 | extern uint16_t FStar_UInt16_uint_to_t(krml_checked_int_t x); 122 | 123 | extern uint16_t FStar_UInt16_zero; 124 | 125 | extern uint16_t FStar_UInt16_one; 126 | 127 | extern uint16_t FStar_UInt16_minus(uint16_t a); 128 | 129 | extern uint32_t FStar_UInt16_n_minus_one; 130 | 131 | static KRML_NOINLINE uint16_t FStar_UInt16_eq_mask(uint16_t a, uint16_t b) 132 | { 133 | uint16_t x = (uint32_t)a ^ (uint32_t)b; 134 | uint16_t minus_x = (uint32_t)~x + 1U; 135 | uint16_t x_or_minus_x = (uint32_t)x | (uint32_t)minus_x; 136 | uint16_t xnx = (uint32_t)x_or_minus_x >> 15U; 137 | return (uint32_t)xnx - 1U; 138 | } 139 | 140 | static KRML_NOINLINE uint16_t FStar_UInt16_gte_mask(uint16_t a, uint16_t b) 141 | { 142 | uint16_t x = a; 143 | uint16_t y = b; 144 | uint16_t x_xor_y = (uint32_t)x ^ (uint32_t)y; 145 | uint16_t x_sub_y = (uint32_t)x - (uint32_t)y; 146 | uint16_t x_sub_y_xor_y = (uint32_t)x_sub_y ^ (uint32_t)y; 147 | uint16_t q = (uint32_t)x_xor_y | (uint32_t)x_sub_y_xor_y; 148 | uint16_t x_xor_q = (uint32_t)x ^ (uint32_t)q; 149 | uint16_t x_xor_q_ = (uint32_t)x_xor_q >> 15U; 150 | return (uint32_t)x_xor_q_ - 1U; 151 | } 152 | 153 | extern Prims_string FStar_UInt16_to_string(uint16_t uu___); 154 | 155 | extern Prims_string FStar_UInt16_to_string_hex(uint16_t uu___); 156 | 157 | extern Prims_string FStar_UInt16_to_string_hex_pad(uint16_t uu___); 158 | 159 | extern uint16_t FStar_UInt16_of_string(Prims_string uu___); 160 | 161 | extern krml_checked_int_t FStar_UInt8_n; 162 | 163 | extern bool FStar_UInt8_uu___is_Mk(uint8_t projectee); 164 | 165 | extern krml_checked_int_t FStar_UInt8___proj__Mk__item__v(uint8_t projectee); 166 | 167 | extern krml_checked_int_t FStar_UInt8_v(uint8_t x); 168 | 169 | extern uint8_t FStar_UInt8_uint_to_t(krml_checked_int_t x); 170 | 171 | extern uint8_t FStar_UInt8_zero; 172 | 173 | extern uint8_t FStar_UInt8_one; 174 | 175 | extern uint8_t FStar_UInt8_minus(uint8_t a); 176 | 177 | extern uint32_t FStar_UInt8_n_minus_one; 178 | 179 | static KRML_NOINLINE uint8_t FStar_UInt8_eq_mask(uint8_t a, uint8_t b) 180 | { 181 | uint8_t x = (uint32_t)a ^ (uint32_t)b; 182 | uint8_t minus_x = (uint32_t)~x + 1U; 183 | uint8_t x_or_minus_x = (uint32_t)x | (uint32_t)minus_x; 184 | uint8_t xnx = (uint32_t)x_or_minus_x >> 7U; 185 | return (uint32_t)xnx - 1U; 186 | } 187 | 188 | static KRML_NOINLINE uint8_t FStar_UInt8_gte_mask(uint8_t a, uint8_t b) 189 | { 190 | uint8_t x = a; 191 | uint8_t y = b; 192 | uint8_t x_xor_y = (uint32_t)x ^ (uint32_t)y; 193 | uint8_t x_sub_y = (uint32_t)x - (uint32_t)y; 194 | uint8_t x_sub_y_xor_y = (uint32_t)x_sub_y ^ (uint32_t)y; 195 | uint8_t q = (uint32_t)x_xor_y | (uint32_t)x_sub_y_xor_y; 196 | uint8_t x_xor_q = (uint32_t)x ^ (uint32_t)q; 197 | uint8_t x_xor_q_ = (uint32_t)x_xor_q >> 7U; 198 | return (uint32_t)x_xor_q_ - 1U; 199 | } 200 | 201 | extern Prims_string FStar_UInt8_to_string(uint8_t uu___); 202 | 203 | extern Prims_string FStar_UInt8_to_string_hex(uint8_t uu___); 204 | 205 | extern Prims_string FStar_UInt8_to_string_hex_pad(uint8_t uu___); 206 | 207 | extern uint8_t FStar_UInt8_of_string(Prims_string uu___); 208 | 209 | typedef uint8_t FStar_UInt8_byte; 210 | 211 | 212 | #define __FStar_UInt_8_16_32_64_H_DEFINED 213 | #endif 214 | -------------------------------------------------------------------------------- /src/tests/allocations.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "stp-dkg.h" 4 | #include "toprf-update.h" 5 | #include "utils.h" 6 | 7 | static size_t stp_peer_ctx_size(const size_t n, const size_t t) { 8 | size_t ret = 0; 9 | uint8_t peerids[n][crypto_generichash_BYTES]; 10 | ret+=sizeof(peerids); 11 | Noise_XK_session_t *noise_outs[n]; 12 | ret+=sizeof(noise_outs); 13 | Noise_XK_session_t *noise_ins[n]; 14 | ret+=sizeof(noise_ins); 15 | TOPRF_Share dealer_shares[n][2]; 16 | ret+=sizeof(dealer_shares); 17 | uint8_t encrypted_shares[n][noise_xk_handshake3_SIZE + stp_dkg_encrypted_share_SIZE]; 18 | ret+=sizeof(encrypted_shares); 19 | uint8_t dealer_commitments[n*n][crypto_core_ristretto255_BYTES]; 20 | ret+=sizeof(dealer_commitments); 21 | uint8_t share_macs[n*n][crypto_auth_hmacsha256_BYTES]; 22 | ret+=sizeof(share_macs); 23 | uint8_t peer_k_commitments[n][crypto_core_ristretto255_BYTES]; 24 | ret+=sizeof(peer_k_commitments); 25 | uint8_t commitments_hashes[n][stp_dkg_commitment_HASHBYTES]; 26 | ret+=sizeof(commitments_hashes); 27 | uint16_t peer_dealer_share_complaints[n*n]; 28 | ret+=sizeof(peer_dealer_share_complaints); 29 | uint8_t peer_my_dealer_share_complaints[n]; 30 | ret+=sizeof(peer_my_dealer_share_complaints); 31 | uint64_t peer_last_ts[n]; 32 | ret+=sizeof(peer_last_ts); 33 | STP_DKG_Cheater peer_cheaters[t*t - 1]; 34 | ret+=sizeof(peer_cheaters); 35 | return ret; 36 | } 37 | 38 | static size_t toprf_update_ctx_size(const size_t n, const size_t t) { 39 | const uint8_t dealers = (t-1)*2 + 1; 40 | size_t ret = 0; 41 | 42 | TOPRF_Share k0_share[2] = {0}; 43 | ret+=sizeof k0_share; 44 | uint8_t k0_commitments[n][crypto_core_ristretto255_BYTES]; 45 | ret+=sizeof k0_commitments; 46 | ret+=sizeof k0_commitments; 47 | uint8_t kid[toprf_keyid_SIZE]; 48 | ret+=sizeof kid; 49 | uint8_t lt_pks[n+1][crypto_sign_PUBLICKEYBYTES]; 50 | ret+=sizeof lt_pks; 51 | uint8_t lt_sks[crypto_sign_SECRETKEYBYTES]; 52 | ret+=sizeof lt_sks; 53 | uint8_t peers_noise_pks[n][crypto_scalarmult_BYTES]; 54 | ret+=sizeof peers_noise_pks; 55 | uint8_t peers_noise_sks[crypto_scalarmult_SCALARBYTES]; 56 | ret+=sizeof peers_noise_sks; 57 | uint8_t pkid[toprf_keyid_SIZE]; 58 | ret+=sizeof pkid; 59 | uint8_t stp_ltpk[crypto_sign_PUBLICKEYBYTES]; 60 | ret+=sizeof stp_ltpk; 61 | Noise_XK_session_t *noise_outs[n]; 62 | ret+=sizeof noise_outs; 63 | Noise_XK_session_t *noise_ins[n]; 64 | ret+=sizeof noise_ins; 65 | TOPRF_Share pshares[n][2]; 66 | ret+=sizeof pshares; 67 | uint8_t p_commitments[n*n][crypto_core_ristretto255_BYTES]; 68 | ret+=sizeof p_commitments; 69 | uint8_t p_commitments_hashes[n][toprf_update_commitment_HASHBYTES]; 70 | ret+=sizeof p_commitments_hashes; 71 | uint8_t peers_p_share_macs[n*n][crypto_auth_hmacsha256_BYTES]; 72 | ret+=sizeof peers_p_share_macs; 73 | uint16_t peer_p_complaints[n*n]; 74 | ret+=sizeof peer_p_complaints; 75 | uint8_t peer_my_p_complaints[n]; 76 | ret+=sizeof peer_my_p_complaints; 77 | uint8_t encrypted_shares[n][noise_xk_handshake3_SIZE + toprf_update_encrypted_shares_SIZE]; 78 | ret+=sizeof encrypted_shares; 79 | uint64_t peer_last_ts[n]; 80 | ret+=sizeof peer_last_ts; 81 | uint8_t lambdas[dealers][crypto_core_ristretto255_SCALARBYTES]; 82 | ret+=sizeof lambdas; 83 | TOPRF_Share k0p_shares[dealers][2]; 84 | ret+=sizeof k0p_shares; 85 | uint8_t k0p_commitments[dealers*(n+1)][crypto_core_ristretto255_BYTES]; 86 | ret+=sizeof k0p_commitments; 87 | uint8_t zk_challenge_nonce_commitments[n][crypto_scalarmult_ristretto255_BYTES]; 88 | ret+=sizeof zk_challenge_nonce_commitments; 89 | uint8_t zk_challenge_nonces[n][2][crypto_scalarmult_ristretto255_SCALARBYTES]; 90 | ret+=sizeof zk_challenge_nonces; 91 | uint8_t zk_challenge_commitments[dealers][3][crypto_scalarmult_ristretto255_SCALARBYTES]; 92 | ret+=sizeof zk_challenge_commitments; 93 | uint8_t zk_challenge_e_i[dealers][crypto_scalarmult_ristretto255_SCALARBYTES]; 94 | ret+=sizeof zk_challenge_e_i; 95 | TOPRF_Update_Cheater peer_cheaters[n*n - 1]; 96 | ret+=sizeof peer_cheaters; 97 | return ret; 98 | } 99 | 100 | static void stp_dkg(void) { 101 | STP_DKG_PeerState ctx; 102 | ctx.share_complaints_len=0; 103 | for(ctx.t=2;ctx.t<64;ctx.t++) { 104 | printf("t=%2d\n", ctx.t); 105 | for(ctx.n=ctx.t+1;ctx.n<129;ctx.n++) { 106 | ctx.step=0; 107 | //ctx.share_complaints_len=ctx.t; 108 | //ctx.my_share_complaints_len=ctx.t-1; 109 | size_t itot=0, otot=0; 110 | int i=0; 111 | while(stp_dkg_peer_not_done(&ctx)) { 112 | const size_t out_size = stp_dkg_peer_output_size(&ctx); 113 | const size_t in_size = stp_dkg_peer_input_size(&ctx); 114 | if(itot> 10; 123 | 124 | if(total<16) printf(GREEN); 125 | else if(total>64) printf(RED); 126 | printf("n=%3d total: %7ldKB ctx size: %7ldKB max: %6ldKB/%6ldKB %d"NORMAL"\n", ctx.n, total, ctx_size >> 10, itot >> 10, otot >> 10, i); 127 | } 128 | } 129 | } 130 | 131 | static void toprf_update(void) { 132 | TOPRF_Update_PeerState ctx; 133 | ctx.p_complaints_len = 0; 134 | ctx.my_p_complaints_len = 0; 135 | ctx.index = 1; 136 | for(ctx.n=5;ctx.n<129;ctx.n++) { 137 | printf("n=%2d\n", ctx.n); 138 | for(ctx.t=2;ctx.t<=((ctx.n-1)>>1)+1;ctx.t++) { 139 | ctx.step=0; 140 | //ctx.p_complaints_len=ctx.n; 141 | size_t itot=0, otot=0; 142 | while(toprf_update_peer_not_done(&ctx)) { 143 | const size_t out_size = toprf_update_peer_output_size(&ctx); 144 | const size_t in_size = toprf_update_peer_input_size(&ctx); 145 | if(in_size>itot) itot=in_size; 146 | if(out_size>otot) otot=out_size; 147 | ctx.step++; 148 | } 149 | const size_t ctx_size=toprf_update_ctx_size(ctx.n, ctx.t)+sizeof ctx; 150 | const size_t total = (ctx_size+itot+otot) >> 10; 151 | if(total<16) printf(GREEN); 152 | else if(total>64) printf(RED); 153 | printf("t=%3d total: %7ldKB ctx size: %7ldKB max: %6ldKB/%6ldKB"NORMAL"\n", ctx.t, total, ctx_size >> 10, itot >> 10, otot >> 10); 154 | } 155 | } 156 | } 157 | 158 | int main(void) { 159 | //printf("xxx: %ld\n", 160 | // (sizeof(STP_DKG_Message) /* header */ \ 161 | // + noise_xk_handshake3_SIZE /* 4th&final noise handshake */ \ 162 | // + sizeof(TOPRF_Share) /* msg: the noise_xk wrapped k share */ \ 163 | // + sizeof(TOPRF_Share) /* msg: the noise_xk wrapped k blind */ \ 164 | // + crypto_secretbox_xchacha20poly1305_MACBYTES /* mac of msg */ )); 165 | printf("toprf-update allocations\n"); 166 | toprf_update(); 167 | printf("stp-dkg allocations\n"); 168 | stp_dkg(); 169 | return 0; 170 | } 171 | -------------------------------------------------------------------------------- /src/oprf.h: -------------------------------------------------------------------------------- 1 | #ifndef oprf_h 2 | #define oprf_h 3 | 4 | /** 5 | * @file oprf.h 6 | * @brief API for Oblivious Pseudorandom Function (OPRF) implementation 7 | * 8 | * SPDX-FileCopyrightText: 2025, Marsiske Stefan 9 | * SPDX-License-Identifier: LGPL-3.0-or-later 10 | * 11 | * This file provides the API for Oblivious Pseudorandom Functions (OPRFs) 12 | * using the Ristretto255 group. It includes functions for key generation, 13 | * blinding inputs, evaluating OPRFs, and unblinding results. 14 | * 15 | * This implementation is based on RFC 9497: Oblivious Pseudorandom 16 | * Functions (OPRFs) Using Prime-Order Groups 17 | * (https://www.rfc-editor.org/rfc/rfc9497.html). 18 | * 19 | * 20 | * This implementation also uses hashing techniques as defined in 21 | * RFC 9380: Hashing to Elliptic Curves 22 | * (https://www.rfc-editor.org/rfc/rfc9380). 23 | * 24 | */ 25 | 26 | #include 27 | #include 28 | #include "toprf.h" 29 | 30 | #define OPRF_BYTES 64 31 | 32 | /** 33 | * @brief Generates an OPRF private key 34 | * 35 | * This is almost the `KeyGen` OPRF function defined in RFC 9497. 36 | * Since this library does not implement Verfiable OPRF (VOPRF) 37 | * functionality, no public key is needed, so steps related to that 38 | * are omitted. 39 | * 40 | * @param[out] kU The per-user OPRF private key 41 | */ 42 | 43 | void oprf_KeyGen(uint8_t kU[crypto_core_ristretto255_SCALARBYTES]); 44 | 45 | /** 46 | * @brief Computes the final OPRF output 47 | * 48 | * Implements the `Finalize` OPRF function defined in RFC 9497. 49 | * It hashes the input and the OPRF evaluation to produce the 50 | * final output for the client. 51 | * 52 | * @param[in] x A value used to compute OPRF (the same value that 53 | * was used as input to be blinded) 54 | * @param[in] x_len Length of input x in bytes. 55 | * @param[in] N Evaluated group element (output from `oprf_Unblind()`) 56 | * @param[out] rwdU Output buffer for the OPRF result 57 | */ 58 | int oprf_Finalize(const uint8_t *x, const uint16_t x_len, 59 | const uint8_t N[crypto_core_ristretto255_BYTES], 60 | uint8_t rwdU[OPRF_BYTES]); 61 | 62 | /** 63 | * @brief Blinds an input value for OPRF evaluation 64 | * 65 | * Implements the `Blind` OPRF function defined in RFC 9497. 66 | * This function converts the input into an OPRF group element and 67 | * randomizes it with a scalar value `r`. Both the scalar and blinded 68 | * element are returned. 69 | * 70 | * @param[in] x Input value to blind. E.g., the user's password in 71 | * OPAQUE (pwdU) 72 | * @param[in] x_len Length of the input value in bytes 73 | * @param[out] r Random scalar used to blind the input 74 | * @param[out] alpha Serialized OPRF group element, the blinded version 75 | * of `x`, used as input to `oprf_Evaluate()` 76 | * 77 | * @return 0 on success, non-zero on error 78 | */ 79 | int oprf_Blind(const uint8_t *x, const uint16_t x_len, 80 | uint8_t r[crypto_core_ristretto255_SCALARBYTES], 81 | uint8_t alpha[crypto_core_ristretto255_BYTES]); 82 | 83 | /** 84 | * @brief Evaluates a blinded input using the OPRF private key 85 | * 86 | * Implements the `Evaluate` OPRF function defined in RFC 9497. 87 | * This function is run by the server. It uses the server's private 88 | * key `k` to evaluate the client's blinded input, producing a group 89 | * element `beta` that the client can later unblind. 90 | * 91 | * @param[in] k OPRF private key E.g., the user's private key in OPAQUE 92 | * (kU) 93 | * @param[in] alpha Serialized OPRF group element, an output of 94 | * `oprf_Blind()`. For OPAQUE, this is the blinded user's 95 | * password, pwdU 96 | * @param[out] beta Serialized OPRF group element, used as input to 97 | * `oprf_Unblind()` 98 | * 99 | * @return 0 on success, non-zero on error 100 | */ 101 | int oprf_Evaluate(const uint8_t k[crypto_core_ristretto255_SCALARBYTES], 102 | const uint8_t alpha[crypto_core_ristretto255_BYTES], 103 | uint8_t beta[crypto_core_ristretto255_BYTES]); 104 | 105 | /** 106 | * @brief Unblinds an evaluated OPRF element 107 | * 108 | * Implements the `Unblind` OPRF function defined in RFC 9497. 109 | * This function removes the random scalar `r` from the evaluated 110 | * element `beta`, producing the unblinded output `N`. 111 | * 112 | * @param[in] r Scalar used to blind the input originally 113 | * @param[in] beta OPRF evaluation result from the server, an output of 114 | * `oprf_Evaluate()` 115 | * @param[out] N Serialized OPRF group element with random scalar `r` 116 | * remove, used as input to `oprf_Finalize()`. 117 | * 118 | * @return 0 on success, non-zero on error 119 | */ 120 | int oprf_Unblind(const uint8_t r[crypto_core_ristretto255_SCALARBYTES], 121 | const uint8_t beta[crypto_core_ristretto255_BYTES], 122 | uint8_t N[crypto_core_ristretto255_BYTES]); 123 | 124 | /** 125 | * @brief Hashes an input message to a point on the Ristretto255 curve 126 | * 127 | * Implements the `hash-to-curve` function defined in RFC 9380. 128 | * This function is needed for the OPRF implementation. 129 | * 130 | * @param[in] msg Input message to hash to a Ristretto255 point 131 | * @param[in] msg_len Length of the input message in bytes 132 | * @param[out] p The resulting Ristretto255 point 133 | * 134 | * @return 0 on success, non-zero on error 135 | */ 136 | int voprf_hash_to_group(const uint8_t *msg, const uint16_t msg_len, uint8_t p[crypto_core_ristretto255_BYTES]); 137 | 138 | /** 139 | * @brief Expands an input message to a uniformly random byte string 140 | * using a cryptographic hash function 141 | * 142 | * Implements `expand_message_xmd` as defined in RFC 9380. 143 | * 144 | * @param[in] msg The input message to expand 145 | * @param[in] msg_len The length of the input message in bytes 146 | * @param[in] dst Domain separation tag (DST) 147 | * @param[in] dst_len The length of the DST 148 | * @param[in] len_in_bytes Desired number of output bytes 149 | * @param[out] uniform_bytes Output buffer of length `len_in_bytes` to 150 | * receive the high entropy result 151 | * 152 | * @return 0 on success, non-zero on error 153 | */ 154 | int oprf_expand_message_xmd(const uint8_t *msg, const uint16_t msg_len, const uint8_t *dst, const uint8_t dst_len, const uint8_t len_in_bytes, uint8_t *uniform_bytes); 155 | 156 | #ifdef __EMSCRIPTEN__ 157 | /** 158 | * if compiling to webassembly, there is no sodium_m(un)?lock and thus we suppress that with the following 159 | */ 160 | 161 | // Per 162 | // https://emscripten.org/docs/compiling/Building-Projects.html#detecting-emscripten-in-preprocessor, 163 | // "The preprocessor define __EMSCRIPTEN__ is always defined when compiling 164 | // programs with Emscripten". For why we are replacing sodium_m(un)?lock, see 165 | // common.c for more details. 166 | #define sodium_mlock(a,l) (0) 167 | #define sodium_munlock(a,l) (0) 168 | #endif //__EMSCRIPTEN__ 169 | 170 | 171 | #endif 172 | -------------------------------------------------------------------------------- /src/mpmult.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dkg_mult.h 3 | * @brief API for the Distributed Key Generation (DKG) Multiplication 4 | * Protocols 5 | * 6 | * SPDX-FileCopyrightText: 2025, Marsiske Stefan 7 | * SPDX-License-Identifier: LGPL-3.0-or-later 8 | * 9 | * Implements a secure multiplication protocol that, given sharings of 10 | * secret `a` and secret `b`, generates a sharing of the product `a*b` 11 | * without revealing either secret. 12 | * 13 | * The interfaces in this header provide access to functions 14 | * implementing the Simple-Mult protocol defined in Fig. 2 from 15 | * R. Gennaro, M. O. Rabin, and T. Rabin. "Simplified VSS and 16 | * fast-track multiparty computations with applications to threshold 17 | * cryptography". In B. A. Coan and Y. Afek, editors, 17th ACM PODC, 18 | * pages 101–111. ACM, June / July 1998. 19 | * 20 | * Also implements the Fast-Track Multiplication (FT-Mult) protocol 21 | * defined in Fig. 5 of the same paper, which allows for faster 22 | * multiparty computations. 23 | * 24 | **/ 25 | 26 | #ifndef THMULT_H 27 | #define THMULT_H 28 | 29 | #include 30 | #include 31 | #include "toprf.h" 32 | #include "dkg.h" 33 | 34 | /** 35 | * @brief Computes the inverse of a Vandermonde matrix 36 | * 37 | * Given a list of dealer indices, this function generates the 38 | * corresponding Vandermonde matrix and computes its inverse, storing 39 | * the result in `inverted`. 40 | * 41 | * @param[in] dealers Number of dealers (matrix dimension) 42 | * @param[in] indexes Array of indices corresponding to each dealer 43 | * @param[out] inverted Output inverted Vandermonde matrix 44 | */ 45 | void invertedVDMmatrix(const uint8_t dealers, 46 | const uint8_t indexes[dealers], 47 | uint8_t inverted[dealers][dealers][crypto_core_ristretto255_SCALARBYTES]); 48 | 49 | /** 50 | * @brief Phase 1 of multiparty threshold multiplication. 51 | * 52 | * Performs the multiplication of two shares, `a` and `b`. 53 | * 54 | * @param[in] a One share held by the dealer contributing to the 55 | * multiplication 56 | * @param[in] b Another share held by the dealer contributing to 57 | * the multiplication 58 | * @param[in] peers The number of peers participating in the 59 | * computation. This should equal the number of peers 60 | * holding shares of `a` and `b`. 61 | * @param[in] threshold The number of peers minimum necessary to 62 | * reconstruct either of the input or the result 63 | * shares. Should equal the threshold for the `a` and `b` 64 | * values. 65 | * @param[out] shares Output array of shares of a*b, one for each peer 66 | * 67 | * @return 0 on success, non-zero on error 68 | */ 69 | int toprf_mpc_mul_start(const uint8_t _a[TOPRF_Share_BYTES], 70 | const uint8_t _b[TOPRF_Share_BYTES], 71 | const uint8_t peers, const uint8_t threshold, 72 | uint8_t shares[peers][TOPRF_Share_BYTES]); 73 | 74 | /** 75 | * @brief Phase 2 of multiparty threshold multiplication. 76 | * 77 | * Each peer calls this function to finalize their share of a*b, 78 | * using all shares from phase 1 and the inverted Vandermonde matrix. 79 | * 80 | * @param[in] dealers Number of dealers 81 | * @param[in] indexes Indices of the participating dealers 82 | * @param[in] peer Index of the current peer computing their share 83 | * @param[in] shares All shares from phase 1 for this participant 84 | * @param[out] share Output share of a*b for this participant 85 | */ 86 | void toprf_mpc_mul_finish(const uint8_t dealers, 87 | const uint8_t indexes[dealers], 88 | const uint8_t peer, 89 | const uint8_t shares[dealers][TOPRF_Share_BYTES], 90 | uint8_t _share[TOPRF_Share_BYTES]); 91 | 92 | /** 93 | * @brief Checks the correctness of a set of commitments 94 | * 95 | * @param[in] t Degree of the polynomials + 1 (threshold) 96 | * @param[in] A Array of commitments to check 97 | * 98 | * @return 0 if the check passes, non-zero otherwise 99 | */ 100 | int toprf_mpc_vsps_check(const uint8_t t, 101 | const uint8_t A[t*2][crypto_core_ristretto255_BYTES]); 102 | 103 | /** 104 | * @brief Step 1 of the Fast-Track Multiplication (FT-Mult) protocol 105 | * 106 | * Each player shares a value (λ_iα_iβ_i) using VSS, producing shares and commitments 107 | * for the next phase. FT-Mult is defined in Fig. 5 of "Simplified VSS and Fast-track 108 | * Multiparty Computations with Applications to Threshold Cryptography" by R. Gennaro, M. O. 109 | * Rabin, and T. Rabin, PODC 1998. 110 | * 111 | * @param[in] dealers Number of participants acting as dealers (always 2t+1) 112 | * @param[in] n Number of parties receiving shares (must be more or equal 2t+1) 113 | * @param[in] t Threshold for reconstruction 114 | * @param[in] self Index of the current participant 115 | * @param[in] alpha Share of secret `a` (and its blinding factor) 116 | * @param[in] beta Share of secret `b` (and its blinding factor) 117 | * @param[in] lambdas Lagrange coefficients 118 | * @param[out] ci_shares Output array of shares for each participant 119 | * @param[out] ci_commitments Output array of commitments 120 | * @param[out] ci_tau Output blinding factor for the commitment 121 | * 122 | * @return 0 on success, non-zero on error 123 | */ 124 | int toprf_mpc_ftmult_step1(const uint8_t dealers, const uint8_t n, const uint8_t t, const uint8_t self, 125 | const TOPRF_Share alpha[2], const TOPRF_Share beta[2], 126 | const uint8_t lambdas[dealers][crypto_core_ristretto255_SCALARBYTES], 127 | TOPRF_Share ci_shares[n][2], 128 | uint8_t ci_commitments[n][crypto_core_ristretto255_BYTES], 129 | uint8_t ci_tau[crypto_core_ristretto255_SCALARBYTES]); 130 | 131 | /** 132 | * @brief Computes zero-knowledge (ZK) commitments for fast-track 133 | * multiplication 134 | * 135 | * Generates commitments for use in the zero-knowledge proof of correct 136 | * multiplication. 137 | * 138 | * @param[in] B_i Commitment to the value being proved 139 | * @param[out] d Random scalar for the proof 140 | * @param[out] s Random scalar for the proof 141 | * @param[out] x Random scalar for the proof 142 | * @param[out] s_1 Random scalar for the proof 143 | * @param[out] s_2 Random scalar for the proof 144 | * @param[out] zk_commitments Output array of three commitments 145 | * 146 | * @return 0 on success, non-zero on error 147 | */ 148 | int toprf_mpc_ftmult_zk_commitments(const uint8_t B_i[crypto_core_ristretto255_BYTES], 149 | uint8_t d[crypto_scalarmult_ristretto255_SCALARBYTES], 150 | uint8_t s[crypto_scalarmult_ristretto255_SCALARBYTES], 151 | uint8_t x[crypto_scalarmult_ristretto255_SCALARBYTES], 152 | uint8_t s_1[crypto_scalarmult_ristretto255_SCALARBYTES], 153 | uint8_t s_2[crypto_scalarmult_ristretto255_SCALARBYTES], 154 | uint8_t zk_commitments[3][crypto_scalarmult_ristretto255_BYTES]); 155 | 156 | #endif // THMULT_H 157 | -------------------------------------------------------------------------------- /src/tests/mpmult.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../oprf.h" 3 | #include "../mpmult.h" 4 | #include "../dkg.h" 5 | #include "../utils.h" 6 | #include 7 | #include 8 | #include 9 | 10 | int test_mpmul(void) { 11 | const uint8_t threshold = 2, dealers = (threshold*2) + 1U, peers = dealers * 2; 12 | 13 | // share value k0 14 | uint8_t k0[crypto_core_ristretto255_SCALARBYTES]; 15 | crypto_core_ristretto255_scalar_random(k0); 16 | //debian_rng(k0); 17 | dump(k0, sizeof k0, "k0"); 18 | // split k into shares 19 | uint8_t shares0[peers][TOPRF_Share_BYTES]; 20 | toprf_create_shares(k0, peers, threshold, shares0); 21 | if(liboprf_debug) { 22 | for(unsigned j=0;j 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/krml/lowstar_endianness.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 2 | Licensed under the Apache 2.0 License. */ 3 | 4 | #ifndef __LOWSTAR_ENDIANNESS_H 5 | #define __LOWSTAR_ENDIANNESS_H 6 | 7 | #include 8 | #include 9 | 10 | /******************************************************************************/ 11 | /* Implementing C.fst (part 2: endian-ness macros) */ 12 | /******************************************************************************/ 13 | 14 | /* ... for Linux */ 15 | #if defined(__linux__) || defined(__CYGWIN__) || defined (__USE_SYSTEM_ENDIAN_H__) || defined(__GLIBC__) 16 | # include 17 | 18 | /* ... for OSX */ 19 | #elif defined(__APPLE__) 20 | # include 21 | # define htole64(x) OSSwapHostToLittleInt64(x) 22 | # define le64toh(x) OSSwapLittleToHostInt64(x) 23 | # define htobe64(x) OSSwapHostToBigInt64(x) 24 | # define be64toh(x) OSSwapBigToHostInt64(x) 25 | 26 | # define htole16(x) OSSwapHostToLittleInt16(x) 27 | # define le16toh(x) OSSwapLittleToHostInt16(x) 28 | # define htobe16(x) OSSwapHostToBigInt16(x) 29 | # define be16toh(x) OSSwapBigToHostInt16(x) 30 | 31 | # define htole32(x) OSSwapHostToLittleInt32(x) 32 | # define le32toh(x) OSSwapLittleToHostInt32(x) 33 | # define htobe32(x) OSSwapHostToBigInt32(x) 34 | # define be32toh(x) OSSwapBigToHostInt32(x) 35 | 36 | /* ... for Solaris */ 37 | #elif defined(__sun__) 38 | # include 39 | # define htole64(x) LE_64(x) 40 | # define le64toh(x) LE_64(x) 41 | # define htobe64(x) BE_64(x) 42 | # define be64toh(x) BE_64(x) 43 | 44 | # define htole16(x) LE_16(x) 45 | # define le16toh(x) LE_16(x) 46 | # define htobe16(x) BE_16(x) 47 | # define be16toh(x) BE_16(x) 48 | 49 | # define htole32(x) LE_32(x) 50 | # define le32toh(x) LE_32(x) 51 | # define htobe32(x) BE_32(x) 52 | # define be32toh(x) BE_32(x) 53 | 54 | /* ... for the BSDs */ 55 | #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) 56 | # include 57 | #elif defined(__OpenBSD__) 58 | # include 59 | 60 | /* ... for Windows (MSVC)... not targeting XBOX 360! */ 61 | #elif defined(_MSC_VER) 62 | 63 | # include 64 | # define htobe16(x) _byteswap_ushort(x) 65 | # define htole16(x) (x) 66 | # define be16toh(x) _byteswap_ushort(x) 67 | # define le16toh(x) (x) 68 | 69 | # define htobe32(x) _byteswap_ulong(x) 70 | # define htole32(x) (x) 71 | # define be32toh(x) _byteswap_ulong(x) 72 | # define le32toh(x) (x) 73 | 74 | # define htobe64(x) _byteswap_uint64(x) 75 | # define htole64(x) (x) 76 | # define be64toh(x) _byteswap_uint64(x) 77 | # define le64toh(x) (x) 78 | 79 | /* ... for Windows (GCC-like, e.g. mingw or clang) */ 80 | #elif (defined(_WIN32) || defined(_WIN64) || defined(__EMSCRIPTEN__)) && \ 81 | (defined(__GNUC__) || defined(__clang__)) 82 | 83 | # define htobe16(x) __builtin_bswap16(x) 84 | # define htole16(x) (x) 85 | # define be16toh(x) __builtin_bswap16(x) 86 | # define le16toh(x) (x) 87 | 88 | # define htobe32(x) __builtin_bswap32(x) 89 | # define htole32(x) (x) 90 | # define be32toh(x) __builtin_bswap32(x) 91 | # define le32toh(x) (x) 92 | 93 | # define htobe64(x) __builtin_bswap64(x) 94 | # define htole64(x) (x) 95 | # define be64toh(x) __builtin_bswap64(x) 96 | # define le64toh(x) (x) 97 | 98 | /* ... generic big-endian fallback code */ 99 | /* ... AIX doesn't have __BYTE_ORDER__ (with XLC compiler) & is always big-endian */ 100 | #elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || defined(_AIX) 101 | 102 | /* byte swapping code inspired by: 103 | * https://github.com/rweather/arduinolibs/blob/master/libraries/Crypto/utility/EndianUtil.h 104 | * */ 105 | 106 | # define htobe32(x) (x) 107 | # define be32toh(x) (x) 108 | # define htole32(x) \ 109 | (__extension__({ \ 110 | uint32_t _temp = (x); \ 111 | ((_temp >> 24) & 0x000000FF) | ((_temp >> 8) & 0x0000FF00) | \ 112 | ((_temp << 8) & 0x00FF0000) | ((_temp << 24) & 0xFF000000); \ 113 | })) 114 | # define le32toh(x) (htole32((x))) 115 | 116 | # define htobe64(x) (x) 117 | # define be64toh(x) (x) 118 | # define htole64(x) \ 119 | (__extension__({ \ 120 | uint64_t __temp = (x); \ 121 | uint32_t __low = htobe32((uint32_t)__temp); \ 122 | uint32_t __high = htobe32((uint32_t)(__temp >> 32)); \ 123 | (((uint64_t)__low) << 32) | __high; \ 124 | })) 125 | # define le64toh(x) (htole64((x))) 126 | 127 | /* ... generic little-endian fallback code */ 128 | #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 129 | 130 | # define htole32(x) (x) 131 | # define le32toh(x) (x) 132 | # define htobe32(x) \ 133 | (__extension__({ \ 134 | uint32_t _temp = (x); \ 135 | ((_temp >> 24) & 0x000000FF) | ((_temp >> 8) & 0x0000FF00) | \ 136 | ((_temp << 8) & 0x00FF0000) | ((_temp << 24) & 0xFF000000); \ 137 | })) 138 | # define be32toh(x) (htobe32((x))) 139 | 140 | # define htole64(x) (x) 141 | # define le64toh(x) (x) 142 | # define htobe64(x) \ 143 | (__extension__({ \ 144 | uint64_t __temp = (x); \ 145 | uint32_t __low = htobe32((uint32_t)__temp); \ 146 | uint32_t __high = htobe32((uint32_t)(__temp >> 32)); \ 147 | (((uint64_t)__low) << 32) | __high; \ 148 | })) 149 | # define be64toh(x) (htobe64((x))) 150 | 151 | /* ... couldn't determine endian-ness of the target platform */ 152 | #else 153 | # error "Please define __BYTE_ORDER__!" 154 | 155 | #endif /* defined(__linux__) || ... */ 156 | 157 | /* Loads and stores. These avoid undefined behavior due to unaligned memory 158 | * accesses, via memcpy. */ 159 | 160 | inline static uint16_t load16(uint8_t *b) { 161 | uint16_t x; 162 | memcpy(&x, b, 2); 163 | return x; 164 | } 165 | 166 | inline static uint32_t load32(uint8_t *b) { 167 | uint32_t x; 168 | memcpy(&x, b, 4); 169 | return x; 170 | } 171 | 172 | inline static uint64_t load64(uint8_t *b) { 173 | uint64_t x; 174 | memcpy(&x, b, 8); 175 | return x; 176 | } 177 | 178 | inline static void store16(uint8_t *b, uint16_t i) { 179 | memcpy(b, &i, 2); 180 | } 181 | 182 | inline static void store32(uint8_t *b, uint32_t i) { 183 | memcpy(b, &i, 4); 184 | } 185 | 186 | inline static void store64(uint8_t *b, uint64_t i) { 187 | memcpy(b, &i, 8); 188 | } 189 | 190 | /* Legacy accessors so that this header can serve as an implementation of 191 | * C.Endianness */ 192 | #define load16_le(b) (le16toh(load16(b))) 193 | #define store16_le(b, i) (store16(b, htole16(i))) 194 | #define load16_be(b) (be16toh(load16(b))) 195 | #define store16_be(b, i) (store16(b, htobe16(i))) 196 | 197 | #define load32_le(b) (le32toh(load32(b))) 198 | #define store32_le(b, i) (store32(b, htole32(i))) 199 | #define load32_be(b) (be32toh(load32(b))) 200 | #define store32_be(b, i) (store32(b, htobe32(i))) 201 | 202 | #define load64_le(b) (le64toh(load64(b))) 203 | #define store64_le(b, i) (store64(b, htole64(i))) 204 | #define load64_be(b) (be64toh(load64(b))) 205 | #define store64_be(b, i) (store64(b, htobe64(i))) 206 | 207 | /* Co-existence of LowStar.Endianness and FStar.Endianness generates name 208 | * conflicts, because of course both insist on having no prefixes. Until a 209 | * prefix is added, or until we truly retire FStar.Endianness, solve this issue 210 | * in an elegant way. */ 211 | #define load16_le0 load16_le 212 | #define store16_le0 store16_le 213 | #define load16_be0 load16_be 214 | #define store16_be0 store16_be 215 | 216 | #define load32_le0 load32_le 217 | #define store32_le0 store32_le 218 | #define load32_be0 load32_be 219 | #define store32_be0 store32_be 220 | 221 | #define load64_le0 load64_le 222 | #define store64_le0 store64_le 223 | #define load64_be0 load64_be 224 | #define store64_be0 store64_be 225 | 226 | #define load128_le0 load128_le 227 | #define store128_le0 store128_le 228 | #define load128_be0 load128_be 229 | #define store128_be0 store128_be 230 | 231 | #endif 232 | -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | PREFIX?=/usr/local 2 | INCLUDES=-Inoise_xk/include -Inoise_xk/include/karmel -Inoise_xk/include/karmel/minimal 3 | CFLAGS?=-Wall -O2 -g -ffunction-sections -fdata-sections \ 4 | -Werror=attributes -Werror=format-security -Werror=format-truncation -Werror=implicit-function-declaration \ 5 | -Wformat=2 -Wconversion -Wimplicit-fallthrough \ 6 | -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \ 7 | -fstack-protector-strong -fasynchronous-unwind-tables -fpic \ 8 | -ftrapv -D_GLIBCXX_ASSERTIONS $(DEFINES) $(EXTRA_CFLAGS) 9 | 10 | LIBS=-lsodium -loprf-noiseXK -Lnoise_xk 11 | CC?=gcc 12 | LD?=ld 13 | OBJCOPY?=objcopy 14 | STRIP?=strip 15 | SOEXT?=so 16 | STATICEXT?=a 17 | SOVER=0 18 | DEBUGDIR?=lib/debug/usr/lib 19 | 20 | # To statically link the noiseXK library, use these LIBS (and comment out the other LIBS) 21 | #LIBS=-lsodium -l:liboprf-noiseXK.a -Wl,--exclude-libs,ALL -Lnoise_xk 22 | 23 | UNAME := $(if $(UNAME),$(UNAME),$(shell uname -s)) 24 | ARCH := $(if $(ARCH),$(ARCH),$(shell uname -m)) 25 | ifeq ($(UNAME),Darwin) 26 | SOEXT=dylib 27 | SOFLAGS=-Wl,-install_name,$(DESTDIR)$(PREFIX)/lib/liboprf.$(SOEXT) 28 | else 29 | CFLAGS+=-Wl,-z,defs -Wl,-z,relro -Wl,-z,noexecstack -Wl,-z,now -Wtrampolines \ 30 | -fsanitize=signed-integer-overflow -fsanitize-undefined-trap-on-error 31 | #-fstrict-flex-arrays=3 -mbranch-protection=standard 32 | SOEXT=so 33 | SOFLAGS=-Wl,-soname,liboprf.$(SOEXT).$(SOVER) 34 | ifeq ($(ARCH),x86_64) 35 | CFLAGS+=-fcf-protection=full 36 | endif 37 | 38 | ifeq ($(ARCH),parisc64) 39 | else ifeq ($(ARCH),parisc64) 40 | else ifeq ($(ARCH),armv7-a) 41 | else 42 | CFLAGS+=-fstack-clash-protection 43 | endif 44 | endif 45 | 46 | PKGCONF_MISSING := $(shell pkgconf --version >/dev/null; echo $$?) 47 | ifneq ($(PKGCONF_MISSING),0) 48 | $(error liboprf: Cannot find pkgconf) 49 | endif 50 | 51 | SODIUM_MISSING := $(shell pkgconf --exists libsodium; echo $$?) 52 | ifneq ($(SODIUM_MISSING),0) 53 | $(error liboprf: Cannot find libsodium via pkgconf. Check that libsodium has been installed) 54 | endif 55 | 56 | SODIUM_NEWER_THAN_1_0_18 := $(shell pkgconf --atleast-version=1.0.19 libsodium; echo $$?) 57 | ifneq ($(SODIUM_NEWER_THAN_1_0_18),0) 58 | INCLUDES+= -Iaux_ 59 | EXTRA_SOURCES+= aux_/kdf_hkdf_sha256.c 60 | $(info liboprf: Using auxiliary sources because libsodium is too old) 61 | else 62 | CFLAGS+= -DHAVE_SODIUM_HKDF=1 63 | endif 64 | 65 | all: liboprf.$(SOEXT) liboprf_release.$(STATICEXT) noise_xk/liboprf-noiseXK.$(SOEXT) liboprf.pc 66 | 67 | android: 68 | $(MAKE) EXTRA_SOURCES+=jni.c liboprf.$(SOEXT) 69 | 70 | LIBOPRF_SOURCES=oprf.c toprf.c dkg.c dkg-vss.c utils.c tp-dkg.c mpmult.c stp-dkg.c toprf-update.c 71 | SOURCES=$(LIBOPRF_SOURCES) $(EXTRA_SOURCES) 72 | OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) 73 | 74 | # Uncomment to use $ORIGIN as the runtime search path 75 | #SOFLAGS += -Wl,-rpath,'$$'ORIGIN 76 | 77 | # Terminal colors: purely for UX, comment out if causing problems 78 | decor = $(shell [ -t 0 ] && printf "\033[38;5;2m====" || printf "====") 79 | endDecor = $(shell [ -t 0 ] && printf "====\033[0m" || printf "====") 80 | 81 | debug: DEFINES=-DTRACE 82 | debug: all 83 | 84 | asan: 85 | CFLAGS=-fsanitize=address -static-libasan -g -march=native -Wall -O2 -g -fstack-protector-strong -fpic -Werror=format-security -Werror=implicit-function-declaration -Wl, -z,noexecstack 86 | ifeq ($(ARCH),x86_64) 87 | CFLAGS+=-fcf-protection=full 88 | endif 89 | ifeq ($(ARCH),parisc64) 90 | else ifeq ($(ARCH),parisc64) 91 | else ifeq ($(ARCH),armv7-a) 92 | else 93 | CFLAGS+=-fstack-clash-protection 94 | endif 95 | asan: LDFLAGS+= -fsanitize=address -static-libasan 96 | asan: all 97 | 98 | AR ?= ar 99 | 100 | aux_/kdf_hkdf_sha256.o: aux_/kdf_hkdf_sha256.c 101 | $(CC) $(CPPFLAGS) $(CFLAGS) -fvisibility=hidden $(INCLUDES) -o $@ -c $^ 102 | 103 | liboprf.$(SOEXT): liboprf_merged.o noise_xk/liboprf-noiseXK.$(SOEXT) 104 | $(info $(decor) Build dynamic release library: $@ $(endDecor)) 105 | $(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -shared $(SOFLAGS) -o $@ liboprf_merged.o $(LDFLAGS) $(LIBS) 106 | $(OBJCOPY) --only-keep-debug $@ $@.debug 107 | $(STRIP) --strip-debug --strip-unneeded $@ 108 | $(OBJCOPY) --add-gnu-debuglink=$@.debug $@ 109 | 110 | liboprf.$(SOEXT).debug: liboprf.$(SOEXT) 111 | 112 | liboprf-corrupt-dkg.$(SOEXT): $(SOURCES) noise_xk/liboprf-noiseXK.$(SOEXT) 113 | $(info $(decor) Build unit test library: $@ $(endDecor)) 114 | $(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -DUNITTEST -DUNITTEST_CORRUPT -fPIC -shared $(SOFLAGS) -o $@ $(SOURCES) $(LDFLAGS) $(LIBS) 115 | 116 | liboprf_merged.o: $(OBJECTS) 117 | $(info $(decor) Merge object files $(endDecor)) 118 | $(LD) -r -o $@ $^ 119 | 120 | liboprf_merged_localized.o: liboprf_merged.o 121 | $(info $(decor) Localize symbols $(endDecor)) 122 | objcopy --localize-hidden $^ $@ 123 | 124 | liboprf_release.$(STATICEXT): liboprf_merged_localized.o 125 | $(info $(decor) Build static release library: $@ $(endDecor)) 126 | $(AR) rcs $@ $^ 127 | 128 | liboprf.$(STATICEXT): $(OBJECTS) 129 | $(AR) rcs $@ $^ 130 | 131 | noise_xk/liboprf-noiseXK.$(SOEXT): 132 | $(info $(decor) Compile vendorized noiseXK library: $@ $(endDecor)) 133 | make -C noise_xk all 134 | 135 | noise_xk/liboprf-noiseXK.$(STATICEXT): 136 | $(info $(decor) Compile vendorized noiseXK library: $@ $(endDecor)) 137 | make -C noise_xk all 138 | 139 | liboprf.pc: 140 | echo "prefix=$(PREFIX)" >liboprf.pc 141 | cat ../liboprf.pc >>liboprf.pc 142 | 143 | clean: 144 | rm -f *.o liboprf.$(SOEXT) liboprf.$(STATICEXT) liboprf-corrupt-dkg.$(SOEXT) 145 | rm -f aux_/*.o 146 | make -C tests clean 147 | make -C noise_xk clean 148 | 149 | install: install-oprf install-noiseXK 150 | 151 | install-oprf: $(DESTDIR)$(PREFIX)/lib/liboprf.$(SOEXT) \ 152 | $(DESTDIR)$(PREFIX)/$(DEBUGDIR)/liboprf.$(SOEXT).debug \ 153 | $(DESTDIR)$(PREFIX)/lib/liboprf.$(STATICEXT) \ 154 | $(DESTDIR)$(PREFIX)/lib/pkgconfig/liboprf.pc \ 155 | $(DESTDIR)$(PREFIX)/include/oprf/oprf.h \ 156 | $(DESTDIR)$(PREFIX)/include/oprf/toprf.h \ 157 | $(DESTDIR)$(PREFIX)/include/oprf/toprf-update.h \ 158 | $(DESTDIR)$(PREFIX)/include/oprf/dkg.h \ 159 | $(DESTDIR)$(PREFIX)/include/oprf/tp-dkg.h \ 160 | $(DESTDIR)$(PREFIX)/include/oprf/stp-dkg.h \ 161 | $(DESTDIR)$(PREFIX)/include/oprf/utils.h 162 | 163 | install-noiseXK: 164 | make -C noise_xk install 165 | 166 | uninstall: uninstall-oprf uninstall-noiseXK 167 | 168 | uninstall-oprf: 169 | @ \ 170 | if [ ! '$(strip $(DESTDIR)$(PREFIX))' ]; then echo 'liboprf: DESTDIR-PREFIX is empty!' && exit 1; fi; \ 171 | if [ ! -d '$(strip $(DESTDIR)$(PREFIX))' ]; then echo 'liboprf: DESTDIR-PREFIX is not a folder' && exit 1; fi; 172 | 173 | rm -vf '$(DESTDIR)$(PREFIX)/lib/liboprf.$(SOEXT)' '$(DESTDIR)$(PREFIX)/lib/liboprf.$(STATICEXT)' 174 | rm -vf '$(DESTDIR)$(PREFIX)/include/oprf/oprf.h' '$(DESTDIR)$(PREFIX)/include/oprf/toprf.h' 175 | rm -vf '$(DESTDIR)$(PREFIX)/include/oprf/dkg.h' '$(DESTDIR)$(PREFIX)/include/oprf/toprf-update.h' 176 | rm -vf '$(DESTDIR)$(PREFIX)/include/oprf/utils.h' '$(DESTDIR)$(PREFIX)/lib/pkgconfig/liboprf.pc' 177 | rm -vf '$(DESTDIR)$(PREFIX)/include/oprf/tp-dkg.h' '$(DESTDIR)$(PREFIX)/include/oprf/stp-dkg.h' 178 | rm -vf '$(DESTDIR)$(PREFIX)/$(DEBUGDIR)/liboprf.$(SOEXT).debug' 179 | rmdir -v '$(DESTDIR)$(PREFIX)/include/oprf/' 180 | 181 | uninstall-noiseXK: 182 | make -C noise_xk uninstall 183 | 184 | $(DESTDIR)$(PREFIX)/lib/liboprf.$(SOEXT): liboprf.$(SOEXT) 185 | mkdir -p $(DESTDIR)$(PREFIX)/lib 186 | cp $< $@.$(SOVER) 187 | ln -sf $@.$(SOVER) $@ 188 | 189 | $(DESTDIR)$(PREFIX)/lib/liboprf.$(STATICEXT): liboprf_release.$(STATICEXT) 190 | mkdir -p $(DESTDIR)$(PREFIX)/lib 191 | cp $< $@ 192 | 193 | $(DESTDIR)$(PREFIX)/lib/pkgconfig/liboprf.pc: liboprf.pc 194 | mkdir -p $(DESTDIR)$(PREFIX)/lib/pkgconfig 195 | cp $< $@ 196 | 197 | $(DESTDIR)$(PREFIX)/include/oprf/oprf.h: oprf.h 198 | mkdir -p $(DESTDIR)$(PREFIX)/include/oprf 199 | cp $< $@ 200 | 201 | $(DESTDIR)$(PREFIX)/include/oprf/toprf.h: toprf.h 202 | mkdir -p $(DESTDIR)$(PREFIX)/include/oprf 203 | cp $< $@ 204 | 205 | $(DESTDIR)$(PREFIX)/include/oprf/toprf-update.h: toprf-update.h 206 | mkdir -p $(DESTDIR)$(PREFIX)/include/oprf 207 | cp $< $@ 208 | 209 | $(DESTDIR)$(PREFIX)/include/oprf/dkg.h: dkg.h 210 | mkdir -p $(DESTDIR)$(PREFIX)/include/oprf 211 | cp $< $@ 212 | 213 | $(DESTDIR)$(PREFIX)/include/oprf/tp-dkg.h: tp-dkg.h 214 | mkdir -p $(DESTDIR)$(PREFIX)/include/oprf 215 | cp $< $@ 216 | 217 | $(DESTDIR)$(PREFIX)/include/oprf/stp-dkg.h: stp-dkg.h 218 | mkdir -p $(DESTDIR)$(PREFIX)/include/oprf 219 | cp $< $@ 220 | 221 | $(DESTDIR)$(PREFIX)/include/oprf/utils.h: utils.h 222 | mkdir -p $(DESTDIR)$(PREFIX)/include/oprf 223 | cp $< $@ 224 | 225 | $(DESTDIR)$(PREFIX)/$(DEBUGDIR)/liboprf.$(SOEXT).debug: liboprf.$(SOEXT).debug 226 | mkdir -p $(DESTDIR)$(PREFIX)/$(DEBUGDIR) 227 | cp $< $@ 228 | 229 | test: liboprf-corrupt-dkg.$(SOEXT) liboprf.$(STATICEXT) noise_xk/liboprf-noiseXK.$(STATICEXT) 230 | make -C tests tests 231 | make -C noise_xk test 232 | 233 | %.o: %.c 234 | $(CC) $(CPPFLAGS) $(CFLAGS) -fPIC $(INCLUDES) -c $< -o $@ 235 | 236 | PHONY: clean 237 | -------------------------------------------------------------------------------- /src/toprf.h: -------------------------------------------------------------------------------- 1 | #ifndef TOPRF_H 2 | #define TOPRF_H 3 | 4 | /** 5 | * @file toprf.h 6 | * @brief API for the Threshold Oblivious Pseudorandom Function (TOPRF) 7 | * implementation 8 | * 9 | * SPDX-FileCopyrightText: 2023, Marsiske Stefan 10 | * SPDX-License-Identifier: LGPL-3.0-or-later 11 | * 12 | * This file defines the structures, types, and functions for implementing 13 | * a Threshold Oblivious Pseudorandom Function (TOPRF) based on the 14 | * paper section 3 of the paper: 15 | * "TOPPSS: Cost-minimal Password-Protected Secret Sharing based on 16 | * Threshold OPRF" by Stanislaw Jarecki, Aggelos Kiayias, Hugo Krawczyk, 17 | * and Jiayu Xu, 2017 (https://eprint.iacr.org/2017/363) 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | /** 24 | * @struct TOPRF_Share 25 | * @brief Share structure for TOPRF 26 | */ 27 | typedef struct 28 | { 29 | uint8_t index; 30 | uint8_t value[crypto_core_ristretto255_SCALARBYTES]; 31 | } __attribute((packed)) TOPRF_Share; 32 | 33 | #define TOPRF_Share_BYTES (sizeof(TOPRF_Share)) 34 | #define TOPRF_Part_BYTES (crypto_core_ristretto255_BYTES + 1UL) 35 | 36 | /** 37 | * @brief Interpolates a polynomial of degree `t` at an arbitrary point 38 | * `x: y = f(x)` 39 | * 40 | * Uses Lagrange interpolation to reconstruct the polynomial value at `x`, 41 | * given `t` shares (evaluations) of the polynomial. 42 | * 43 | * @param[in] x The value at which the polynomial is evaluated 44 | * @param[in] t The degree of the polynomial 45 | * @param[in] shares Evaluated points on the polynomial. 46 | * @param[out] y Output buffer to store the computed result, `f(x)` 47 | */ 48 | void interpolate(const uint8_t x, const uint8_t t, const TOPRF_Share shares[t], uint8_t y[crypto_scalarmult_ristretto255_SCALARBYTES]); 49 | 50 | /** 51 | * @brief Computes the Lagrange coefficient for `f(x)` 52 | * 53 | * This function calculates a Lagrange coefficient for `f(x)` 54 | * based on the index and the indices of the other contributing peers 55 | * 56 | * @param[in] index The index of the peer for which the Lagrange coefficient 57 | * is being calculated 58 | * @param[in] x The evaluation point for the polynomial 59 | * @param[in] degree Total number of shares participating (number of peers) 60 | * @param[in] peers Array of indices of all participating peers that 61 | * contribute to the reconstruction 62 | * @param[out] result Output buffer to store the computed Lagrange 63 | * coefficient 64 | */ 65 | 66 | void lcoeff(const uint8_t index, const uint8_t x, const size_t degree, const uint8_t peers[degree], uint8_t result[crypto_scalarmult_ristretto255_SCALARBYTES]); 67 | 68 | /** 69 | * @brief Computes the Lagrange coefficient for `f(0) 70 | * 71 | * This function calculates a lagrange coefficient for `f(0)` based on 72 | * the index and the indices of the other contributing peers 73 | * 74 | * @param[in] index The index of the peer for which the Lagrange coefficient 75 | * is being calculated 76 | * @param[in] peers_len Total number of shares in the peers 77 | * @param[in] peers Shares that contribute to the reconstruction 78 | * @param[out] result Output buffer to store the computed Lagrange 79 | * coefficient 80 | */ 81 | void coeff(const uint8_t index, const size_t peers_len, const uint8_t peers[peers_len], uint8_t result[crypto_scalarmult_ristretto255_SCALARBYTES]); 82 | 83 | /** 84 | * @brief Splits a secret into `n` shares using Shamir's secret sharing over 85 | * the curve Ristretto255 86 | * 87 | * The secret is shared in a (threshold, n) scheme: any threshold number 88 | * of shares can reconstruct the secret, but fewer reveal nothing. 89 | * This function wraps `lcoeff()`, allowing to recover the shared 90 | * secret without providing `x=0` as a parameter. This is mostly for 91 | * backward compatibility. 92 | * 93 | * @param[in] secret The scalar value to be secretly shared 94 | * @param[in] n The number of shares created 95 | * @param[in] threshold Minimum number of shares required to reconstruct 96 | * the secret 97 | * @param[out] shares Output buffer receiving `n` generated shares 98 | * 99 | * @return 0 on success, non-zero on failure 100 | */ 101 | void toprf_create_shares(const uint8_t secret[crypto_core_ristretto255_SCALARBYTES], 102 | const uint8_t n, 103 | const uint8_t threshold, 104 | uint8_t shares[n][TOPRF_Share_BYTES]); 105 | 106 | /** 107 | * @brief Combines shares in the exponent using Lagrange interpolation over 108 | * the curve Ristretto255 109 | * 110 | * This function combines a threshold number of shares to recover the secret 111 | * in the exponent. It uses Lagrange interpolation over the curve 112 | * Ristretto255. 113 | * The peers are unaware of whether they participate in threshold or 114 | * standalone mode. Their computation remains the same in both cases. 115 | * 116 | * @param[in] response_len Number of elements in the `responses` array 117 | * @param[in] responses Array of shares to be combined 118 | * @param[out] result Output buffer receiving the reconstructed secret 119 | * 120 | * @return 0 on success, non-zero on error 121 | */ 122 | int toprf_thresholdmult(const size_t response_len, 123 | const uint8_t responses[response_len][TOPRF_Part_BYTES], 124 | uint8_t result[crypto_scalarmult_ristretto255_BYTES]); 125 | 126 | /** 127 | * @brief Efficiently evaluates a blinded input using the private key 128 | * in a threshold setting 129 | * 130 | * This function is the efficient threshold version of `oprf_Evaluate()` 131 | * defined in oprf.h. 132 | * It needs to know in advance the indices of all shares that will be 133 | * combined later in the `toprf_thresholdcombine()` function. This 134 | * precomputation reduces the total costs and distributes them to the peers 135 | * 136 | * @param[in] k The server's secret key share. For OPAQUE, this is kU, the 137 | * user's OPRF private key 138 | * @param[in] blinded Serialized OPRF group element, an output of 139 | * `oprf_Blind()`. For OPAQUE, this is the blinded user's 140 | * password, pwdU 141 | * @param[in] self The index of the current peer 142 | * @param[in] indexes Array of indices of all peers contributing to this 143 | * OPRF evaluation 144 | * @param[in] index_len Number of participating peers (Length of `indexes`) 145 | * @param[out] Z Serialized OPRF group element, used as input to 146 | * `oprf_Unblind()` 147 | * 148 | * @return 0 on success, non-zero on error 149 | */ 150 | int toprf_Evaluate(const uint8_t k[TOPRF_Share_BYTES], 151 | const uint8_t blinded[crypto_core_ristretto255_BYTES], 152 | const uint8_t self, const uint8_t *indexes, const uint16_t index_len, 153 | uint8_t Z[TOPRF_Part_BYTES]); 154 | 155 | /** 156 | * @brief Combines the partial results to reconstruct the final OPRF output 157 | * 158 | * This function is combines the results of the `toprf_Evaluate()` to recover 159 | * the shared secret in the exponent. 160 | 161 | * @param[in] response_len Number of elements in the `responses` array 162 | * @param[in] responses Array of shares to be combined 163 | * @param[out] result Output buffer receiving the reconstructed secret 164 | * 165 | * @return 0 on success, non-zero on error 166 | */ 167 | int toprf_thresholdcombine(const size_t response_len, 168 | const uint8_t _responses[response_len][TOPRF_Part_BYTES], 169 | uint8_t result[crypto_scalarmult_ristretto255_BYTES]); 170 | 171 | typedef int (*toprf_evalcb)(void *ctx, 172 | const uint8_t k[crypto_core_ristretto255_SCALARBYTES], 173 | const uint8_t alpha[crypto_core_ristretto255_BYTES], 174 | uint8_t beta[crypto_core_ristretto255_BYTES]); 175 | 176 | typedef int (*toprf_keygencb)(void *ctx, uint8_t k[crypto_core_ristretto255_SCALARBYTES]); 177 | 178 | /** 179 | * @brief Implements the 3HashTDH protocol 180 | * 181 | * This function implements the 3HashTDH protocol from the paper: 182 | * "Threshold PAKE with Security against Compromise of All Servers" 183 | * (https://eprint.iacr.org/2024/1455) by Gu, Jarecki, Kedzior, 184 | * Nazarian, Xu. 185 | * 186 | * Use this function to implement a threshold OPRF. 187 | * 188 | * @param[in] k A share of the secret key 189 | * @param[in] z A random zero-sharing of the secret key. This is a share of 190 | * a random `t`-degree polynomial that evaluates to zero, where t 191 | * is the threshold 192 | * @param[in] alpha The blinded element from the client 193 | * @param[in] ssid_S A session-specific identifier that all participants in 194 | * the threshold evaluation must agree on (it must be the same 195 | * for all participants) 196 | * @param[in] ssid_S_len Length of the `ssid_S` identifier 197 | * @param[out] beta Output buffer containing the result of evaluation, to 198 | * be returned to the client 199 | * 200 | * @return 0 on success, non-zero on error 201 | */ 202 | int toprf_3hashtdh(const uint8_t k[TOPRF_Share_BYTES], 203 | const uint8_t z[TOPRF_Share_BYTES], 204 | const uint8_t alpha[crypto_core_ristretto255_BYTES], 205 | const uint8_t *ssid_S, const uint16_t ssid_S_len, 206 | uint8_t beta[TOPRF_Part_BYTES]); 207 | 208 | #endif // TOPRF_H 209 | -------------------------------------------------------------------------------- /python/examples/toprf-update.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Test for TP DKG wrapper of pyoprf/liboprf 5 | 6 | SPDX-FileCopyrightText: 2024, Marsiske Stefan 7 | SPDX-License-Identifier: LGPL-3.0-or-later 8 | 9 | Copyright (c) 2024, Marsiske Stefan. 10 | All rights reserved. 11 | 12 | This file is part of liboprf. 13 | 14 | liboprf is free software: you can redistribute it and/or 15 | modify it under the terms of the GNU Lesser General Public License 16 | as published by the Free Software Foundation, either version 3 of 17 | the License, or (at your option) any later version. 18 | 19 | liboprf is distributed in the hope that it will be 20 | useful, but WITHOUT ANY WARRANTY; without even the implied 21 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 22 | See the GNU Lesser General Public License for more details. 23 | 24 | You should have received a copy of the GNU Lesser General Public License 25 | along with liboprf. If not, see . 26 | 27 | """ 28 | 29 | import pyoprf, pysodium, ctypes as c 30 | from itertools import combinations 31 | 32 | n = 9 33 | t = 4 34 | ts_epsilon = 5 35 | 36 | # enable verbose logging for tp-dkg 37 | libc = c.cdll.LoadLibrary('libc.so.6') 38 | cstderr = c.c_void_p.in_dll(libc, 'stderr') 39 | log_file = c.c_void_p.in_dll(pyoprf.liboprf,'log_file') 40 | log_file.value = cstderr.value 41 | 42 | # create some long-term keypairs 43 | sig_pks = [] 44 | sig_sks = [] 45 | for _ in range(n+1): 46 | pk, sk = pysodium.crypto_sign_keypair() 47 | sig_pks.append(pk) 48 | sig_sks.append(sk) 49 | 50 | noise_pks = [] 51 | noise_sks = [] 52 | for _ in range(n): 53 | sk = pysodium.randombytes(pysodium.crypto_scalarmult_SCALARBYTES) 54 | pk = pysodium.crypto_scalarmult_base(sk) 55 | noise_sks.append(sk) 56 | noise_pks.append(pk) 57 | 58 | # initialize the TP and get the first message 59 | stp, msg0 = pyoprf.stp_dkg_start_stp(n, t, ts_epsilon, "pyoprf stp_dkg test", sig_pks, sig_sks[0]) 60 | 61 | print(f"n: {pyoprf.stp_dkg_stpstate_n(stp)}, t: {pyoprf.stp_dkg_stpstate_t(stp)}, sid: {bytes(c for c in pyoprf.stp_dkg_stpstate_sessionid(stp)).hex()}") 62 | 63 | # initialize all peers with the 1st message from TP 64 | 65 | keystore = { pysodium.crypto_generichash(s): (s, n) for s,n in zip(sig_pks[1:], noise_pks)} 66 | #typedef int (*Keyloader_CB)(const uint8_t id[crypto_generichash_BYTES], 67 | # void *arg, 68 | # uint8_t sigpk[crypto_sign_PUBLICKEYBYTES], 69 | # uint8_t noise_pk[crypto_scalarmult_BYTES]); 70 | @c.CFUNCTYPE(c.c_int, c.POINTER(c.c_ubyte), c.POINTER(c.c_ubyte), c.POINTER(c.c_ubyte), c.POINTER(c.c_ubyte)) 71 | def load_key(keyid, arg, sig_pk, noise_pk): 72 | rec = keystore.get(bytes(keyid[:pysodium.crypto_generichash_BYTES])) 73 | if rec is None: return 1 74 | c.memmove(sig_pk, rec[0], len(rec[0])) 75 | c.memmove(noise_pk, rec[1], len(rec[1])) 76 | return 0 77 | 78 | peers=[] 79 | for i in range(n): 80 | peer = pyoprf.stp_dkg_peer_start(ts_epsilon, sig_sks[i+1], noise_sks[i], sig_pks[0], msg0, keyloader=load_key) 81 | peers.append(peer) 82 | 83 | for i in range(n): 84 | assert(pyoprf.stp_dkg_peerstate_sessionid(peers[i]) == pyoprf.stp_dkg_stpstate_sessionid(stp)) 85 | assert(sig_sks[i+1] == pyoprf.stp_dkg_peerstate_lt_sk(peers[i])) 86 | 87 | peer_msgs = [] 88 | while pyoprf.stp_dkg_stp_not_done(stp): 89 | ret, sizes = pyoprf.stp_dkg_stp_input_sizes(stp) 90 | # peer_msgs = (recv(size) for size in sizes) 91 | msgs = b''.join(peer_msgs) 92 | 93 | cur_step = pyoprf.stp_dkg_stpstate_step(stp) 94 | try: 95 | stp_out = pyoprf.stp_dkg_stp_next(stp, msgs) 96 | #print(f"tp: msg[{tp[0].step}]: {tp_out.raw.hex()}") 97 | except Exception as e: 98 | #cheaters, cheats = pyoprf.stp_dkg_get_cheaters(stp) 99 | #print(f"Warning during the distributed key generation the peers misbehaved: {sorted(cheaters)}") 100 | #for k, v in cheats: 101 | # print(f"\tmisbehaving peer: {k} was caught: {v}") 102 | raise ValueError(f"{e} | tp step {cur_step}") 103 | 104 | peer_msgs = [] 105 | while(len(b''.join(peer_msgs))==0 and pyoprf.stp_dkg_peer_not_done(peers[0])): 106 | for i in range(n): 107 | if(len(stp_out)>0): 108 | msg = pyoprf.stp_dkg_stp_peer_msg(stp, stp_out, i) 109 | #print(f"tp -> peer[{i+1}] {msg.hex()}") 110 | else: 111 | msg = '' 112 | out = pyoprf.stp_dkg_peer_next(peers[i], msg) 113 | if(len(out)>0): 114 | peer_msgs.append(out) 115 | #print(f"peer[{i+1}] -> tp {peer_msgs[-1].hex()}") 116 | stp_out = '' 117 | 118 | # we are done, let's check the shares 119 | 120 | k0shares = [pyoprf.stp_dkg_peerstate_share(peers[i]) for i in range(n)] 121 | k0commitments = pyoprf.stp_dkg_stpstate_commitments(stp) 122 | print("commitments", k0commitments) 123 | for i, share in enumerate(k0shares): 124 | print(f"share[{i+1}] {share.hex()} {k0commitments[i].hex()}") 125 | ci = pyoprf.stp_dkg_peerstate_commitments(peers[i]) 126 | assert ci == k0commitments 127 | 128 | kc0, blind = pyoprf.dkg_vss_reconstruct(n, t, 0, k0shares, k0commitments) 129 | print("kc0 is", kc0.hex()) 130 | 131 | for s_sub in combinations(k0shares, t): 132 | v, _ = pyoprf.dkg_vss_reconstruct(n, t, 0, s_sub) 133 | assert kc0 == v 134 | 135 | keyid = pyoprf.stp_dkg_stpstate_sessionid(stp) 136 | 137 | # clean up allocated buffers 138 | for i in range(n): 139 | pyoprf.stp_dkg_peer_free(peers[i]) 140 | 141 | # calculate some OPRF 142 | 143 | r, alpha = pyoprf.blind(b"test") 144 | betas = tuple(s[:1]+pyoprf.evaluate(s[1:33], alpha) for s in k0shares) 145 | beta = pyoprf.thresholdmult(betas) 146 | oprfed_test = pyoprf.unblind(r, beta) 147 | 148 | print('oprf("test")', oprfed_test.hex()) 149 | 150 | # tOPRF update 151 | 152 | stp, msg0 = pyoprf.tupdate_start_stp(n, t, ts_epsilon, "tOPRF update test", sig_pks, keyid, sig_sks[0], k0commitments) 153 | 154 | for s,p in zip(sig_sks, sig_pks): 155 | print("sp", s.hex(), p.hex()) 156 | for s,p in zip(noise_sks, noise_pks): 157 | print("nsp", s.hex(), p.hex()) 158 | 159 | peers=[] 160 | for i in range(n): 161 | ctx, keyid, stp_pub = pyoprf.tupdate_peer_start(ts_epsilon, sig_sks[i+1], noise_sks[i], msg0) 162 | #print(keyid.hex(), stp_pub.hex()) 163 | # based on keyid load the relevant parameters: n, t, share, commitment. 164 | ctx = pyoprf.tupdate_peer_set_bufs(ctx, n, t, i+1, sig_pks, noise_pks, k0shares[i], k0commitments) 165 | peers.append(ctx) 166 | #print(ctx) 167 | 168 | for i in range(n): 169 | assert(pyoprf.tupdate_peerstate_sessionid(peers[i]) == pyoprf.tupdate_stpstate_sessionid(stp)) 170 | 171 | peer_msgs = [] 172 | while pyoprf.tupdate_peer_not_done(peers[0]): 173 | peer_msgs = [] 174 | while(len(b''.join(peer_msgs))==0 and pyoprf.tupdate_peer_not_done(peers[0])): 175 | for i in range(n): 176 | if(len(stp_out)>0): 177 | msg = pyoprf.tupdate_stp_peer_msg(stp, stp_out, i) 178 | #print(f"tp -> peer[{i+1}] {msg.hex()}") 179 | else: 180 | msg = '' 181 | out = pyoprf.tupdate_peer_next(peers[i], msg) 182 | if(len(out)>0): 183 | peer_msgs.append(out) 184 | #print(f"peer[{i+1}] -> tp {peer_msgs[-1].hex()}") 185 | stp_out = '' 186 | if pyoprf.tupdate_stp_not_done(stp): 187 | ret, sizes = pyoprf.tupdate_stp_input_sizes(stp) 188 | # peer_msgs = (recv(size) for size in sizes) 189 | msgs = b''.join(peer_msgs) 190 | 191 | cur_step = pyoprf.tupdate_stpstate_step(stp) 192 | try: 193 | stp_out = pyoprf.tupdate_stp_next(stp, msgs) 194 | #print(f"tp: msg[{tp[0].step}]: {tp_out.raw.hex()}") 195 | except Exception as e: 196 | #cheaters, cheats = pyoprf.stp_dkg_get_cheaters(stp) 197 | #print(f"Warning during the distributed key generation the peers misbehaved: {sorted(cheaters)}") 198 | #for k, v in cheats: 199 | # print(f"\tmisbehaving peer: {k} was caught: {v}") 200 | raise ValueError(f"{e} | tp step {cur_step}") 201 | 202 | delta = pyoprf.tupdate_stpstate_delta(stp) 203 | print("delta", delta.hex()) 204 | 205 | k1shares = [pyoprf.tupdate_peerstate_share(peers[i]) for i in range(n)] 206 | k1commitments = tuple(pyoprf.tupdate_peerstate_commitment(peers[i]) for i in range(n)) 207 | assert k1commitments == pyoprf.tupdate_stpstate_commitments(stp) 208 | for i, share in enumerate(k1shares): 209 | print(f"share[{i+1}] {share.hex()} {k1commitments[i].hex()}") 210 | assert k1commitments == pyoprf.tupdate_peerstate_commitments(peers[i]) 211 | 212 | kc1, blind = pyoprf.dkg_vss_reconstruct(n, t, 0, k1shares, k1commitments) 213 | print("kc1 is", kc1.hex()) 214 | 215 | for s_sub in combinations(k1shares, t): 216 | v, _ = pyoprf.dkg_vss_reconstruct(n, t, 0, s_sub) 217 | assert kc1 == v 218 | 219 | kc0inv = pysodium.crypto_core_ristretto255_scalar_invert(kc0) 220 | deltakc = pysodium.crypto_core_ristretto255_scalar_mul(kc1, kc0inv) 221 | print("delta", deltakc.hex()) 222 | assert delta == deltakc 223 | 224 | updated_test = pysodium.crypto_scalarmult_ristretto255(deltakc, oprfed_test) 225 | 226 | r, alpha = pyoprf.blind(b"test") 227 | betas = tuple(s[:1]+pyoprf.evaluate(s[1:33], alpha) for s in k1shares) 228 | beta = pyoprf.thresholdmult(betas) 229 | updated_oprfed_test = pyoprf.unblind(r, beta) 230 | 231 | print('updated oprf\'("test")', updated_test.hex()) 232 | print('oprf\'("test") ', updated_oprfed_test.hex()) 233 | 234 | assert updated_test == updated_oprfed_test 235 | -------------------------------------------------------------------------------- /src/noise_xk/include/karmel/minimal/FStar_UInt128_Verified.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) INRIA and Microsoft Corporation. All rights reserved. 3 | Licensed under the Apache 2.0 License. 4 | */ 5 | 6 | 7 | #ifndef __FStar_UInt128_Verified_H 8 | #define __FStar_UInt128_Verified_H 9 | 10 | #include "FStar_UInt_8_16_32_64.h" 11 | #include 12 | #include 13 | #include "krml/internal/types.h" 14 | #include "krml/internal/target.h" 15 | 16 | static inline uint64_t FStar_UInt128_constant_time_carry(uint64_t a, uint64_t b) 17 | { 18 | return (a ^ ((a ^ b) | ((a - b) ^ b))) >> 63U; 19 | } 20 | 21 | static inline uint64_t FStar_UInt128_carry(uint64_t a, uint64_t b) 22 | { 23 | return FStar_UInt128_constant_time_carry(a, b); 24 | } 25 | 26 | static inline FStar_UInt128_uint128 27 | FStar_UInt128_add(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 28 | { 29 | FStar_UInt128_uint128 lit; 30 | lit.low = a.low + b.low; 31 | lit.high = a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low); 32 | return lit; 33 | } 34 | 35 | static inline FStar_UInt128_uint128 36 | FStar_UInt128_add_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 37 | { 38 | FStar_UInt128_uint128 lit; 39 | lit.low = a.low + b.low; 40 | lit.high = a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low); 41 | return lit; 42 | } 43 | 44 | static inline FStar_UInt128_uint128 45 | FStar_UInt128_add_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 46 | { 47 | FStar_UInt128_uint128 lit; 48 | lit.low = a.low + b.low; 49 | lit.high = a.high + b.high + FStar_UInt128_carry(a.low + b.low, b.low); 50 | return lit; 51 | } 52 | 53 | static inline FStar_UInt128_uint128 54 | FStar_UInt128_sub(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 55 | { 56 | FStar_UInt128_uint128 lit; 57 | lit.low = a.low - b.low; 58 | lit.high = a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low); 59 | return lit; 60 | } 61 | 62 | static inline FStar_UInt128_uint128 63 | FStar_UInt128_sub_underspec(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 64 | { 65 | FStar_UInt128_uint128 lit; 66 | lit.low = a.low - b.low; 67 | lit.high = a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low); 68 | return lit; 69 | } 70 | 71 | static inline FStar_UInt128_uint128 72 | FStar_UInt128_sub_mod_impl(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 73 | { 74 | FStar_UInt128_uint128 lit; 75 | lit.low = a.low - b.low; 76 | lit.high = a.high - b.high - FStar_UInt128_carry(a.low, a.low - b.low); 77 | return lit; 78 | } 79 | 80 | static inline FStar_UInt128_uint128 81 | FStar_UInt128_sub_mod(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 82 | { 83 | return FStar_UInt128_sub_mod_impl(a, b); 84 | } 85 | 86 | static inline FStar_UInt128_uint128 87 | FStar_UInt128_logand(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 88 | { 89 | FStar_UInt128_uint128 lit; 90 | lit.low = a.low & b.low; 91 | lit.high = a.high & b.high; 92 | return lit; 93 | } 94 | 95 | static inline FStar_UInt128_uint128 96 | FStar_UInt128_logxor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 97 | { 98 | FStar_UInt128_uint128 lit; 99 | lit.low = a.low ^ b.low; 100 | lit.high = a.high ^ b.high; 101 | return lit; 102 | } 103 | 104 | static inline FStar_UInt128_uint128 105 | FStar_UInt128_logor(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 106 | { 107 | FStar_UInt128_uint128 lit; 108 | lit.low = a.low | b.low; 109 | lit.high = a.high | b.high; 110 | return lit; 111 | } 112 | 113 | static inline FStar_UInt128_uint128 FStar_UInt128_lognot(FStar_UInt128_uint128 a) 114 | { 115 | FStar_UInt128_uint128 lit; 116 | lit.low = ~a.low; 117 | lit.high = ~a.high; 118 | return lit; 119 | } 120 | 121 | static uint32_t FStar_UInt128_u32_64 = 64U; 122 | 123 | static inline uint64_t FStar_UInt128_add_u64_shift_left(uint64_t hi, uint64_t lo, uint32_t s) 124 | { 125 | return (hi << s) + (lo >> (FStar_UInt128_u32_64 - s)); 126 | } 127 | 128 | static inline uint64_t 129 | FStar_UInt128_add_u64_shift_left_respec(uint64_t hi, uint64_t lo, uint32_t s) 130 | { 131 | return FStar_UInt128_add_u64_shift_left(hi, lo, s); 132 | } 133 | 134 | static inline FStar_UInt128_uint128 135 | FStar_UInt128_shift_left_small(FStar_UInt128_uint128 a, uint32_t s) 136 | { 137 | if (s == 0U) 138 | { 139 | return a; 140 | } 141 | else 142 | { 143 | FStar_UInt128_uint128 lit; 144 | lit.low = a.low << s; 145 | lit.high = FStar_UInt128_add_u64_shift_left_respec(a.high, a.low, s); 146 | return lit; 147 | } 148 | } 149 | 150 | static inline FStar_UInt128_uint128 151 | FStar_UInt128_shift_left_large(FStar_UInt128_uint128 a, uint32_t s) 152 | { 153 | FStar_UInt128_uint128 lit; 154 | lit.low = 0ULL; 155 | lit.high = a.low << (s - FStar_UInt128_u32_64); 156 | return lit; 157 | } 158 | 159 | static inline FStar_UInt128_uint128 160 | FStar_UInt128_shift_left(FStar_UInt128_uint128 a, uint32_t s) 161 | { 162 | if (s < FStar_UInt128_u32_64) 163 | { 164 | return FStar_UInt128_shift_left_small(a, s); 165 | } 166 | else 167 | { 168 | return FStar_UInt128_shift_left_large(a, s); 169 | } 170 | } 171 | 172 | static inline uint64_t FStar_UInt128_add_u64_shift_right(uint64_t hi, uint64_t lo, uint32_t s) 173 | { 174 | return (lo >> s) + (hi << (FStar_UInt128_u32_64 - s)); 175 | } 176 | 177 | static inline uint64_t 178 | FStar_UInt128_add_u64_shift_right_respec(uint64_t hi, uint64_t lo, uint32_t s) 179 | { 180 | return FStar_UInt128_add_u64_shift_right(hi, lo, s); 181 | } 182 | 183 | static inline FStar_UInt128_uint128 184 | FStar_UInt128_shift_right_small(FStar_UInt128_uint128 a, uint32_t s) 185 | { 186 | if (s == 0U) 187 | { 188 | return a; 189 | } 190 | else 191 | { 192 | FStar_UInt128_uint128 lit; 193 | lit.low = FStar_UInt128_add_u64_shift_right_respec(a.high, a.low, s); 194 | lit.high = a.high >> s; 195 | return lit; 196 | } 197 | } 198 | 199 | static inline FStar_UInt128_uint128 200 | FStar_UInt128_shift_right_large(FStar_UInt128_uint128 a, uint32_t s) 201 | { 202 | FStar_UInt128_uint128 lit; 203 | lit.low = a.high >> (s - FStar_UInt128_u32_64); 204 | lit.high = 0ULL; 205 | return lit; 206 | } 207 | 208 | static inline FStar_UInt128_uint128 209 | FStar_UInt128_shift_right(FStar_UInt128_uint128 a, uint32_t s) 210 | { 211 | if (s < FStar_UInt128_u32_64) 212 | { 213 | return FStar_UInt128_shift_right_small(a, s); 214 | } 215 | else 216 | { 217 | return FStar_UInt128_shift_right_large(a, s); 218 | } 219 | } 220 | 221 | static inline bool FStar_UInt128_eq(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 222 | { 223 | return a.low == b.low && a.high == b.high; 224 | } 225 | 226 | static inline bool FStar_UInt128_gt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 227 | { 228 | return a.high > b.high || (a.high == b.high && a.low > b.low); 229 | } 230 | 231 | static inline bool FStar_UInt128_lt(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 232 | { 233 | return a.high < b.high || (a.high == b.high && a.low < b.low); 234 | } 235 | 236 | static inline bool FStar_UInt128_gte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 237 | { 238 | return a.high > b.high || (a.high == b.high && a.low >= b.low); 239 | } 240 | 241 | static inline bool FStar_UInt128_lte(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 242 | { 243 | return a.high < b.high || (a.high == b.high && a.low <= b.low); 244 | } 245 | 246 | static inline FStar_UInt128_uint128 247 | FStar_UInt128_eq_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 248 | { 249 | FStar_UInt128_uint128 lit; 250 | lit.low = FStar_UInt64_eq_mask(a.low, b.low) & FStar_UInt64_eq_mask(a.high, b.high); 251 | lit.high = FStar_UInt64_eq_mask(a.low, b.low) & FStar_UInt64_eq_mask(a.high, b.high); 252 | return lit; 253 | } 254 | 255 | static inline FStar_UInt128_uint128 256 | FStar_UInt128_gte_mask(FStar_UInt128_uint128 a, FStar_UInt128_uint128 b) 257 | { 258 | FStar_UInt128_uint128 lit; 259 | lit.low = 260 | (FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high)) 261 | | (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low)); 262 | lit.high = 263 | (FStar_UInt64_gte_mask(a.high, b.high) & ~FStar_UInt64_eq_mask(a.high, b.high)) 264 | | (FStar_UInt64_eq_mask(a.high, b.high) & FStar_UInt64_gte_mask(a.low, b.low)); 265 | return lit; 266 | } 267 | 268 | static inline FStar_UInt128_uint128 FStar_UInt128_uint64_to_uint128(uint64_t a) 269 | { 270 | FStar_UInt128_uint128 lit; 271 | lit.low = a; 272 | lit.high = 0ULL; 273 | return lit; 274 | } 275 | 276 | static inline uint64_t FStar_UInt128_uint128_to_uint64(FStar_UInt128_uint128 a) 277 | { 278 | return a.low; 279 | } 280 | 281 | static inline uint64_t FStar_UInt128_u64_mod_32(uint64_t a) 282 | { 283 | return a & 0xffffffffULL; 284 | } 285 | 286 | static uint32_t FStar_UInt128_u32_32 = 32U; 287 | 288 | static inline uint64_t FStar_UInt128_u32_combine(uint64_t hi, uint64_t lo) 289 | { 290 | return lo + (hi << FStar_UInt128_u32_32); 291 | } 292 | 293 | static inline FStar_UInt128_uint128 FStar_UInt128_mul32(uint64_t x, uint32_t y) 294 | { 295 | FStar_UInt128_uint128 lit; 296 | lit.low = 297 | FStar_UInt128_u32_combine((x >> FStar_UInt128_u32_32) 298 | * (uint64_t)y 299 | + (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32), 300 | FStar_UInt128_u64_mod_32(FStar_UInt128_u64_mod_32(x) * (uint64_t)y)); 301 | lit.high = 302 | ((x >> FStar_UInt128_u32_32) 303 | * (uint64_t)y 304 | + (FStar_UInt128_u64_mod_32(x) * (uint64_t)y >> FStar_UInt128_u32_32)) 305 | >> FStar_UInt128_u32_32; 306 | return lit; 307 | } 308 | 309 | static inline uint64_t FStar_UInt128_u32_combine_(uint64_t hi, uint64_t lo) 310 | { 311 | return lo + (hi << FStar_UInt128_u32_32); 312 | } 313 | 314 | static inline FStar_UInt128_uint128 FStar_UInt128_mul_wide(uint64_t x, uint64_t y) 315 | { 316 | FStar_UInt128_uint128 lit; 317 | lit.low = 318 | FStar_UInt128_u32_combine_(FStar_UInt128_u64_mod_32(x) 319 | * (y >> FStar_UInt128_u32_32) 320 | + 321 | FStar_UInt128_u64_mod_32((x >> FStar_UInt128_u32_32) 322 | * FStar_UInt128_u64_mod_32(y) 323 | + (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32)), 324 | FStar_UInt128_u64_mod_32(FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y))); 325 | lit.high = 326 | (x >> FStar_UInt128_u32_32) 327 | * (y >> FStar_UInt128_u32_32) 328 | + 329 | (((x >> FStar_UInt128_u32_32) 330 | * FStar_UInt128_u64_mod_32(y) 331 | + (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32)) 332 | >> FStar_UInt128_u32_32) 333 | + 334 | ((FStar_UInt128_u64_mod_32(x) 335 | * (y >> FStar_UInt128_u32_32) 336 | + 337 | FStar_UInt128_u64_mod_32((x >> FStar_UInt128_u32_32) 338 | * FStar_UInt128_u64_mod_32(y) 339 | + (FStar_UInt128_u64_mod_32(x) * FStar_UInt128_u64_mod_32(y) >> FStar_UInt128_u32_32))) 340 | >> FStar_UInt128_u32_32); 341 | return lit; 342 | } 343 | 344 | 345 | #define __FStar_UInt128_Verified_H_DEFINED 346 | #endif 347 | -------------------------------------------------------------------------------- /python/pyoprf/noisexk.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Wrapper for hacl-star XK_Noise 4 | 5 | SPDX-FileCopyrightText: 2024, Marsiske Stefan 6 | SPDX-License-Identifier: LGPL-3.0-or-later 7 | 8 | Copyright (c) 2024, Marsiske Stefan. 9 | All rights reserved. 10 | 11 | This file is part of liboprf. 12 | 13 | liboprf is free software: you can redistribute it and/or 14 | modify it under the terms of the GNU Lesser General Public License 15 | as published by the Free Software Foundation, either version 3 of 16 | the License, or (at your option) any later version. 17 | 18 | liboprf is distributed in the hope that it will be 19 | useful, but WITHOUT ANY WARRANTY; without even the implied 20 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 21 | See the GNU Lesser General Public License for more details. 22 | 23 | You should have received a copy of the GNU Lesser General Public License 24 | along with liboprf. If not, see . 25 | 26 | """ 27 | 28 | 29 | import ctypes 30 | import ctypes.util 31 | from ctypes import c_void_p, c_ubyte, c_uint32, c_char, c_size_t, POINTER, byref 32 | 33 | lib = ctypes.cdll.LoadLibrary(ctypes.util.find_library('oprf-noiseXK') 34 | or ctypes.util.find_library('liboprf-noiseXK')) 35 | if not lib._name: 36 | raise ValueError('Unable to find liboprf-noiseXK') 37 | libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c') or ctypes.util.find_library('libc')) 38 | if not libc._name: 39 | raise ValueError('Unable to find libc') 40 | 41 | KEYSIZE = 32 42 | NOISE_XK_CONF_ZERO = 0 43 | NOISE_XK_AUTH_KNOWN_SENDER_NO_KCI = 2 44 | NOISE_XK_CONF_STRONG_FORWARD_SECRECY = 5 45 | 46 | def __check(code): 47 | if code != 0: 48 | raise ValueError 49 | 50 | lib.Noise_XK_device_add_peer.restype = c_void_p 51 | lib.Noise_XK_device_add_peer.argtypes = [c_void_p, c_void_p, ctypes.c_char_p] 52 | def add_peer(device, name, key): 53 | return lib.Noise_XK_device_add_peer(device, name, key) 54 | 55 | def pubkey(privkey): 56 | pubkey = ctypes.create_string_buffer(KEYSIZE) 57 | lib.Noise_XK_dh_secret_to_public(pubkey, privkey) 58 | return pubkey.raw 59 | 60 | lib.Noise_XK_device_create.restype = c_void_p 61 | def create_device(prologue, name, privkey): 62 | srlz_key = b'\x00'*KEYSIZE 63 | return lib.Noise_XK_device_create(len(prologue), prologue, name, srlz_key, privkey) 64 | 65 | lib.Noise_XK_peer_get_id.restype = c_void_p 66 | lib.Noise_XK_peer_get_id.argtypes = [c_void_p] 67 | def get_peerid(peer): 68 | return lib.Noise_XK_peer_get_id(peer) 69 | 70 | lib.Noise_XK_session_create_initiator.restype = c_void_p 71 | lib.Noise_XK_session_create_initiator.argtypes = [c_void_p, c_void_p] 72 | def create_session_initiator(device, peerid): 73 | return lib.Noise_XK_session_create_initiator(device, peerid) 74 | 75 | 76 | lib.Noise_XK_session_create_initiator.restype = c_void_p 77 | lib.Noise_XK_session_create_initiator.argtypes = [c_void_p, c_void_p] 78 | def create_session_initiator(device, peerid): 79 | res = lib.Noise_XK_session_create_initiator(device, peerid) 80 | if res == 0: raise ValueError 81 | return res 82 | 83 | lib.Noise_XK_session_create_responder.restype = c_void_p 84 | lib.Noise_XK_session_create_responder.argtypes = [c_void_p] 85 | def create_session_responder(device): 86 | res = lib.Noise_XK_session_create_responder(device) 87 | if res == 0: raise ValueError 88 | return res 89 | 90 | lib.Noise_XK_pack_message_with_conf_level.restype = c_void_p 91 | lib.Noise_XK_session_write.argtypes = [c_void_p, c_void_p, POINTER(c_uint32), POINTER(POINTER(c_ubyte))] 92 | lib.Noise_XK_encap_message_p_free.argtypes = [c_void_p] 93 | def initiator_1st_msg(session): 94 | encap_msg = lib.Noise_XK_pack_message_with_conf_level(0, 0, 0); 95 | msg_len = c_uint32() 96 | msg = POINTER(c_ubyte)() 97 | if 0!=lib.Noise_XK_session_write(encap_msg, session, byref(msg_len), byref(msg)): 98 | raise ValueError 99 | lib.Noise_XK_encap_message_p_free(encap_msg) 100 | res = bytes(msg[i] for i in range(msg_len.value)) 101 | if msg_len.value > 0: 102 | libc.free(msg) 103 | return res 104 | 105 | # Noise_XK_session_read(&encap_msg, bob_session, cipher_msg_len, cipher_msg); 106 | lib.Noise_XK_session_read.argtypes = [POINTER(c_void_p), c_void_p, c_uint32, POINTER(c_ubyte)] 107 | # Noise_XK_unpack_message_with_auth_level(&plain_msg_len, &plain_msg, NOISE_XK_AUTH_ZERO, encap_msg), 108 | def responder_1st_msg(session, msg): 109 | encap_msg = c_void_p() 110 | msg = (c_ubyte * len(msg)).from_buffer(bytearray(msg)) 111 | msg_len = c_uint32(len(msg)) 112 | if 0 != lib.Noise_XK_session_read(byref(encap_msg), session, msg_len, msg): 113 | raise ValueError 114 | plain_msg_len = c_uint32() 115 | plain_msg = POINTER(c_ubyte)() 116 | if not lib.Noise_XK_unpack_message_with_auth_level(byref(plain_msg_len), byref(plain_msg), 0, encap_msg): 117 | raise ValueError 118 | lib.Noise_XK_encap_message_p_free(encap_msg) 119 | if plain_msg_len.value > 0: 120 | libc.free(plain_msg) 121 | return initiator_1st_msg(session) 122 | 123 | def initiator_handshake_finish(session, msg): 124 | encap_msg = c_void_p() 125 | msg = (c_ubyte * len(msg)).from_buffer(bytearray(msg)) 126 | msg_len = c_uint32(len(msg)) 127 | if 0 != lib.Noise_XK_session_read(byref(encap_msg), session, msg_len, msg): 128 | raise ValueError 129 | plain_msg_len = c_uint32() 130 | plain_msg = POINTER(c_ubyte)() 131 | if not lib.Noise_XK_unpack_message_with_auth_level(byref(plain_msg_len), byref(plain_msg), 0, encap_msg): 132 | raise ValueError 133 | lib.Noise_XK_encap_message_p_free(encap_msg) 134 | if plain_msg_len.value > 0: 135 | libc.free(plain_msg) 136 | 137 | def send_msg(session, msg): 138 | if isinstance(msg, str): msg = msg.encode('utf8') 139 | encap_msg = lib.Noise_XK_pack_message_with_conf_level(NOISE_XK_CONF_STRONG_FORWARD_SECRECY, len(msg), msg); 140 | ct_len = c_uint32() 141 | ct = POINTER(c_ubyte)() 142 | if 0!=lib.Noise_XK_session_write(encap_msg, session, byref(ct_len), byref(ct)): 143 | raise ValueError 144 | lib.Noise_XK_encap_message_p_free(encap_msg) 145 | res = bytes(ct[:ct_len.value]) 146 | if ct_len.value > 0: 147 | libc.free(ct) 148 | return res 149 | 150 | def read_msg(session, msg): 151 | encap_msg = c_void_p() 152 | u_bytes = (c_ubyte * (len(msg)))() 153 | u_bytes[:] = msg 154 | if 0 != lib.Noise_XK_session_read(byref(encap_msg), session, len(msg), u_bytes): 155 | raise ValueError 156 | plain_msg_len = c_uint32() 157 | plain_msg = POINTER(c_ubyte)() 158 | if not lib.Noise_XK_unpack_message_with_auth_level(byref(plain_msg_len), byref(plain_msg), 159 | NOISE_XK_AUTH_KNOWN_SENDER_NO_KCI, encap_msg): 160 | raise ValueError 161 | lib.Noise_XK_encap_message_p_free(encap_msg) 162 | res = bytes(plain_msg[i] for i in range(plain_msg_len.value)) 163 | if plain_msg_len.value > 0: 164 | libc.free(plain_msg) 165 | return res 166 | 167 | lib.Noise_XK_session_get_peer_id.restype = c_uint32 168 | lib.Noise_XK_session_get_peer_id.argtypes = [c_void_p] 169 | lib.Noise_XK_device_lookup_peer_by_id.restype = c_void_p 170 | lib.Noise_XK_device_lookup_peer_by_id.argtypes = [c_void_p, c_uint32] 171 | lib.Noise_XK_peer_get_static.argtypes = [(c_char * 32), c_void_p] 172 | def get_pubkey(session, device): 173 | peerid = lib.Noise_XK_session_get_peer_id(session) 174 | peer = lib.Noise_XK_device_lookup_peer_by_id(device, peerid); 175 | pubkey = ctypes.create_string_buffer(KEYSIZE) 176 | lib.Noise_XK_peer_get_static(pubkey, peer); 177 | return pubkey.raw 178 | 179 | def initiator_session(initiator_privkey, responder_pubkey, iname=None, 180 | rname=None, dst=None): 181 | if dst is None: 182 | dst = b"liboprf-noiseXK" 183 | if iname is None: 184 | iname = b"initiator" 185 | if rname is None: 186 | rname = b"responder" 187 | #initiator_pubkey = pubkey(initiator_privkey) 188 | dev = create_device(dst, iname, initiator_privkey) 189 | peer = add_peer(dev, rname, responder_pubkey) 190 | peerid = get_peerid(peer) 191 | 192 | session = create_session_initiator(dev, peerid) 193 | msg = initiator_1st_msg(session) 194 | return session, msg 195 | 196 | libc.malloc.restype = POINTER(c_ubyte) 197 | def responder_session(responder_privkey, auth_keys, msg, dst=None, name=None): 198 | if dst is None: 199 | dst = b"liboprf-noiseXK" 200 | if name is None: 201 | name = b"responder" 202 | #responder_pubkey = pubkey(responder_privkey) 203 | dev = create_device(dst, name, responder_privkey) 204 | for key, peer in auth_keys: 205 | add_peer(dev,peer,key) 206 | session = create_session_responder(dev) 207 | msg = responder_1st_msg(session, msg) 208 | return session, msg 209 | 210 | def initiator_session_complete(session, msg): 211 | return initiator_handshake_finish(session, msg) 212 | 213 | def test(): 214 | from binascii import unhexlify, hexlify 215 | # low level 216 | alice_privkey = unhexlify("c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552") 217 | alice_pubkey = pubkey(alice_privkey) 218 | bob_privkey = unhexlify("c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552") 219 | bob_pubkey = pubkey(bob_privkey) 220 | 221 | adev = create_device("liboprf-noiseXK test", "Alice", alice_privkey) 222 | bpeer = add_peer(adev, "Bob", bob_pubkey) 223 | bobid = get_peerid(bpeer) 224 | 225 | bdev = create_device("liboprf-noiseXK test", "Bob", bob_privkey) 226 | add_peer(bdev, "Alice", alice_pubkey) 227 | 228 | asession = create_session_initiator(adev, bobid) 229 | bsession = create_session_responder(bdev) 230 | 231 | msg = initiator_1st_msg(asession) 232 | 233 | msg = responder_1st_msg(bsession, msg) 234 | 235 | initiator_handshake_finish(asession, msg) 236 | 237 | ct = send_msg(asession, "hello bob!") 238 | pt = read_msg(bsession, ct) 239 | 240 | peer_pk = get_pubkey(bsession, bdev) 241 | print(hexlify(peer_pk)) 242 | 243 | print(pt) 244 | ct = send_msg(bsession, "hello alice!") 245 | pt = read_msg(asession, ct) 246 | print(pt) 247 | 248 | # high-level 249 | a2session, msg = initiator_session(alice_privkey, bob_pubkey) 250 | b2session, msg = responder_session(bob_privkey, [(alice_pubkey, "Alice")], msg) 251 | initiator_session_complete(a2session, msg) 252 | 253 | ct = send_msg(a2session, "hello bob!") 254 | pt = read_msg(b2session, ct) 255 | print(pt) 256 | ct = send_msg(b2session, "hello alice!") 257 | pt = read_msg(a2session, ct) 258 | print(pt) 259 | 260 | for _ in range(1000): 261 | if ct[0] % 2 == 0: 262 | sender = a2session 263 | receiver = b2session 264 | else: 265 | sender = b2session 266 | receiver = a2session 267 | message = ct[:16+(ct[1]>>4)] * (ct[1] & 0xf) 268 | ct = send_msg(sender, message) 269 | pt = read_msg(receiver, ct) 270 | assert(pt == message) 271 | 272 | if __name__ == '__main__': 273 | test() 274 | --------------------------------------------------------------------------------