├── .gitignore ├── .travis.yml ├── AUTHORS.md ├── CODE_OF_CONDUCT.md ├── LICENSE.txt ├── Makefile ├── README.md ├── appveyor.yml ├── ci └── test.bat ├── include └── ristretto255.h ├── src ├── arch │ ├── 32 │ │ ├── arch_intrinsics.h │ │ ├── f_impl.c │ │ └── f_impl.h │ ├── arm32 │ │ └── arch_intrinsics.h │ ├── neon │ │ └── arch_intrinsics.h │ ├── ref64 │ │ ├── arch_intrinsics.h │ │ ├── f_impl.c │ │ └── f_impl.h │ └── x86_64 │ │ ├── arch_intrinsics.h │ │ ├── f_impl.c │ │ └── f_impl.h ├── bool.c ├── bzero.c ├── constant_time.h ├── elligator.c ├── f_arithmetic.c ├── f_field.h ├── field.h ├── portable_endian.h ├── ristretto.c ├── ristretto_gen_tables.c ├── scalar.c └── word.h └── tests ├── Cargo.lock ├── Cargo.toml ├── README.md ├── libristretto255-sys ├── Cargo.toml ├── build.rs └── src │ └── lib.rs └── src ├── constants.rs ├── lib.rs ├── ristretto.rs ├── scalar.rs ├── util.rs └── vectors.rs /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | /build 3 | /src/ristretto_tables.c 4 | /tests/target 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | install: 4 | - curl https://sh.rustup.rs -sSf | sh -s -- -y 5 | - export PATH=$PATH:~/.cargo/bin 6 | 7 | env: 8 | - XCFLAGS=-g 9 | 10 | script: 11 | - make 12 | - make test 13 | 14 | compiler: 15 | - gcc 16 | - clang 17 | 18 | os: 19 | - osx 20 | - linux 21 | 22 | matrix: 23 | fast_finish: true 24 | exclude: 25 | - os: linux 26 | compiler: clang 27 | include: 28 | - os: linux 29 | compiler: clang 30 | script: 31 | # Enable ASAN as a workaround for ristretto_gen_tables SEGV 32 | # See: https://github.com/Ristretto/libristretto255/issues/24 33 | - XCFLAGS="-g -fsanitize=address" XLDFLAGS=-fsanitize=address ASAN_OPTIONS=detect_leaks=0 make 34 | - make clean 35 | - make build/obj/bin/ristretto_gen_tables && rm build/obj/ristretto_gen_tables.o 36 | - clang -std=c99 -fno-strict-aliasing -g -Iinclude -Isrc -Isrc/arch/x86_64 -O2 -march=native -ffunction-sections -fdata-sections -fomit-frame-pointer -fPIC -c -o build/obj/ristretto_tables.o src/ristretto_tables.c 37 | - ar rcs build/lib/libristretto255.a build/obj/*.o 38 | - cd tests && cargo test --all --lib 39 | 40 | branches: 41 | only: 42 | - master 43 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # libristretto255 contributors 2 | 3 | This project is a fork of [libdecaf] by Mike Hamburg. libdecaf is 4 | Copyright (c) 2014-2017 Cryptography Research, Inc (a division of Rambus) 5 | and released under the [MIT license](https://sourceforge.net/p/ed448goldilocks/code/ci/master/tree/LICENSE.txt). 6 | 7 | [libdecaf]: https://sourceforge.net/projects/ed448goldilocks/ 8 | 9 | The following additional people (credited as "Ristretto Developers") have 10 | contributed to this library and have also granted the right to use their 11 | contributions under the terms of the [MIT license]: 12 | 13 | [MIT license]: https://github.com/Ristretto/libristretto255/blob/master/LICENSE.txt 14 | 15 | * [Tony Arcieri (@tarcieri)](https://github.com/tarcieri) 16 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [bascule@gmail.com]. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | [bascule@gmail.com]: mailto:bascule@gmail.com 69 | 70 | ## Attribution 71 | 72 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 73 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 74 | 75 | [homepage]: https://www.contributor-covenant.org 76 | 77 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2018 Ristretto Developers, Cryptography Research, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014-2018 Ristretto Developers, Cryptography Research, Inc. 2 | # Released under the MIT License. See LICENSE.txt for license information. 3 | 4 | UNAME := $(shell uname) 5 | MACHINE := $(shell uname -m) 6 | 7 | # Subdirectories for objects etc. 8 | BUILD_OBJ = build/obj 9 | BUILD_LIB = build/lib 10 | BUILD_IBIN = build/obj/bin 11 | 12 | # TODO: fix builds for non-x86_64 architectures 13 | ARCH ?= $(MACHINE) 14 | 15 | ifeq ($(UNAME),Darwin) 16 | CC ?= clang 17 | else 18 | CC ?= gcc 19 | endif 20 | 21 | LD = $(CC) 22 | AR ?= ar 23 | ASM ?= $(CC) 24 | 25 | WARNFLAGS = -pedantic -Wall -Wextra -Werror -Wunreachable-code \ 26 | -Wmissing-declarations -Wunused-function -Wno-overlength-strings $(EXWARN) 27 | 28 | INCFLAGS = -Iinclude -Isrc -Isrc/arch/$(ARCH) 29 | LANGFLAGS = -std=c99 -fno-strict-aliasing 30 | GENFLAGS = -ffunction-sections -fdata-sections -fomit-frame-pointer -fPIC 31 | OFLAGS ?= -O2 32 | 33 | MACOSX_VERSION_MIN ?= 10.9 34 | ifeq ($(UNAME),Darwin) 35 | GENFLAGS += -mmacosx-version-min=$(MACOSX_VERSION_MIN) 36 | endif 37 | 38 | ARCHFLAGS ?= -march=native 39 | 40 | ifeq ($(CC),clang) 41 | WARNFLAGS_C += -Wgcc-compat 42 | endif 43 | 44 | ARCHFLAGS += $(XARCHFLAGS) 45 | CFLAGS = $(LANGFLAGS) $(WARNFLAGS) $(WARNFLAGS_C) $(INCFLAGS) $(OFLAGS) $(ARCHFLAGS) $(GENFLAGS) $(XCFLAGS) 46 | LDFLAGS = $(XLDFLAGS) 47 | ASFLAGS = $(ARCHFLAGS) $(XASFLAGS) 48 | 49 | .PHONY: clean test all lib 50 | .PRECIOUS: src/%.c src/*/%.c include/%.h include/*/%.h $(BUILD_IBIN)/% 51 | 52 | HEADERS= Makefile $(BUILD_OBJ)/timestamp 53 | 54 | # components needed by all targets 55 | COMPONENTS = $(BUILD_OBJ)/bool.o \ 56 | $(BUILD_OBJ)/bzero.o \ 57 | $(BUILD_OBJ)/f_impl.o \ 58 | $(BUILD_OBJ)/f_arithmetic.o \ 59 | $(BUILD_OBJ)/ristretto.o \ 60 | $(BUILD_OBJ)/scalar.o 61 | 62 | # components needed by libristretto255.so 63 | LIBCOMPONENTS = $(COMPONENTS) $(BUILD_OBJ)/elligator.o $(BUILD_OBJ)/ristretto_tables.o 64 | 65 | # components needed by the ristretto_gen_tables binary 66 | GENCOMPONENTS = $(COMPONENTS) $(BUILD_OBJ)/ristretto_gen_tables.o 67 | 68 | all: lib 69 | 70 | # Create all the build subdirectories 71 | $(BUILD_OBJ)/timestamp: 72 | mkdir -p $(BUILD_OBJ) $(BUILD_LIB) $(BUILD_IBIN) 73 | touch $@ 74 | 75 | $(BUILD_OBJ)/f_impl.o: src/arch/$(ARCH)/f_impl.c $(HEADERS) 76 | $(CC) $(CFLAGS) -c -o $@ $< 77 | 78 | $(BUILD_IBIN)/ristretto_gen_tables: $(GENCOMPONENTS) 79 | $(LD) $(LDFLAGS) -o $@ $^ 80 | 81 | src/ristretto_tables.c: $(BUILD_IBIN)/ristretto_gen_tables 82 | ./$< > $@ || (rm $@; exit 1) 83 | 84 | # The libristretto255 library 85 | lib: $(BUILD_LIB)/libristretto255.so $(BUILD_LIB)/libristretto255.a 86 | 87 | $(BUILD_LIB)/libristretto255.so: $(BUILD_LIB)/libristretto255.so.1 88 | ln -sf `basename $^` $@ 89 | 90 | $(BUILD_LIB)/libristretto255.so.1: $(LIBCOMPONENTS) 91 | rm -f $@ 92 | ifeq ($(UNAME),Darwin) 93 | libtool -macosx_version_min $(MACOSX_VERSION_MIN) -dynamic -dead_strip -lc -x -o $@ \ 94 | $(LIBCOMPONENTS) 95 | else ifeq ($(UNAME),SunOS) 96 | $(LD) $(LDFLAGS) -shared -Wl,-soname,`basename $@` -o $@ $(LIBCOMPONENTS) 97 | strip --discard-all $@ 98 | else 99 | $(LD) $(LDFLAGS) -shared -Wl,-soname,`basename $@` -Wl,--gc-sections -o $@ $(LIBCOMPONENTS) 100 | strip --discard-all $@ 101 | endif 102 | 103 | $(BUILD_LIB)/libristretto255.a: $(LIBCOMPONENTS) 104 | $(AR) rcs $@ $(LIBCOMPONENTS) 105 | 106 | $(BUILD_OBJ)/%.o: src/%.c $(HEADERS) 107 | $(CC) $(CFLAGS) -c -o $@ $< 108 | 109 | # Test suite: requires Rust is installed 110 | test: $(BUILD_LIB)/libristretto255.a 111 | cd tests && cargo test --all --lib 112 | 113 | clean: 114 | rm -fr build tests/target 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **DISCONTINUED:** Please check out [ristretto-donna](https://github.com/isislovecruft/ristretto-donna) instead if you are looking for a Ristretto C library 2 | 3 | # libristretto255 [![Build Status][build-image]][build-link] [![Appveyor Status][appveyor-image]][appveyor-link] 4 | 5 | [build-image]: https://travis-ci.org/Ristretto/libristretto255.svg?branch=master 6 | [build-link]: https://travis-ci.org/Ristretto/libristretto255 7 | [appveyor-image]: https://ci.appveyor.com/api/projects/status/nn8d1gwg9agumo9l?svg=true 8 | [appveyor-link]: https://ci.appveyor.com/project/tarcieri/libristretto255 9 | 10 | 11 | 12 | Experimental C implementation of **Ristretto255**, a prime order elliptic curve 13 | group created by applying the [Decaf] approach to cofactor elimination to 14 | [Curve25519] ([RFC 7748]). 15 | 16 | libristretto255 is based off of the [libdecaf] library by Mike Hamburg. 17 | For more information on Ristretto, please see the Ristretto web site: 18 | 19 | https://ristretto.group/ 20 | 21 | [Decaf]: https://www.shiftleft.org/papers/decaf/ 22 | [Curve25519]: https://en.wikipedia.org/wiki/Curve25519 23 | [RFC 7748]: https://tools.ietf.org/html/rfc7748 24 | [libdecaf]: https://sourceforge.net/p/ed448goldilocks/wiki/Home/ 25 | 26 | ## Status 27 | 28 | This library is in an extremely early stage of development and is not ready to 29 | be used yet. Check back later for updates. 30 | 31 | ### Known Issues 32 | 33 | #### Travis CI 34 | 35 | * [#24]: Sporadic SEGV on Travis C with clang when running 36 | `ristretto_gen_tables`. This has been worked-around by enabling ASAN, 37 | but is probably indicative of deeper problems. 38 | 39 | [#24]: https://github.com/Ristretto/libristretto255/issues/24 40 | 41 | ## License 42 | 43 | Copyright (c) 2014-2018 Ristretto Developers ([AUTHORS.md]), 44 | Cryptography Research, Inc (a division of Rambus). 45 | 46 | Distributed under the MIT License. See [LICENSE.txt] for more information. 47 | 48 | [AUTHORS.md]: https://github.com/Ristretto/libristretto255/blob/master/AUTHORS.md 49 | [LICENSE.txt]: https://github.com/Ristretto/libristretto255/blob/master/LICENSE.txt 50 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | LLVM_VERSION: 5.0.0 3 | RUST_BACKTRACE: 1 4 | matrix: 5 | - TARGET: gnu 6 | # TODO: test MSVC: https://github.com/Ristretto/libristretto255/issues/30 7 | # - TARGET: msvc 8 | 9 | image: Visual Studio 2017 10 | 11 | platform: 12 | # TODO: 32-bit support: https://github.com/Ristretto/libristretto255/issues/29 13 | # - x86 14 | - x64 15 | 16 | branches: 17 | only: 18 | - master 19 | 20 | install: 21 | - if %PLATFORM% == x86 set ARCH=32&set RUST_PLATFORM=i686&set MINGW_BITS=32 22 | - if %PLATFORM% == x64 set RUST_PLATFORM=x86_64&set MINGW_BITS=64 23 | - if %PLATFORM% == x86 call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat" 24 | - if %PLATFORM% == x64 call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" 25 | - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 26 | - rustup-init.exe -y --default-host %RUST_PLATFORM%-pc-windows-%TARGET% --default-toolchain stable 27 | - set PATH=C:\msys64\usr\bin;%USERPROFILE%\.cargo\bin;%PATH% 28 | - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin 29 | - if %TARGET%==gnu set PATH=C:\msys64\mingw%MINGW_BITS%\bin;C:\msys64\usr\bin\;%PATH% 30 | - if %TARGET%==gnu set "MINGW_URL=http://repo.msys2.org/mingw/%RUST_PLATFORM%/mingw-w64-%RUST_PLATFORM%" 31 | - if %TARGET%==gnu set "URL_VER=%LLVM_VERSION%-1-any.pkg.tar.xz" 32 | - if %TARGET%==gnu bash -lc "pacman -U --noconfirm $MINGW_URL-clang-$URL_VER $MINGW_URL-llvm-$URL_VER" 33 | - if %TARGET%==gnu bash -lc "clang --version" 34 | - if %TARGET%==msvc appveyor-retry appveyor DownloadFile http://releases.llvm.org/%LLVM_VERSION%/LLVM-%LLVM_VERSION%-win64.exe -FileName llvm-installer.exe 35 | - if %TARGET%==msvc 7z x llvm-installer.exe -oc:\llvm-binary 36 | - if %TARGET%==msvc set PATH=C:\llvm-binary\bin;%PATH% 37 | - if %TARGET%==msvc where clang 38 | - if %TARGET%==msvc clang --version 39 | 40 | build_script: 41 | - if %TARGET%==gnu make 42 | - if %TARGET%==gnu make test 43 | - if %TARGET%==msvc call "ci\test.bat" 44 | 45 | test: off 46 | -------------------------------------------------------------------------------- /ci/test.bat: -------------------------------------------------------------------------------- 1 | echo "Running ci/test.bat" 2 | 3 | @echo on 4 | 5 | md build 6 | md build\lib 7 | md build\obj 8 | md build\obj\bin 9 | 10 | for %%c in (src\bool.c src\bzero.c src\arch\ref64\f_impl.c src\f_arithmetic.c src\ristretto.c src/ristretto_gen_tables.c src\scalar.c) do ( 11 | cl.exe /W4 /I include /I src /I src\arch\ref64 /Fo.\build\obj\ %%c 12 | ) 13 | 14 | link /out:build\obj\bin\ristretto_gen_tables.exe build\obj\*.obj 15 | bin\obj\bin\ristretto_gen_tables > src\ristretto_tables.c 16 | cl /W4 /I.\include /I.\src src\ristretto_tables.c /out:bin\obj\ristretto_tables.obj 17 | lib /out:build\lib\libristretto255.lib build\obj\bool.obj build\obj\bzero.obj build\obj\f_impl.obj build\obj\f_arithmetic.o build\ristretto.o build\scalar.obj 18 | 19 | cd tests 20 | cargo test --all --lib 21 | -------------------------------------------------------------------------------- /include/ristretto255.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ristretto255.h 3 | * @author Mike Hamburg 4 | * 5 | * @copyright 6 | * Copyright (c) 2015-2018 Ristretto Developers, Cryptography Research, Inc. \n 7 | * Released under the MIT License. See LICENSE.txt for license information. 8 | * 9 | * @brief A group of prime order p, based on Curve25519. 10 | */ 11 | 12 | #include 13 | #if defined (__GNUC__) // File only exists for GNU compilers 14 | #include 15 | #endif 16 | 17 | #ifndef __RISTRETTO255_H__ 18 | #define __RISTRETTO255_H__ 1 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | /* Aliasing MSVC preprocessing to GNU preprocessing */ 25 | #if defined _MSC_VER 26 | # define __attribute__(x) // Turn off attribute code 27 | # define __attribute(x) 28 | # define __restrict__ __restrict // Use MSVC restrict code 29 | //# define RISTRETTO_NOINLINE __declspec(noinline) // MSVC for noinline 30 | //# define RISTRETTO_INLINE __forceinline // MSVC for always inline 31 | //# define RISTRETTO_WARN_UNUSED _Check_return_ 32 | #endif 33 | 34 | // The following are disabled for MSVC 35 | #define RISTRETTO_NOINLINE __attribute__((noinline)) 36 | #define RISTRETTO_INLINE inline __attribute__((always_inline,unused)) 37 | #define RISTRETTO_WARN_UNUSED __attribute__((warn_unused_result)) 38 | #define RISTRETTO_NONNULL __attribute__((nonnull)) 39 | // Cribbed from libnotmuch 40 | #if defined (__clang_major__) && __clang_major__ >= 3 \ 41 | || defined (__GNUC__) && __GNUC__ >= 5 \ 42 | || defined (__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 5 43 | #define RISTRETTO_DEPRECATED(msg) __attribute__ ((deprecated(msg))) 44 | #else 45 | #define RISTRETTO_DEPRECATED(msg) __attribute__ ((deprecated)) 46 | #endif 47 | /** @endcond */ 48 | 49 | /* Internal word types. 50 | * 51 | * Somewhat tricky. This could be decided separately per platform. However, 52 | * the structs do need to be all the same size and alignment on a given 53 | * platform to support dynamic linking, since even if you header was built 54 | * with eg arch_neon, you might end up linking a library built with arch_arm32. 55 | */ 56 | #ifndef RISTRETTO_WORD_BITS 57 | #if (defined(__ILP64__) || defined(__amd64__) || defined(__x86_64__) || (((__UINT_FAST32_MAX__)>>30)>>30)) 58 | #define RISTRETTO_WORD_BITS 64 /**< The number of bits in a word */ 59 | #else 60 | #define RISTRETTO_WORD_BITS 32 /**< The number of bits in a word */ 61 | #endif 62 | #endif 63 | 64 | #if RISTRETTO_WORD_BITS == 64 65 | typedef uint64_t ristretto_word_t; /**< Word size for internal computations */ 66 | typedef int64_t ristretto_sword_t; /**< Signed word size for internal computations */ 67 | typedef uint64_t ristretto_bool_t; /**< "Boolean" type, will be set to all-zero or all-one (i.e. -1u) */ 68 | typedef __uint128_t ristretto_dword_t; /**< Double-word size for internal computations */ 69 | typedef __int128_t ristretto_dsword_t; /**< Signed double-word size for internal computations */ 70 | #elif RISTRETTO_WORD_BITS == 32 /**< The number of bits in a word */ 71 | typedef uint32_t ristretto_word_t; /**< Word size for internal computations */ 72 | typedef int32_t ristretto_sword_t; /**< Signed word size for internal computations */ 73 | typedef uint32_t ristretto_bool_t; /**< "Boolean" type, will be set to all-zero or all-one (i.e. -1u) */ 74 | typedef uint64_t ristretto_dword_t; /**< Double-word size for internal computations */ 75 | typedef int64_t ristretto_dsword_t; /**< Signed double-word size for internal computations */ 76 | #else 77 | #error "Only supporting RISTRETTO_WORD_BITS = 32 or 64 for now" 78 | #endif 79 | 80 | /** RISTRETTO_TRUE = -1 so that RISTRETTO_TRUE & x = x */ 81 | extern const ristretto_bool_t RISTRETTO_TRUE; 82 | 83 | /** RISTRETTO_FALSE = 0 so that RISTRETTO_FALSE & x = 0 */ 84 | extern const ristretto_bool_t RISTRETTO_FALSE; 85 | 86 | /** Another boolean type used to indicate success or failure. */ 87 | typedef enum { 88 | RISTRETTO_SUCCESS = -1, /**< The operation succeeded. */ 89 | RISTRETTO_FAILURE = 0 /**< The operation failed. */ 90 | } ristretto_error_t; 91 | 92 | 93 | /** Return success if x is true */ 94 | static RISTRETTO_INLINE ristretto_error_t 95 | ristretto_succeed_if(ristretto_bool_t x) { 96 | return (ristretto_error_t)x; 97 | } 98 | 99 | /** Return RISTRETTO_TRUE iff x == RISTRETTO_SUCCESS */ 100 | static RISTRETTO_INLINE ristretto_bool_t 101 | ristretto_successful(ristretto_error_t e) { 102 | ristretto_dword_t w = ((ristretto_word_t)e) ^ ((ristretto_word_t)RISTRETTO_SUCCESS); 103 | return (w-1)>>RISTRETTO_WORD_BITS; 104 | } 105 | 106 | /** Overwrite data with zeros. Uses memset_s if available. */ 107 | void ristretto_bzero ( 108 | void *data, 109 | size_t size 110 | ) RISTRETTO_NONNULL; 111 | 112 | /** @cond internal */ 113 | #define RISTRETTO255_SCALAR_LIMBS ((253-1)/RISTRETTO_WORD_BITS+1) 114 | /** @endcond */ 115 | 116 | /** The number of bits in a scalar */ 117 | #define RISTRETTO255_SCALAR_BITS 253 118 | 119 | /** @cond internal */ 120 | /** @brief Galois field element internal structure */ 121 | #define RISTRETTO255_FIELD_LIMBS (40/sizeof(ristretto_word_t)) 122 | 123 | typedef struct { 124 | ristretto_word_t limb[RISTRETTO255_FIELD_LIMBS]; 125 | } __attribute__((aligned(32))) gf_25519_t; 126 | /** @endcond */ 127 | 128 | /** Number of bytes in a serialized point. */ 129 | #define RISTRETTO255_SER_BYTES 32 130 | 131 | /** Number of bytes in an elligated point. For now set the same as SER_BYTES 132 | * but could be different for other curves. 133 | */ 134 | #define RISTRETTO255_HASH_BYTES 32 135 | 136 | /** Number of bytes in a serialized scalar. */ 137 | #define RISTRETTO255_SCALAR_BYTES 32 138 | 139 | /** Number of bits in the "which" field of an elligator inverse */ 140 | #define RISTRETTO255_INVERT_ELLIGATOR_WHICH_BITS 5 141 | 142 | /** The cofactor the curve would have, if we hadn't removed it */ 143 | #define RISTRETTO255_REMOVED_COFACTOR 8 144 | 145 | /** Representation of a point on the elliptic curve. */ 146 | typedef struct { 147 | /** @cond internal */ 148 | gf_25519_t x,y,z,t; /* Twisted extended homogeneous coordinates */ 149 | /** @endcond */ 150 | } ristretto255_point_t; 151 | 152 | /** Precomputed table based on a point. Can be trivial implementation. */ 153 | struct ristretto255_precomputed_s; 154 | 155 | /** Precomputed table based on a point. Can be trivial implementation. */ 156 | typedef struct ristretto255_precomputed_s ristretto255_precomputed_s; 157 | 158 | /** Size and alignment of precomputed point tables. */ 159 | extern const size_t ristretto255_sizeof_precomputed_s, ristretto255_alignof_precomputed_s; 160 | 161 | /** Representation of an element of the scalar field. */ 162 | typedef struct { 163 | /** @cond internal */ 164 | ristretto_word_t limb[RISTRETTO255_SCALAR_LIMBS]; 165 | /** @endcond */ 166 | } ristretto255_scalar_t; 167 | 168 | #if defined _MSC_VER 169 | 170 | /** The scalar 1. */ 171 | extern const ristretto255_scalar_t ristretto255_scalar_one; 172 | 173 | /** The scalar 0. */ 174 | extern const ristretto255_scalar_t ristretto255_scalar_zero; 175 | 176 | /** The identity (zero) point on the curve. */ 177 | extern const ristretto255_point_t ristretto255_point_identity; 178 | 179 | /** An arbitrarily-chosen base point on the curve. */ 180 | extern const ristretto255_point_t ristretto255_point_base; 181 | 182 | /** Precomputed table of multiples of the base point on the curve. */ 183 | extern const struct ristretto255_precomputed_s *ristretto255_precomputed_base; 184 | 185 | 186 | #else // _MSC_VER 187 | 188 | /** The scalar 1. */ 189 | extern const ristretto255_scalar_t ristretto255_scalar_one; 190 | 191 | /** The scalar 0. */ 192 | extern const ristretto255_scalar_t ristretto255_scalar_zero; 193 | 194 | /** The identity (zero) point on the curve. */ 195 | extern const ristretto255_point_t ristretto255_point_identity; 196 | 197 | /** An arbitrarily-chosen base point on the curve. */ 198 | extern const ristretto255_point_t ristretto255_point_base; 199 | 200 | /** Precomputed table of multiples of the base point on the curve. */ 201 | extern const ristretto255_precomputed_s *ristretto255_precomputed_base; 202 | 203 | #endif // _MSC_VER 204 | /** 205 | * @brief Read a scalar from wire format or from bytes. 206 | * 207 | * @param [in] ser Serialized form of a scalar. 208 | * @param [out] out Deserialized form. 209 | * 210 | * @retval RISTRETTO_SUCCESS The scalar was correctly encoded. 211 | * @retval RISTRETTO_FAILURE The scalar was greater than the modulus, 212 | * and has been reduced modulo that modulus. 213 | */ 214 | ristretto_error_t ristretto255_scalar_decode ( 215 | ristretto255_scalar_t *out, 216 | const unsigned char ser[RISTRETTO255_SCALAR_BYTES] 217 | ) RISTRETTO_WARN_UNUSED RISTRETTO_NONNULL RISTRETTO_NOINLINE; 218 | 219 | /** 220 | * @brief Read a scalar from wire format or from bytes. Reduces mod 221 | * scalar prime. 222 | * 223 | * @param [in] ser Serialized form of a scalar. 224 | * @param [in] ser_len Length of serialized form. 225 | * @param [out] out Deserialized form. 226 | */ 227 | void ristretto255_scalar_decode_long ( 228 | ristretto255_scalar_t *out, 229 | const unsigned char *ser, 230 | size_t ser_len 231 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 232 | 233 | /** 234 | * @brief Serialize a scalar to wire format. 235 | * 236 | * @param [out] ser Serialized form of a scalar. 237 | * @param [in] s Deserialized scalar. 238 | */ 239 | void ristretto255_scalar_encode ( 240 | unsigned char ser[RISTRETTO255_SCALAR_BYTES], 241 | const ristretto255_scalar_t *s 242 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE RISTRETTO_NOINLINE; 243 | 244 | /** 245 | * @brief Add two scalars. The scalars may use the same memory. 246 | * @param [in] a One scalar. 247 | * @param [in] b Another scalar. 248 | * @param [out] out a+b. 249 | */ 250 | void ristretto255_scalar_add ( 251 | ristretto255_scalar_t *out, 252 | const ristretto255_scalar_t *a, 253 | const ristretto255_scalar_t *b 254 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 255 | 256 | /** 257 | * @brief Compare two scalars. 258 | * @param [in] a One scalar. 259 | * @param [in] b Another scalar. 260 | * @retval RISTRETTO_TRUE The scalars are equal. 261 | * @retval RISTRETTO_FALSE The scalars are not equal. 262 | */ 263 | ristretto_bool_t ristretto255_scalar_eq ( 264 | const ristretto255_scalar_t *a, 265 | const ristretto255_scalar_t *b 266 | ) RISTRETTO_WARN_UNUSED RISTRETTO_NONNULL RISTRETTO_NOINLINE; 267 | 268 | /** 269 | * @brief Subtract two scalars. The scalars may use the same memory. 270 | * @param [in] a One scalar. 271 | * @param [in] b Another scalar. 272 | * @param [out] out a-b. 273 | */ 274 | void ristretto255_scalar_sub ( 275 | ristretto255_scalar_t *out, 276 | const ristretto255_scalar_t *a, 277 | const ristretto255_scalar_t *b 278 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 279 | 280 | /** 281 | * @brief Multiply two scalars. The scalars may use the same memory. 282 | * @param [in] a One scalar. 283 | * @param [in] b Another scalar. 284 | * @param [out] out a*b. 285 | */ 286 | void ristretto255_scalar_mul ( 287 | ristretto255_scalar_t *out, 288 | const ristretto255_scalar_t *a, 289 | const ristretto255_scalar_t *b 290 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 291 | 292 | /** 293 | * @brief Halve a scalar. The scalars may use the same memory. 294 | * @param [in] a A scalar. 295 | * @param [out] out a/2. 296 | */ 297 | void ristretto255_scalar_halve ( 298 | ristretto255_scalar_t *out, 299 | const ristretto255_scalar_t *a 300 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 301 | 302 | /** 303 | * @brief Invert a scalar. When passed zero, return 0. The input and output may alias. 304 | * @param [in] a A scalar. 305 | * @param [out] out 1/a. 306 | * @return RISTRETTO_SUCCESS The input is nonzero. 307 | */ 308 | ristretto_error_t ristretto255_scalar_invert ( 309 | ristretto255_scalar_t *out, 310 | const ristretto255_scalar_t *a 311 | ) RISTRETTO_WARN_UNUSED RISTRETTO_NONNULL RISTRETTO_NOINLINE; 312 | 313 | /** 314 | * @brief Copy a scalar. The scalars may use the same memory, in which 315 | * case this function does nothing. 316 | * @param [in] a A scalar. 317 | * @param [out] out Will become a copy of a. 318 | */ 319 | static inline void RISTRETTO_NONNULL ristretto255_scalar_copy ( 320 | ristretto255_scalar_t *out, 321 | const ristretto255_scalar_t *a 322 | ) { 323 | *out = *a; 324 | } 325 | 326 | /** 327 | * @brief Set a scalar to an unsigned 64-bit integer. 328 | * @param [in] a An integer. 329 | * @param [out] out Will become equal to a. 330 | */ 331 | void ristretto255_scalar_set_unsigned ( 332 | ristretto255_scalar_t *out, 333 | uint64_t a 334 | ) RISTRETTO_NONNULL; 335 | 336 | /** 337 | * @brief Encode a point as a sequence of bytes. 338 | * 339 | * @param [out] ser The byte representation of the point. 340 | * @param [in] pt The point to encode. 341 | */ 342 | void ristretto255_point_encode ( 343 | uint8_t ser[RISTRETTO255_SER_BYTES], 344 | const ristretto255_point_t *pt 345 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 346 | 347 | /** 348 | * @brief Decode a point from a sequence of bytes. 349 | * 350 | * Every point has a unique encoding, so not every 351 | * sequence of bytes is a valid encoding. If an invalid 352 | * encoding is given, the output is undefined. 353 | * 354 | * @param [out] pt The decoded point. 355 | * @param [in] ser The serialized version of the point. 356 | * @param [in] allow_identity RISTRETTO_TRUE if the identity is a legal input. 357 | * @retval RISTRETTO_SUCCESS The decoding succeeded. 358 | * @retval RISTRETTO_FAILURE The decoding didn't succeed, because 359 | * ser does not represent a point. 360 | */ 361 | ristretto_error_t ristretto255_point_decode ( 362 | ristretto255_point_t *pt, 363 | const uint8_t ser[RISTRETTO255_SER_BYTES], 364 | ristretto_bool_t allow_identity 365 | ) RISTRETTO_WARN_UNUSED RISTRETTO_NONNULL RISTRETTO_NOINLINE; 366 | 367 | /** 368 | * @brief Copy a point. The input and output may alias, 369 | * in which case this function does nothing. 370 | * 371 | * @param [out] a A copy of the point. 372 | * @param [in] b Any point. 373 | */ 374 | static inline void RISTRETTO_NONNULL ristretto255_point_copy ( 375 | ristretto255_point_t *a, 376 | const ristretto255_point_t *b 377 | ) { 378 | *a=*b; 379 | } 380 | 381 | /** 382 | * @brief Test whether two points are equal. If yes, return 383 | * RISTRETTO_TRUE, else return RISTRETTO_FALSE. 384 | * 385 | * @param [in] a A point. 386 | * @param [in] b Another point. 387 | * @retval RISTRETTO_TRUE The points are equal. 388 | * @retval RISTRETTO_FALSE The points are not equal. 389 | */ 390 | ristretto_bool_t ristretto255_point_eq ( 391 | const ristretto255_point_t *a, 392 | const ristretto255_point_t *b 393 | ) RISTRETTO_WARN_UNUSED RISTRETTO_NONNULL RISTRETTO_NOINLINE; 394 | 395 | /** 396 | * @brief Add two points to produce a third point. The 397 | * input points and output point can be pointers to the same 398 | * memory. 399 | * 400 | * @param [out] sum The sum a+b. 401 | * @param [in] a An addend. 402 | * @param [in] b An addend. 403 | */ 404 | void ristretto255_point_add ( 405 | ristretto255_point_t *sum, 406 | const ristretto255_point_t *a, 407 | const ristretto255_point_t *b 408 | ) RISTRETTO_NONNULL; 409 | 410 | /** 411 | * @brief Double a point. Equivalent to 412 | * ristretto255_point_add(two_a,a,a), but potentially faster. 413 | * 414 | * @param [out] two_a The sum a+a. 415 | * @param [in] a A point. 416 | */ 417 | void ristretto255_point_double ( 418 | ristretto255_point_t *two_a, 419 | const ristretto255_point_t *a 420 | ) RISTRETTO_NONNULL; 421 | 422 | /** 423 | * @brief Subtract two points to produce a third point. The 424 | * input points and output point can be pointers to the same 425 | * memory. 426 | * 427 | * @param [out] diff The difference a-b. 428 | * @param [in] a The minuend. 429 | * @param [in] b The subtrahend. 430 | */ 431 | void ristretto255_point_sub ( 432 | ristretto255_point_t *diff, 433 | const ristretto255_point_t *a, 434 | const ristretto255_point_t *b 435 | ) RISTRETTO_NONNULL; 436 | 437 | /** 438 | * @brief Negate a point to produce another point. The input 439 | * and output points can use the same memory. 440 | * 441 | * @param [out] nega The negated input point 442 | * @param [in] a The input point. 443 | */ 444 | void ristretto255_point_negate ( 445 | ristretto255_point_t *nega, 446 | const ristretto255_point_t *a 447 | ) RISTRETTO_NONNULL; 448 | 449 | /** 450 | * @brief Multiply a base point by a scalar: scaled = scalar*base. 451 | * 452 | * @param [out] scaled The scaled point base*scalar 453 | * @param [in] base The point to be scaled. 454 | * @param [in] scalar The scalar to multiply by. 455 | */ 456 | void ristretto255_point_scalarmul ( 457 | ristretto255_point_t *scaled, 458 | const ristretto255_point_t *base, 459 | const ristretto255_scalar_t *scalar 460 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 461 | 462 | /** 463 | * @brief Multiply a base point by a scalar: scaled = scalar*base. 464 | * This function operates directly on serialized forms. 465 | * 466 | * @warning This function is experimental. It may not be supported 467 | * long-term. 468 | * 469 | * @param [out] scaled The scaled point base*scalar 470 | * @param [in] base The point to be scaled. 471 | * @param [in] scalar The scalar to multiply by. 472 | * @param [in] allow_identity Allow the input to be the identity. 473 | * @param [in] short_circuit Allow a fast return if the input is illegal. 474 | * 475 | * @retval RISTRETTO_SUCCESS The scalarmul succeeded. 476 | * @retval RISTRETTO_FAILURE The scalarmul didn't succeed, because 477 | * base does not represent a point. 478 | */ 479 | ristretto_error_t ristretto255_direct_scalarmul ( 480 | uint8_t scaled[RISTRETTO255_SER_BYTES], 481 | const uint8_t base[RISTRETTO255_SER_BYTES], 482 | const ristretto255_scalar_t *scalar, 483 | ristretto_bool_t allow_identity, 484 | ristretto_bool_t short_circuit 485 | ) RISTRETTO_NONNULL RISTRETTO_WARN_UNUSED RISTRETTO_NOINLINE; 486 | 487 | /** 488 | * @brief Precompute a table for fast scalar multiplication. 489 | * Some implementations do not include precomputed points; for 490 | * those implementations, this implementation simply copies the 491 | * point. 492 | * 493 | * @param [out] a A precomputed table of multiples of the point. 494 | * @param [in] b Any point. 495 | */ 496 | void ristretto255_precompute ( 497 | ristretto255_precomputed_s *a, 498 | const ristretto255_point_t *b 499 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 500 | 501 | /** 502 | * @brief Multiply a precomputed base point by a scalar: 503 | * scaled = scalar*base. 504 | * Some implementations do not include precomputed points; for 505 | * those implementations, this function is the same as 506 | * ristretto255_point_scalarmul 507 | * 508 | * @param [out] scaled The scaled point base*scalar 509 | * @param [in] base The point to be scaled. 510 | * @param [in] scalar The scalar to multiply by. 511 | */ 512 | void ristretto255_precomputed_scalarmul ( 513 | ristretto255_point_t *scaled, 514 | const ristretto255_precomputed_s *base, 515 | const ristretto255_scalar_t *scalar 516 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 517 | 518 | /** 519 | * @brief Multiply two base points by two scalars: 520 | * scaled = scalar1*base1 + scalar2*base2. 521 | * 522 | * Equivalent to two calls to ristretto255_point_scalarmul, but may be 523 | * faster. 524 | * 525 | * @param [out] combo The linear combination scalar1*base1 + scalar2*base2. 526 | * @param [in] base1 A first point to be scaled. 527 | * @param [in] scalar1 A first scalar to multiply by. 528 | * @param [in] base2 A second point to be scaled. 529 | * @param [in] scalar2 A second scalar to multiply by. 530 | */ 531 | void ristretto255_point_double_scalarmul ( 532 | ristretto255_point_t *combo, 533 | const ristretto255_point_t *base1, 534 | const ristretto255_scalar_t *scalar1, 535 | const ristretto255_point_t *base2, 536 | const ristretto255_scalar_t *scalar2 537 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 538 | 539 | /** 540 | * Multiply one base point by two scalars: 541 | * 542 | * a1 = scalar1 * base 543 | * a2 = scalar2 * base 544 | * 545 | * Equivalent to two calls to ristretto255_point_scalarmul, but may be 546 | * faster. 547 | * 548 | * @param [out] a1 The first multiple. It may be the same as the input point. 549 | * @param [out] a2 The second multiple. It may be the same as the input point. 550 | * @param [in] base1 A point to be scaled. 551 | * @param [in] scalar1 A first scalar to multiply by. 552 | * @param [in] scalar2 A second scalar to multiply by. 553 | */ 554 | void ristretto255_point_dual_scalarmul ( 555 | ristretto255_point_t *a1, 556 | ristretto255_point_t *a2, 557 | const ristretto255_point_t *base1, 558 | const ristretto255_scalar_t *scalar1, 559 | const ristretto255_scalar_t *scalar2 560 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 561 | 562 | /** 563 | * @brief Multiply two base points by two scalars: 564 | * scaled = scalar1*ristretto255_point_base + scalar2*base2. 565 | * 566 | * Otherwise equivalent to ristretto255_point_double_scalarmul, but may be 567 | * faster at the expense of being variable time. 568 | * 569 | * @param [out] combo The linear combination scalar1*base + scalar2*base2. 570 | * @param [in] scalar1 A first scalar to multiply by. 571 | * @param [in] base2 A second point to be scaled. 572 | * @param [in] scalar2 A second scalar to multiply by. 573 | * 574 | * @warning: This function takes variable time, and may leak the scalars 575 | * used. It is designed for signature verification. 576 | */ 577 | void ristretto255_base_double_scalarmul_non_secret ( 578 | ristretto255_point_t *combo, 579 | const ristretto255_scalar_t *scalar1, 580 | const ristretto255_point_t *base2, 581 | const ristretto255_scalar_t *scalar2 582 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 583 | 584 | /** 585 | * @brief Constant-time decision between two points. If pick_b 586 | * is zero, out = a; else out = b. 587 | * 588 | * @param [out] out The output. It may be the same as either input. 589 | * @param [in] a Any point. 590 | * @param [in] b Any point. 591 | * @param [in] pick_b If nonzero, choose point b. 592 | */ 593 | void ristretto255_point_cond_sel ( 594 | ristretto255_point_t *out, 595 | const ristretto255_point_t *a, 596 | const ristretto255_point_t *b, 597 | ristretto_word_t pick_b 598 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 599 | 600 | /** 601 | * @brief Constant-time decision between two scalars. If pick_b 602 | * is zero, out = a; else out = b. 603 | * 604 | * @param [out] out The output. It may be the same as either input. 605 | * @param [in] a Any scalar. 606 | * @param [in] b Any scalar. 607 | * @param [in] pick_b If nonzero, choose scalar b. 608 | */ 609 | void ristretto255_scalar_cond_sel ( 610 | ristretto255_scalar_t *out, 611 | const ristretto255_scalar_t *a, 612 | const ristretto255_scalar_t *b, 613 | ristretto_word_t pick_b 614 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 615 | 616 | /** 617 | * @brief Test that a point is valid, for debugging purposes. 618 | * 619 | * @param [in] to_test The point to test. 620 | * @retval RISTRETTO_TRUE The point is valid. 621 | * @retval RISTRETTO_FALSE The point is invalid. 622 | */ 623 | ristretto_bool_t ristretto255_point_valid ( 624 | const ristretto255_point_t *to_test 625 | ) RISTRETTO_WARN_UNUSED RISTRETTO_NONNULL RISTRETTO_NOINLINE; 626 | 627 | /** 628 | * @brief Torque a point, for debugging purposes. The output 629 | * will be equal to the input. 630 | * 631 | * @param [out] q The point to torque. 632 | * @param [in] p The point to torque. 633 | */ 634 | void ristretto255_point_debugging_torque ( 635 | ristretto255_point_t *q, 636 | const ristretto255_point_t *p 637 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 638 | 639 | /** 640 | * @brief Projectively scale a point, for debugging purposes. 641 | * The output will be equal to the input, and will be valid 642 | * even if the factor is zero. 643 | * 644 | * @param [out] q The point to scale. 645 | * @param [in] p The point to scale. 646 | * @param [in] factor Serialized GF factor to scale. 647 | */ 648 | void ristretto255_point_debugging_pscale ( 649 | ristretto255_point_t *q, 650 | const ristretto255_point_t *p, 651 | const unsigned char factor[RISTRETTO255_SER_BYTES] 652 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 653 | 654 | /** 655 | * @brief Almost-Elligator-like hash to curve. 656 | * 657 | * Call this function with the output of a hash to make a hash to the curve. 658 | * 659 | * This function runs Elligator2 on the ristretto255 Jacobi quartic model. It then 660 | * uses the isogeny to put the result in twisted Edwards form. As a result, 661 | * it is safe (cannot produce points of order 4), and would be compatible with 662 | * hypothetical other implementations of Decaf using a Montgomery or untwisted 663 | * Edwards model. 664 | * 665 | * Unlike Elligator, this function may be up to 4:1 on [0,(p-1)/2]: 666 | * A factor of 2 due to the isogeny. 667 | * A factor of 2 because we quotient out the 2-torsion. 668 | * 669 | * This makes it about 8:1 overall, or 16:1 overall on curves with cofactor 8. 670 | * 671 | * Negating the input (mod q) results in the same point. Inverting the input 672 | * (mod q) results in the negative point. This is the same as Elligator. 673 | * 674 | * This function isn't quite indifferentiable from a random oracle. 675 | * However, it is suitable for many protocols, including SPEKE and SPAKE2 EE. 676 | * Furthermore, calling it twice with independent seeds and adding the results 677 | * is indifferentiable from a random oracle. 678 | * 679 | * @param [in] hashed_data Output of some hash function. 680 | * @param [out] pt The data hashed to the curve. 681 | */ 682 | void ristretto255_point_from_hash_nonuniform ( 683 | ristretto255_point_t *pt, 684 | const unsigned char hashed_data[RISTRETTO255_HASH_BYTES] 685 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 686 | 687 | /** 688 | * @brief Indifferentiable hash function encoding to curve. 689 | * 690 | * Equivalent to calling ristretto255_point_from_hash_nonuniform twice and adding. 691 | * 692 | * @param [in] hashed_data Output of some hash function. 693 | * @param [out] pt The data hashed to the curve. 694 | */ 695 | void ristretto255_point_from_hash_uniform ( 696 | ristretto255_point_t *pt, 697 | const unsigned char hashed_data[2*RISTRETTO255_HASH_BYTES] 698 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE; 699 | 700 | /** 701 | * @brief Inverse of elligator-like hash to curve. 702 | * 703 | * This function writes to the buffer, to make it so that 704 | * ristretto255_point_from_hash_nonuniform(buffer) = pt if 705 | * possible. Since there may be multiple preimages, the 706 | * "which" parameter chooses between them. To ensure uniform 707 | * inverse sampling, this function succeeds or fails 708 | * independently for different "which" values. 709 | * 710 | * This function isn't guaranteed to find every possible 711 | * preimage, but it finds all except a small finite number. 712 | * In particular, when the number of bits in the modulus isn't 713 | * a multiple of 8 (i.e. for curve25519), it sets the high bits 714 | * independently, which enables the generated data to be uniform. 715 | * But it doesn't add p, so you'll never get exactly p from this 716 | * function. This might change in the future, especially if 717 | * we ever support eg Brainpool curves, where this could cause 718 | * real nonuniformity. 719 | * 720 | * @param [out] recovered_hash Encoded data. 721 | * @param [in] pt The point to encode. 722 | * @param [in] which A value determining which inverse point 723 | * to return. 724 | * 725 | * @retval RISTRETTO_SUCCESS The inverse succeeded. 726 | * @retval RISTRETTO_FAILURE The inverse failed. 727 | */ 728 | ristretto_error_t ristretto255_invert_elligator_nonuniform ( 729 | unsigned char recovered_hash[RISTRETTO255_HASH_BYTES], 730 | const ristretto255_point_t *pt, 731 | uint32_t which 732 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE RISTRETTO_WARN_UNUSED; 733 | 734 | /** 735 | * @brief Inverse of elligator-like hash to curve. 736 | * 737 | * This function writes to the buffer, to make it so that 738 | * ristretto255_point_from_hash_uniform(buffer) = pt if 739 | * possible. Since there may be multiple preimages, the 740 | * "which" parameter chooses between them. To ensure uniform 741 | * inverse sampling, this function succeeds or fails 742 | * independently for different "which" values. 743 | * 744 | * @param [out] recovered_hash Encoded data. 745 | * @param [in] pt The point to encode. 746 | * @param [in] which A value determining which inverse point 747 | * to return. 748 | * 749 | * @retval RISTRETTO_SUCCESS The inverse succeeded. 750 | * @retval RISTRETTO_FAILURE The inverse failed. 751 | */ 752 | ristretto_error_t ristretto255_invert_elligator_uniform ( 753 | unsigned char recovered_hash[2*RISTRETTO255_HASH_BYTES], 754 | const ristretto255_point_t *pt, 755 | uint32_t which 756 | ) RISTRETTO_NONNULL RISTRETTO_NOINLINE RISTRETTO_WARN_UNUSED; 757 | 758 | /** Securely erase a scalar. */ 759 | void ristretto255_scalar_destroy ( 760 | ristretto255_scalar_t *scalar 761 | ) RISTRETTO_NONNULL; 762 | 763 | /** Securely erase a point by overwriting it with zeros. 764 | * @warning This causes the point object to become invalid. 765 | */ 766 | void ristretto255_point_destroy ( 767 | ristretto255_point_t *point 768 | ) RISTRETTO_NONNULL; 769 | 770 | /** Securely erase a precomputed table by overwriting it with zeros. 771 | * @warning This causes the table object to become invalid. 772 | */ 773 | void ristretto255_precomputed_destroy ( 774 | ristretto255_precomputed_s *pre 775 | ) RISTRETTO_NONNULL; 776 | 777 | #ifdef __cplusplus 778 | } /* extern "C" */ 779 | #endif 780 | 781 | #endif /* __RISTRETTO255_H__ */ 782 | -------------------------------------------------------------------------------- /src/arch/32/arch_intrinsics.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2016-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #ifndef __ARCH_ARCH_32_ARCH_INTRINSICS_H__ 6 | #define __ARCH_ARCH_32_ARCH_INTRINSICS_H__ 7 | 8 | #define ARCH_WORD_BITS 32 9 | 10 | #if defined _MSC_VER 11 | #define __attribute(x) 12 | #define __inline__ __inline 13 | #endif // MSVC 14 | 15 | static __inline__ __attribute((always_inline,unused)) 16 | uint32_t word_is_zero(uint32_t a) { 17 | /* let's hope the compiler isn't clever enough to optimize this. */ 18 | return (((uint64_t)a)-1)>>32; 19 | } 20 | 21 | static __inline__ __attribute((always_inline,unused)) 22 | uint64_t widemul(uint32_t a, uint32_t b) { 23 | return ((uint64_t)a) * b; 24 | } 25 | 26 | #endif /* __ARCH_ARM_32_ARCH_INTRINSICS_H__ */ 27 | 28 | -------------------------------------------------------------------------------- /src/arch/32/f_impl.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2016-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #include 6 | #include "f_field.h" 7 | 8 | void gf_mul (gf_25519_t *__restrict__ cs, const gf_25519_t *as, const gf_25519_t *bs) { 9 | const uint32_t *a = as->limb, *b = bs->limb, maske = ((1<<26)-1), masko = ((1<<25)-1); 10 | 11 | uint32_t bh[9]; 12 | int i,j; 13 | for (i=0; i<9; i++) bh[i] = b[i+1] * 19; 14 | 15 | uint32_t *c = cs->limb; 16 | 17 | uint64_t accum = 0; 18 | for (i=0; i<10; /*i+=2*/) { 19 | /* Even case. */ 20 | for (j=0; j>= 26; 32 | i++; 33 | 34 | /* Odd case is easier: all place values are exact. */ 35 | for (j=0; j<=i; j++) { 36 | accum += widemul(b[i-j], a[j]); 37 | } 38 | for (; j<10; j++) { 39 | accum += widemul(bh[i-j+9], a[j]); 40 | } 41 | c[i] = accum & masko; 42 | accum >>= 25; 43 | i++; 44 | } 45 | 46 | accum *= 19; 47 | accum += c[0]; 48 | c[0] = accum & maske; 49 | accum >>= 26; 50 | 51 | assert(accum < masko); 52 | c[1] += accum; 53 | } 54 | 55 | void gf_mulw_unsigned (gf_25519_t *__restrict__ cs, const gf_25519_t *as, uint32_t b) { 56 | const uint32_t *a = as->limb, maske = ((1<<26)-1), masko = ((1<<25)-1); 57 | uint32_t *c = cs->limb; 58 | uint64_t accum = widemul(b, a[0]); 59 | c[0] = accum & maske; 60 | accum >>= 26; 61 | 62 | accum += widemul(b, a[1]); 63 | c[1] = accum & masko; 64 | accum >>= 25; 65 | 66 | for (int i=2; i<10; /*i+=2*/) { 67 | accum += widemul(b, a[i]); 68 | c[i] = accum & maske; 69 | accum >>= 26; 70 | i++; 71 | 72 | accum += widemul(b, a[i]); 73 | c[i] = accum & masko; 74 | accum >>= 25; 75 | i++; 76 | } 77 | 78 | accum *= 19; 79 | accum += c[0]; 80 | c[0] = accum & maske; 81 | accum >>= 26; 82 | 83 | assert(accum < masko); 84 | c[1] += accum; 85 | } 86 | 87 | void gf_sqr (gf_25519_t *__restrict__ cs, const gf_25519_t *as) { 88 | gf_mul(cs,as,as); /* Performs better with dedicated square */ 89 | } 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/arch/32/f_impl.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #define GF_HEADROOM 3 /* Would be 5, but 3*19 * 2^26+small is all that fits in a uint32_t */ 6 | #define LIMB(x) (x##ull)&((1ull<<26)-1), (x##ull)>>26 7 | #define FIELD_LITERAL(a,b,c,d,e) {{LIMB(a),LIMB(b),LIMB(c),LIMB(d),LIMB(e)}} 8 | 9 | #define LIMB_PLACE_VALUE(i) (((i)&1)?25:26) 10 | 11 | void gf_add_RAW (gf_25519_t *out, const gf_25519_t *a, const gf_25519_t *b) { 12 | for (unsigned int i=0; i<10; i++) { 13 | out->limb[i] = a->limb[i] + b->limb[i]; 14 | } 15 | } 16 | 17 | void gf_sub_RAW (gf_25519_t *out, const gf_25519_t *a, const gf_25519_t *b) { 18 | for (unsigned int i=0; i<10; i++) { 19 | out->limb[i] = a->limb[i] - b->limb[i]; 20 | } 21 | } 22 | 23 | void gf_bias (gf_25519_t *a, int amt) { 24 | uint32_t coe = ((1ull<<26)-1)*amt, coo = ((1ull<<25)-1)*amt, co0 = coe-18*amt; 25 | for (unsigned int i=0; i<10; i+=2) { 26 | a->limb[i] += ((i==0) ? co0 : coe); 27 | a->limb[i+1] += coo; 28 | } 29 | } 30 | 31 | void gf_weak_reduce (gf_25519_t *a) { 32 | uint32_t maske = (1ull<<26) - 1, masko = (1ull<<25) - 1; 33 | uint32_t tmp = a->limb[9] >> 25; 34 | for (unsigned int i=8; i>0; i-=2) { 35 | a->limb[i+1] = (a->limb[i+1] & masko) + (a->limb[i]>>26); 36 | a->limb[i] = (a->limb[i] & maske) + (a->limb[i-1]>>25); 37 | } 38 | a->limb[1] = (a->limb[1] & masko) + (a->limb[0]>>26); 39 | a->limb[0] = (a->limb[0] & maske) + tmp*19; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/arch/arm32/arch_intrinsics.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2016-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #ifndef __ARCH_ARM_32_ARCH_INTRINSICS_H__ 6 | #define __ARCH_ARM_32_ARCH_INTRINSICS_H__ 7 | 8 | #define ARCH_WORD_BITS 32 9 | 10 | static __inline__ __attribute((always_inline,unused)) 11 | uint32_t word_is_zero(uint32_t a) { 12 | uint32_t ret; 13 | __asm__("subs %0, %1, #1;\n\tsbc %0, %0, %0" : "=r"(ret) : "r"(a) : "cc"); 14 | return ret; 15 | } 16 | 17 | static __inline__ __attribute((always_inline,unused)) 18 | uint64_t widemul(uint32_t a, uint32_t b) { 19 | /* Could be UMULL, but it's hard to express to CC that the registers must be different */ 20 | return ((uint64_t)a) * b; 21 | } 22 | 23 | #endif /* __ARCH_ARM_32_ARCH_INTRINSICS_H__ */ 24 | 25 | -------------------------------------------------------------------------------- /src/arch/neon/arch_intrinsics.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2016-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #ifndef __ARCH_NEON_ARCH_INTRINSICS_H__ 6 | #define __ARCH_NEON_ARCH_INTRINSICS_H__ 7 | 8 | #define ARCH_WORD_BITS 32 9 | 10 | static __inline__ __attribute((always_inline,unused)) 11 | uint32_t word_is_zero(uint32_t a) { 12 | uint32_t ret; 13 | __asm__("subs %0, %1, #1;\n\tsbc %0, %0, %0" : "=r"(ret) : "r"(a) : "cc"); 14 | return ret; 15 | } 16 | 17 | static __inline__ __attribute((always_inline,unused)) 18 | uint64_t widemul(uint32_t a, uint32_t b) { 19 | /* Could be UMULL, but it's hard to express to CC that the registers must be different */ 20 | return ((uint64_t)a) * b; 21 | } 22 | 23 | #endif /* __ARCH_NEON_ARCH_INTRINSICS_H__ */ 24 | 25 | -------------------------------------------------------------------------------- /src/arch/ref64/arch_intrinsics.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2016-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #ifndef __ARCH_REF64_ARCH_INTRINSICS_H__ 6 | #define __ARCH_REF64_ARCH_INTRINSICS_H__ 7 | 8 | #define ARCH_WORD_BITS 64 9 | 10 | static __inline__ __attribute((always_inline,unused)) 11 | uint64_t word_is_zero(uint64_t a) { 12 | /* let's hope the compiler isn't clever enough to optimize this. */ 13 | return (((__uint128_t)a)-1)>>64; 14 | } 15 | 16 | static __inline__ __attribute((always_inline,unused)) 17 | __uint128_t widemul(uint64_t a, uint64_t b) { 18 | return ((__uint128_t)a) * b; 19 | } 20 | 21 | #endif /* ARCH_REF64_ARCH_INTRINSICS_H__ */ 22 | 23 | -------------------------------------------------------------------------------- /src/arch/ref64/f_impl.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #include 6 | #include "f_field.h" 7 | 8 | void gf_mul (gf_25519_t *__restrict__ cs, const gf_25519_t *as, const gf_25519_t *bs) { 9 | const uint64_t *a = as->limb, *b = bs->limb, mask = ((1ull<<51)-1); 10 | 11 | uint64_t bh[4]; 12 | int i,j; 13 | for (i=0; i<4; i++) bh[i] = b[i+1] * 19; 14 | 15 | uint64_t *c = cs->limb; 16 | 17 | __uint128_t accum = 0; 18 | for (i=0; i<5; i++) { 19 | for (j=0; j<=i; j++) { 20 | accum += widemul(b[i-j], a[j]); 21 | } 22 | for (; j<5; j++) { 23 | accum += widemul(bh[i-j+4], a[j]); 24 | } 25 | c[i] = accum & mask; 26 | accum >>= 51; 27 | } 28 | 29 | accum *= 19; 30 | accum += c[0]; 31 | c[0] = accum & mask; 32 | accum >>= 51; 33 | 34 | assert(accum < mask); 35 | c[1] += accum; 36 | } 37 | 38 | void gf_mulw_unsigned (gf_25519_t *__restrict__ cs, const gf_25519_t *as, uint32_t b) { 39 | const uint64_t *a = as->limb, mask = ((1ull<<51)-1); 40 | int i; 41 | 42 | uint64_t *c = cs->limb; 43 | 44 | __uint128_t accum = 0; 45 | for (i=0; i<5; i++) { 46 | accum += widemul(b, a[i]); 47 | c[i] = accum & mask; 48 | accum >>= 51; 49 | } 50 | 51 | accum *= 19; 52 | accum += c[0]; 53 | c[0] = accum & mask; 54 | accum >>= 51; 55 | 56 | assert(accum < mask); 57 | c[1] += accum; 58 | } 59 | 60 | void gf_sqr (gf_25519_t *__restrict__ cs, const gf_25519_t *as) { 61 | gf_mul(cs,as,as); /* Performs better with dedicated square */ 62 | } 63 | -------------------------------------------------------------------------------- /src/arch/ref64/f_impl.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #define GF_HEADROOM 9999 /* Always reduced */ 6 | #define FIELD_LITERAL(a,b,c,d,e) {{ a,b,c,d,e }} 7 | 8 | #define LIMB_PLACE_VALUE(i) 51 9 | 10 | void gf_add_RAW (gf_25519_t *out, const gf_25519_t *a, const gf_25519_t *b) { 11 | for (unsigned int i=0; i<5; i++) { 12 | out->limb[i] = a->limb[i] + b->limb[i]; 13 | } 14 | gf_weak_reduce(out); 15 | } 16 | 17 | void gf_sub_RAW (gf_25519_t *out, const gf_25519_t *a, const gf_25519_t *b) { 18 | uint64_t co1 = ((1ull<<51)-1)*2, co2 = co1-36; 19 | for (unsigned int i=0; i<5; i++) { 20 | out->limb[i] = a->limb[i] - b->limb[i] + ((i==0) ? co2 : co1); 21 | } 22 | gf_weak_reduce(out); 23 | } 24 | 25 | void gf_bias (gf_25519_t *a, int amt) { 26 | (void) a; 27 | (void) amt; 28 | } 29 | 30 | void gf_weak_reduce (gf_25519_t *a) { 31 | uint64_t mask = (1ull<<51) - 1; 32 | uint64_t tmp = a->limb[4] >> 51; 33 | for (unsigned int i=4; i>0; i--) { 34 | a->limb[i] = (a->limb[i] & mask) + (a->limb[i-1]>>51); 35 | } 36 | a->limb[0] = (a->limb[0] & mask) + tmp*19; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /src/arch/x86_64/arch_intrinsics.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #ifndef __ARCH_X86_64_ARCH_INTRINSICS_H__ 6 | #define __ARCH_X86_64_ARCH_INTRINSICS_H__ 7 | 8 | #define ARCH_WORD_BITS 64 9 | 10 | #include 11 | 12 | /* FUTURE: autogenerate */ 13 | static __inline__ __uint128_t widemul(const uint64_t *a, const uint64_t *b) { 14 | uint64_t c,d; 15 | #ifndef __BMI2__ 16 | __asm__ volatile 17 | ("movq %[a], %%rax;" 18 | "mulq %[b];" 19 | : [c]"=&a"(c), [d]"=d"(d) 20 | : [b]"m"(*b), [a]"m"(*a) 21 | : "cc"); 22 | #else 23 | __asm__ volatile 24 | ("movq %[a], %%rdx;" 25 | "mulx %[b], %[c], %[d];" 26 | : [c]"=r"(c), [d]"=r"(d) 27 | : [b]"m"(*b), [a]"m"(*a) 28 | : "rdx"); 29 | #endif 30 | return (((__uint128_t)(d))<<64) | c; 31 | } 32 | 33 | static __inline__ __uint128_t widemul_rm(uint64_t a, const uint64_t *b) { 34 | uint64_t c,d; 35 | #ifndef __BMI2__ 36 | __asm__ volatile 37 | ("movq %[a], %%rax;" 38 | "mulq %[b];" 39 | : [c]"=&a"(c), [d]"=d"(d) 40 | : [b]"m"(*b), [a]"r"(a) 41 | : "cc"); 42 | #else 43 | __asm__ volatile 44 | ("mulx %[b], %[c], %[d];" 45 | : [c]"=r"(c), [d]"=r"(d) 46 | : [b]"m"(*b), [a]"d"(a)); 47 | #endif 48 | return (((__uint128_t)(d))<<64) | c; 49 | } 50 | 51 | static __inline__ __uint128_t widemul_rr(uint64_t a, uint64_t b) { 52 | uint64_t c,d; 53 | #ifndef __BMI2__ 54 | __asm__ volatile 55 | ("mulq %[b];" 56 | : [c]"=a"(c), [d]"=d"(d) 57 | : [b]"r"(b), "a"(a) 58 | : "cc"); 59 | #else 60 | __asm__ volatile 61 | ("mulx %[b], %[c], %[d];" 62 | : [c]"=r"(c), [d]"=r"(d) 63 | : [b]"r"(b), [a]"d"(a)); 64 | #endif 65 | return (((__uint128_t)(d))<<64) | c; 66 | } 67 | 68 | static __inline__ __uint128_t widemul2(const uint64_t *a, const uint64_t *b) { 69 | uint64_t c,d; 70 | #ifndef __BMI2__ 71 | __asm__ volatile 72 | ("movq %[a], %%rax; " 73 | "addq %%rax, %%rax; " 74 | "mulq %[b];" 75 | : [c]"=&a"(c), [d]"=d"(d) 76 | : [b]"m"(*b), [a]"m"(*a) 77 | : "cc"); 78 | #else 79 | __asm__ volatile 80 | ("movq %[a], %%rdx;" 81 | "leaq (,%%rdx,2), %%rdx;" 82 | "mulx %[b], %[c], %[d];" 83 | : [c]"=r"(c), [d]"=r"(d) 84 | : [b]"m"(*b), [a]"m"(*a) 85 | : "rdx"); 86 | #endif 87 | return (((__uint128_t)(d))<<64) | c; 88 | } 89 | 90 | static __inline__ void mac(__uint128_t *acc, const uint64_t *a, const uint64_t *b) { 91 | uint64_t lo = *acc, hi = *acc>>64; 92 | 93 | #ifdef __BMI2__ 94 | uint64_t c,d; 95 | __asm__ volatile 96 | ("movq %[a], %%rdx; " 97 | "mulx %[b], %[c], %[d]; " 98 | "addq %[c], %[lo]; " 99 | "adcq %[d], %[hi]; " 100 | : [c]"=&r"(c), [d]"=&r"(d), [lo]"+r"(lo), [hi]"+r"(hi) 101 | : [b]"m"(*b), [a]"m"(*a) 102 | : "rdx", "cc"); 103 | #else 104 | __asm__ volatile 105 | ("movq %[a], %%rax; " 106 | "mulq %[b]; " 107 | "addq %%rax, %[lo]; " 108 | "adcq %%rdx, %[hi]; " 109 | : [lo]"+r"(lo), [hi]"+r"(hi) 110 | : [b]"m"(*b), [a]"m"(*a) 111 | : "rax", "rdx", "cc"); 112 | #endif 113 | 114 | *acc = (((__uint128_t)(hi))<<64) | lo; 115 | } 116 | 117 | static __inline__ void macac(__uint128_t *acc, __uint128_t *acc2, const uint64_t *a, const uint64_t *b) { 118 | uint64_t lo = *acc, hi = *acc>>64; 119 | uint64_t lo2 = *acc2, hi2 = *acc2>>64; 120 | 121 | #ifdef __BMI2__ 122 | uint64_t c,d; 123 | __asm__ volatile 124 | ("movq %[a], %%rdx; " 125 | "mulx %[b], %[c], %[d]; " 126 | "addq %[c], %[lo]; " 127 | "adcq %[d], %[hi]; " 128 | "addq %[c], %[lo2]; " 129 | "adcq %[d], %[hi2]; " 130 | : [c]"=r"(c), [d]"=r"(d), [lo]"+r"(lo), [hi]"+r"(hi), [lo2]"+r"(lo2), [hi2]"+r"(hi2) 131 | : [b]"m"(*b), [a]"m"(*a) 132 | : "rdx", "cc"); 133 | #else 134 | __asm__ volatile 135 | ("movq %[a], %%rax; " 136 | "mulq %[b]; " 137 | "addq %%rax, %[lo]; " 138 | "adcq %%rdx, %[hi]; " 139 | "addq %%rax, %[lo2]; " 140 | "adcq %%rdx, %[hi2]; " 141 | : [lo]"+r"(lo), [hi]"+r"(hi), [lo2]"+r"(lo2), [hi2]"+r"(hi2) 142 | : [b]"m"(*b), [a]"m"(*a) 143 | : "rax", "rdx", "cc"); 144 | #endif 145 | 146 | *acc = (((__uint128_t)(hi))<<64) | lo; 147 | *acc2 = (((__uint128_t)(hi2))<<64) | lo2; 148 | } 149 | 150 | static __inline__ void mac_rm(__uint128_t *acc, uint64_t a, const uint64_t *b) { 151 | uint64_t lo = *acc, hi = *acc>>64; 152 | 153 | #ifdef __BMI2__ 154 | uint64_t c,d; 155 | __asm__ volatile 156 | ("mulx %[b], %[c], %[d]; " 157 | "addq %[c], %[lo]; " 158 | "adcq %[d], %[hi]; " 159 | : [c]"=r"(c), [d]"=r"(d), [lo]"+r"(lo), [hi]"+r"(hi) 160 | : [b]"m"(*b), [a]"d"(a) 161 | : "cc"); 162 | #else 163 | __asm__ volatile 164 | ("movq %[a], %%rax; " 165 | "mulq %[b]; " 166 | "addq %%rax, %[lo]; " 167 | "adcq %%rdx, %[hi]; " 168 | : [lo]"+r"(lo), [hi]"+r"(hi) 169 | : [b]"m"(*b), [a]"r"(a) 170 | : "rax", "rdx", "cc"); 171 | #endif 172 | 173 | *acc = (((__uint128_t)(hi))<<64) | lo; 174 | } 175 | 176 | static __inline__ void mac_rr(__uint128_t *acc, uint64_t a, const uint64_t b) { 177 | uint64_t lo = *acc, hi = *acc>>64; 178 | 179 | #ifdef __BMI2__ 180 | uint64_t c,d; 181 | __asm__ volatile 182 | ("mulx %[b], %[c], %[d]; " 183 | "addq %[c], %[lo]; " 184 | "adcq %[d], %[hi]; " 185 | : [c]"=r"(c), [d]"=r"(d), [lo]"+r"(lo), [hi]"+r"(hi) 186 | : [b]"r"(b), [a]"d"(a) 187 | : "cc"); 188 | #else 189 | __asm__ volatile 190 | ("mulq %[b]; " 191 | "addq %%rax, %[lo]; " 192 | "adcq %%rdx, %[hi]; " 193 | : [lo]"+r"(lo), [hi]"+r"(hi), "+a"(a) 194 | : [b]"r"(b) 195 | : "rdx", "cc"); 196 | #endif 197 | 198 | *acc = (((__uint128_t)(hi))<<64) | lo; 199 | } 200 | 201 | static __inline__ void mac2(__uint128_t *acc, const uint64_t *a, const uint64_t *b) { 202 | uint64_t lo = *acc, hi = *acc>>64; 203 | 204 | #ifdef __BMI2__ 205 | uint64_t c,d; 206 | __asm__ volatile 207 | ("movq %[a], %%rdx; " 208 | "addq %%rdx, %%rdx; " 209 | "mulx %[b], %[c], %[d]; " 210 | "addq %[c], %[lo]; " 211 | "adcq %[d], %[hi]; " 212 | : [c]"=r"(c), [d]"=r"(d), [lo]"+r"(lo), [hi]"+r"(hi) 213 | : [b]"m"(*b), [a]"m"(*a) 214 | : "rdx", "cc"); 215 | #else 216 | __asm__ volatile 217 | ("movq %[a], %%rax; " 218 | "addq %%rax, %%rax; " 219 | "mulq %[b]; " 220 | "addq %%rax, %[lo]; " 221 | "adcq %%rdx, %[hi]; " 222 | : [lo]"+r"(lo), [hi]"+r"(hi) 223 | : [b]"m"(*b), [a]"m"(*a) 224 | : "rax", "rdx", "cc"); 225 | #endif 226 | 227 | *acc = (((__uint128_t)(hi))<<64) | lo; 228 | } 229 | 230 | static __inline__ void msb(__uint128_t *acc, const uint64_t *a, const uint64_t *b) { 231 | uint64_t lo = *acc, hi = *acc>>64; 232 | #ifdef __BMI2__ 233 | uint64_t c,d; 234 | __asm__ volatile 235 | ("movq %[a], %%rdx; " 236 | "mulx %[b], %[c], %[d]; " 237 | "subq %[c], %[lo]; " 238 | "sbbq %[d], %[hi]; " 239 | : [c]"=r"(c), [d]"=r"(d), [lo]"+r"(lo), [hi]"+r"(hi) 240 | : [b]"m"(*b), [a]"m"(*a) 241 | : "rdx", "cc"); 242 | #else 243 | __asm__ volatile 244 | ("movq %[a], %%rax; " 245 | "mulq %[b]; " 246 | "subq %%rax, %[lo]; " 247 | "sbbq %%rdx, %[hi]; " 248 | : [lo]"+r"(lo), [hi]"+r"(hi) 249 | : [b]"m"(*b), [a]"m"(*a) 250 | : "rax", "rdx", "cc"); 251 | #endif 252 | *acc = (((__uint128_t)(hi))<<64) | lo; 253 | } 254 | 255 | static __inline__ void msb2(__uint128_t *acc, const uint64_t *a, const uint64_t *b) { 256 | uint64_t lo = *acc, hi = *acc>>64; 257 | #ifdef __BMI2__ 258 | uint64_t c,d; 259 | __asm__ volatile 260 | ("movq %[a], %%rdx; " 261 | "addq %%rdx, %%rdx; " 262 | "mulx %[b], %[c], %[d]; " 263 | "subq %[c], %[lo]; " 264 | "sbbq %[d], %[hi]; " 265 | : [c]"=r"(c), [d]"=r"(d), [lo]"+r"(lo), [hi]"+r"(hi) 266 | : [b]"m"(*b), [a]"m"(*a) 267 | : "rdx", "cc"); 268 | #else 269 | __asm__ volatile 270 | ("movq %[a], %%rax; " 271 | "addq %%rax, %%rax; " 272 | "mulq %[b]; " 273 | "subq %%rax, %[lo]; " 274 | "sbbq %%rdx, %[hi]; " 275 | : [lo]"+r"(lo), [hi]"+r"(hi) 276 | : [b]"m"(*b), [a]"m"(*a) 277 | : "rax", "rdx", "cc"); 278 | #endif 279 | *acc = (((__uint128_t)(hi))<<64) | lo; 280 | 281 | } 282 | 283 | static __inline__ void mrs(__uint128_t *acc, const uint64_t *a, const uint64_t *b) { 284 | uint64_t c,d, lo = *acc, hi = *acc>>64; 285 | __asm__ volatile 286 | ("movq %[a], %%rdx; " 287 | "mulx %[b], %[c], %[d]; " 288 | "subq %[lo], %[c]; " 289 | "sbbq %[hi], %[d]; " 290 | : [c]"=r"(c), [d]"=r"(d), [lo]"+r"(lo), [hi]"+r"(hi) 291 | : [b]"m"(*b), [a]"m"(*a) 292 | : "rdx", "cc"); 293 | *acc = (((__uint128_t)(d))<<64) | c; 294 | } 295 | 296 | static __inline__ uint64_t word_is_zero(uint64_t x) { 297 | __asm__ volatile("neg %0; sbb %0, %0;" : "+r"(x)); 298 | return ~x; 299 | } 300 | 301 | static inline uint64_t shrld(__uint128_t x, int n) { 302 | return x>>n; 303 | } 304 | 305 | #endif /* __ARCH_X86_64_ARCH_INTRINSICS_H__ */ 306 | -------------------------------------------------------------------------------- /src/arch/x86_64/f_impl.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #include 6 | #include "f_field.h" 7 | 8 | /** Requires: input limbs < 9*2^51 */ 9 | void gf_mul (gf_25519_t *__restrict__ cs, const gf_25519_t *as, const gf_25519_t *bs) { 10 | const uint64_t *a = as->limb, *b = bs->limb, mask = ((1ull<<51)-1); 11 | uint64_t *c = cs->limb; 12 | 13 | __uint128_t accum0, accum1, accum2; 14 | 15 | uint64_t ai = a[0]; 16 | accum0 = widemul_rm(ai, &b[0]); 17 | accum1 = widemul_rm(ai, &b[1]); 18 | accum2 = widemul_rm(ai, &b[2]); 19 | 20 | ai = a[1]; 21 | mac_rm(&accum2, ai, &b[1]); 22 | mac_rm(&accum1, ai, &b[0]); 23 | ai *= 19; 24 | mac_rm(&accum0, ai, &b[4]); 25 | 26 | ai = a[2]; 27 | mac_rm(&accum2, ai, &b[0]); 28 | ai *= 19; 29 | mac_rm(&accum0, ai, &b[3]); 30 | mac_rm(&accum1, ai, &b[4]); 31 | 32 | ai = a[3] * 19; 33 | mac_rm(&accum0, ai, &b[2]); 34 | mac_rm(&accum1, ai, &b[3]); 35 | mac_rm(&accum2, ai, &b[4]); 36 | 37 | ai = a[4] * 19; 38 | mac_rm(&accum0, ai, &b[1]); 39 | mac_rm(&accum1, ai, &b[2]); 40 | mac_rm(&accum2, ai, &b[3]); 41 | 42 | uint64_t c0 = accum0 & mask; 43 | accum1 += shrld(accum0, 51); 44 | uint64_t c1 = accum1 & mask; 45 | accum2 += shrld(accum1, 51); 46 | c[2] = accum2 & mask; 47 | 48 | accum0 = shrld(accum2, 51); 49 | 50 | mac_rm(&accum0, ai, &b[4]); 51 | 52 | ai = a[0]; 53 | mac_rm(&accum0, ai, &b[3]); 54 | accum1 = widemul_rm(ai, &b[4]); 55 | 56 | ai = a[1]; 57 | mac_rm(&accum0, ai, &b[2]); 58 | mac_rm(&accum1, ai, &b[3]); 59 | 60 | ai = a[2]; 61 | mac_rm(&accum0, ai, &b[1]); 62 | mac_rm(&accum1, ai, &b[2]); 63 | 64 | ai = a[3]; 65 | mac_rm(&accum0, ai, &b[0]); 66 | mac_rm(&accum1, ai, &b[1]); 67 | 68 | ai = a[4]; 69 | mac_rm(&accum1, ai, &b[0]); 70 | /* Here accum1 < 5*(9*2^51)^2 */ 71 | 72 | c[3] = accum0 & mask; 73 | accum1 += shrld(accum0, 51); 74 | c[4] = accum1 & mask; 75 | 76 | uint64_t a1 = shrld(accum1,51); 77 | /* Here a1 < (5*(9*2^51)^2 + small) >> 51 = 405 * 2^51 + small 78 | * a1 * 19 + c0 < (405*19+1)*2^51 + small < 2^13 * 2^51. 79 | */ 80 | accum1 = a1 * 19 + c0; 81 | c[0] = accum1 & mask; 82 | c[1] = c1 + (accum1>>51); 83 | } 84 | 85 | void gf_sqr (gf_25519_t *__restrict__ cs, const gf_25519_t *as) { 86 | const uint64_t *a = as->limb, mask = ((1ull<<51)-1); 87 | uint64_t *c = cs->limb; 88 | 89 | __uint128_t accum0, accum1, accum2; 90 | 91 | uint64_t ai = a[0]; 92 | accum0 = widemul_rr(ai, ai); 93 | ai *= 2; 94 | accum1 = widemul_rm(ai, &a[1]); 95 | accum2 = widemul_rm(ai, &a[2]); 96 | 97 | ai = a[1]; 98 | mac_rr(&accum2, ai, ai); 99 | ai *= 38; 100 | mac_rm(&accum0, ai, &a[4]); 101 | 102 | ai = a[2] * 38; 103 | mac_rm(&accum0, ai, &a[3]); 104 | mac_rm(&accum1, ai, &a[4]); 105 | 106 | ai = a[3] * 19; 107 | mac_rm(&accum1, ai, &a[3]); 108 | ai *= 2; 109 | mac_rm(&accum2, ai, &a[4]); 110 | 111 | uint64_t c0 = accum0 & mask; 112 | accum1 += shrld(accum0, 51); 113 | uint64_t c1 = accum1 & mask; 114 | accum2 += shrld(accum1, 51); 115 | c[2] = accum2 & mask; 116 | 117 | accum0 = accum2 >> 51; 118 | 119 | ai = a[0]*2; 120 | mac_rm(&accum0, ai, &a[3]); 121 | accum1 = widemul_rm(ai, &a[4]); 122 | 123 | ai = a[1]*2; 124 | mac_rm(&accum0, ai, &a[2]); 125 | mac_rm(&accum1, ai, &a[3]); 126 | 127 | mac_rr(&accum0, a[4]*19, a[4]); 128 | mac_rr(&accum1, a[2], a[2]); 129 | 130 | c[3] = accum0 & mask; 131 | accum1 += shrld(accum0, 51); 132 | c[4] = accum1 & mask; 133 | 134 | /* 2^102 * 16 * 5 * 19 * (1+ep) >> 64 135 | * = 2^(-13 + <13) 136 | */ 137 | 138 | uint64_t a1 = shrld(accum1,51); 139 | accum1 = a1 * 19 + c0; 140 | c[0] = accum1 & mask; 141 | c[1] = c1 + (accum1>>51); 142 | } 143 | 144 | void gf_mulw_unsigned (gf_25519_t *__restrict__ cs, const gf_25519_t *as, uint32_t b) { 145 | const uint64_t *a = as->limb, mask = ((1ull<<51)-1); 146 | uint64_t *c = cs->limb; 147 | 148 | __uint128_t accum = widemul_rm(b, &a[0]); 149 | uint64_t c0 = accum & mask; 150 | accum = shrld(accum,51); 151 | 152 | mac_rm(&accum, b, &a[1]); 153 | uint64_t c1 = accum & mask; 154 | accum = shrld(accum,51); 155 | 156 | mac_rm(&accum, b, &a[2]); 157 | c[2] = accum & mask; 158 | accum = shrld(accum,51); 159 | 160 | mac_rm(&accum, b, &a[3]); 161 | c[3] = accum & mask; 162 | accum = shrld(accum,51); 163 | 164 | mac_rm(&accum, b, &a[4]); 165 | c[4] = accum & mask; 166 | 167 | uint64_t a1 = shrld(accum,51); 168 | a1 = a1*19+c0; 169 | 170 | c[0] = a1 & mask; 171 | c[1] = c1 + (a1>>51); 172 | } 173 | -------------------------------------------------------------------------------- /src/arch/x86_64/f_impl.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #define GF_HEADROOM 933 6 | #define FIELD_LITERAL(a,b,c,d,e) {{ a,b,c,d,e }} 7 | 8 | #define LIMB_PLACE_VALUE(i) 51 9 | 10 | void gf_add_RAW (gf_25519_t *out, const gf_25519_t *a, const gf_25519_t *b) { 11 | for (unsigned int i=0; i<5; i++) { 12 | out->limb[i] = a->limb[i] + b->limb[i]; 13 | } 14 | } 15 | 16 | void gf_sub_RAW (gf_25519_t *out, const gf_25519_t *a, const gf_25519_t *b) { 17 | for (unsigned int i=0; i<5; i++) { 18 | out->limb[i] = a->limb[i] - b->limb[i]; 19 | } 20 | } 21 | 22 | void gf_bias (gf_25519_t *a, int amt) { 23 | a->limb[0] += ((uint64_t)(amt)<<52) - 38*amt; 24 | for (unsigned int i=1; i<5; i++) { 25 | a->limb[i] += ((uint64_t)(amt)<<52)-2*amt; 26 | } 27 | } 28 | 29 | void gf_weak_reduce (gf_25519_t *a) { 30 | uint64_t mask = (1ull<<51) - 1; 31 | uint64_t tmp = a->limb[4] >> 51; 32 | for (unsigned int i=4; i>0; i--) { 33 | a->limb[i] = (a->limb[i] & mask) + (a->limb[i-1]>>51); 34 | } 35 | a->limb[0] = (a->limb[0] & mask) + tmp*19; 36 | } 37 | -------------------------------------------------------------------------------- /src/bool.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bool.c 3 | * @author Mike Hamburg 4 | * 5 | * @copyright 6 | * Copyright (c) 2015-2018 Ristretto Developers, Cryptography Research, Inc. \n 7 | * Released under the MIT License. See LICENSE.txt for license information. 8 | * 9 | * @brief Boolean values used by this library 10 | */ 11 | 12 | #include 13 | 14 | /* These constants exist to make the existing implementation immediately 15 | * FFI-able and therefore testable, however exposing these constants and 16 | * `ristretto_bool_t` as part of the public API is probably a bad idea. 17 | * -@tarcieri 18 | * 19 | * Here is Mike Hamburg's original plan for booleans (from word.h): 20 | * 21 | * The external interface uses ristretto_bool_t, but this might be a different 22 | * size than our particular arch's word_t (and thus mask_t). Also, the caller 23 | * isn't guaranteed to pass it as nonzero. So bool_to_mask converts word sizes 24 | * and checks nonzero. 25 | * 26 | * On the flip side, mask_t is always -1 or 0, but it might be a different size 27 | * than ristretto_bool_t. 28 | */ 29 | 30 | /** RISTRETTO_TRUE = -1 so that RISTRETTO_TRUE & x = x */ 31 | const ristretto_bool_t RISTRETTO_TRUE = -(ristretto_bool_t)1; 32 | 33 | /** RISTRETTO_FALSE = 0 so that RISTRETTO_FALSE & x = 0 */ 34 | const ristretto_bool_t RISTRETTO_FALSE = 0; 35 | -------------------------------------------------------------------------------- /src/bzero.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | /** 6 | * @file bzero.c 7 | * @author Mike Hamburg 8 | * @brief Zero a byte string 9 | */ 10 | 11 | #include 12 | 13 | void ristretto_bzero ( 14 | void *s, 15 | size_t size 16 | ) { 17 | #ifdef __STDC_LIB_EXT1__ 18 | memset_s(s, size, 0, size); 19 | #else 20 | const size_t sw = sizeof(ristretto_word_t); 21 | volatile uint8_t *destroy = (volatile uint8_t *)s; 22 | for (; size && ((uintptr_t)destroy)%sw; size--, destroy++) 23 | *destroy = 0; 24 | for (; size >= sw; size -= sw, destroy += sw) 25 | *(volatile ristretto_word_t *)destroy = 0; 26 | for (; size; size--, destroy++) 27 | *destroy = 0; 28 | #endif 29 | } 30 | -------------------------------------------------------------------------------- /src/constant_time.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file constant_time.h 3 | * @copyright 4 | * Copyright (c) 2014-2018 Ristretto Developers, Cryptography Research, Inc. \n 5 | * Released under the MIT License. See LICENSE.txt for license information. 6 | * @author Mike Hamburg 7 | * 8 | * @brief Constant-time routines. 9 | */ 10 | 11 | #ifndef __CONSTANT_TIME_H__ 12 | #define __CONSTANT_TIME_H__ 1 13 | 14 | #include "word.h" 15 | #include 16 | 17 | /* 18 | * Constant-time operations on hopefully-compile-time-sized memory 19 | * regions. Needed for flexibility / demagication: not all fields 20 | * have sizes which are multiples of the vector width, necessitating 21 | * a change from the Ed448 versions. 22 | * 23 | * These routines would be much simpler to define at the byte level, 24 | * but if not vectorized they would be a significant fraction of the 25 | * runtime. Eg on NEON-less ARM, constant_time_lookup is like 15% of 26 | * signing time, vs 6% on Haswell with its fancy AVX2 vectors. 27 | * 28 | * If the compiler could do a good job of autovectorizing the code, 29 | * we could just leave it with the byte definition. But that's unlikely 30 | * on most deployed compilers, especially if you consider that pcmpeq[size] 31 | * is much faster than moving a scalar to the vector unit (which is what 32 | * a naive autovectorizer will do with constant_time_lookup on Intel). 33 | * 34 | * Instead, we're putting our trust in the loop unroller and unswitcher. 35 | */ 36 | 37 | 38 | /** 39 | * Unaligned big (vector?) register. 40 | */ 41 | typedef struct { 42 | big_register_t unaligned; 43 | } __attribute__((packed)) unaligned_br_t; 44 | 45 | /** 46 | * Unaligned word register, for architectures where that matters. 47 | */ 48 | typedef struct { 49 | word_t unaligned; 50 | } __attribute__((packed)) unaligned_word_t; 51 | 52 | /** 53 | * @brief Constant-time conditional swap. 54 | * 55 | * If doswap, then swap elem_bytes between *a and *b. 56 | * 57 | * *a and *b must not alias. Also, they must be at least as aligned 58 | * as their sizes, if the CPU cares about that sort of thing. 59 | */ 60 | static __inline__ void 61 | __attribute__((unused,always_inline)) 62 | constant_time_cond_swap ( 63 | void *__restrict__ a_, 64 | void *__restrict__ b_, 65 | word_t elem_bytes, 66 | mask_t doswap 67 | ) { 68 | word_t k; 69 | unsigned char *a = (unsigned char *)a_; 70 | unsigned char *b = (unsigned char *)b_; 71 | 72 | big_register_t br_mask = br_set_to_mask(doswap); 73 | for (k=0; k<=elem_bytes-sizeof(big_register_t); k+=sizeof(big_register_t)) { 74 | if (elem_bytes % sizeof(big_register_t)) { 75 | /* unaligned */ 76 | big_register_t xor = 77 | ((unaligned_br_t*)(&a[k]))->unaligned 78 | ^ ((unaligned_br_t*)(&b[k]))->unaligned; 79 | xor &= br_mask; 80 | ((unaligned_br_t*)(&a[k]))->unaligned ^= xor; 81 | ((unaligned_br_t*)(&b[k]))->unaligned ^= xor; 82 | } else { 83 | /* aligned */ 84 | big_register_t xor = 85 | *((big_register_t*)(&a[k])) 86 | ^ *((big_register_t*)(&b[k])); 87 | xor &= br_mask; 88 | *((big_register_t*)(&a[k])) ^= xor; 89 | *((big_register_t*)(&b[k])) ^= xor; 90 | } 91 | } 92 | 93 | if (elem_bytes % sizeof(big_register_t) >= sizeof(word_t)) { 94 | for (; k<=elem_bytes-sizeof(word_t); k+=sizeof(word_t)) { 95 | if (elem_bytes % sizeof(word_t)) { 96 | /* unaligned */ 97 | word_t xor = 98 | ((unaligned_word_t*)(&a[k]))->unaligned 99 | ^ ((unaligned_word_t*)(&b[k]))->unaligned; 100 | xor &= doswap; 101 | ((unaligned_word_t*)(&a[k]))->unaligned ^= xor; 102 | ((unaligned_word_t*)(&b[k]))->unaligned ^= xor; 103 | } else { 104 | /* aligned */ 105 | word_t xor = 106 | *((word_t*)(&a[k])) 107 | ^ *((word_t*)(&b[k])); 108 | xor &= doswap; 109 | *((word_t*)(&a[k])) ^= xor; 110 | *((word_t*)(&b[k])) ^= xor; 111 | } 112 | } 113 | } 114 | 115 | if (elem_bytes % sizeof(word_t)) { 116 | for (; kunaligned 156 | |= br_mask & ((const unaligned_br_t*)(&table[k+j*elem_bytes]))->unaligned; 157 | } else { 158 | /* aligned */ 159 | *(big_register_t *)(out+k) |= br_mask & *(const big_register_t*)(&table[k+j*elem_bytes]); 160 | } 161 | } 162 | 163 | word_t mask = word_is_zero(idx^j); 164 | if (elem_bytes % sizeof(big_register_t) >= sizeof(word_t)) { 165 | for (; k<=elem_bytes-sizeof(word_t); k+=sizeof(word_t)) { 166 | if (elem_bytes % sizeof(word_t)) { 167 | /* input unaligned, output aligned */ 168 | *(word_t *)(out+k) |= mask & ((const unaligned_word_t*)(&table[k+j*elem_bytes]))->unaligned; 169 | } else { 170 | /* aligned */ 171 | *(word_t *)(out+k) |= mask & *(const word_t*)(&table[k+j*elem_bytes]); 172 | } 173 | } 174 | } 175 | 176 | if (elem_bytes % sizeof(word_t)) { 177 | for (; kunaligned 214 | = ( ((unaligned_br_t*)(&table[k+j*elem_bytes]))->unaligned & ~br_mask ) 215 | | ( ((const unaligned_br_t *)(in+k))->unaligned & br_mask ); 216 | } else { 217 | /* aligned */ 218 | *(big_register_t*)(&table[k+j*elem_bytes]) 219 | = ( *(big_register_t*)(&table[k+j*elem_bytes]) & ~br_mask ) 220 | | ( *(const big_register_t *)(in+k) & br_mask ); 221 | } 222 | } 223 | 224 | word_t mask = word_is_zero(idx^j); 225 | if (elem_bytes % sizeof(big_register_t) >= sizeof(word_t)) { 226 | for (; k<=elem_bytes-sizeof(word_t); k+=sizeof(word_t)) { 227 | if (elem_bytes % sizeof(word_t)) { 228 | /* output unaligned, input aligned */ 229 | ((unaligned_word_t*)(&table[k+j*elem_bytes]))->unaligned 230 | = ( ((unaligned_word_t*)(&table[k+j*elem_bytes]))->unaligned & ~mask ) 231 | | ( *(const word_t *)(in+k) & mask ); 232 | } else { 233 | /* aligned */ 234 | *(word_t*)(&table[k+j*elem_bytes]) 235 | = ( *(word_t*)(&table[k+j*elem_bytes]) & ~mask ) 236 | | ( *(const word_t *)(in+k) & mask ); 237 | } 238 | } 239 | } 240 | 241 | if (elem_bytes % sizeof(word_t)) { 242 | for (; kunaligned = br_mask & ((const unaligned_br_t*)(&b[k]))->unaligned; 273 | } else { 274 | /* aligned */ 275 | *(big_register_t *)(a+k) = br_mask & *(const big_register_t*)(&b[k]); 276 | } 277 | } 278 | 279 | if (elem_bytes % sizeof(big_register_t) >= sizeof(word_t)) { 280 | for (; k<=elem_bytes-sizeof(word_t); k+=sizeof(word_t)) { 281 | if (elem_bytes % sizeof(word_t)) { 282 | /* unaligned */ 283 | ((unaligned_word_t*)(&a[k]))->unaligned = mask & ((const unaligned_word_t*)(&b[k]))->unaligned; 284 | } else { 285 | /* aligned */ 286 | *(word_t *)(a+k) = mask & *(const word_t*)(&b[k]); 287 | } 288 | } 289 | } 290 | 291 | if (elem_bytes % sizeof(word_t)) { 292 | for (; kunaligned = 329 | ( br_mask & ((const unaligned_br_t*)(&bTrue [k]))->unaligned) 330 | | (~br_mask & ((const unaligned_br_t*)(&bFalse[k]))->unaligned); 331 | } else { 332 | /* aligned */ 333 | *(big_register_t *)(a+k) = 334 | ( br_mask & *(const big_register_t*)(&bTrue [k])) 335 | | (~br_mask & *(const big_register_t*)(&bFalse[k])); 336 | } 337 | } 338 | 339 | if (elem_bytes % sizeof(big_register_t) >= sizeof(word_t)) { 340 | for (; k<=elem_bytes-sizeof(word_t); k+=sizeof(word_t)) { 341 | if (alignment_bytes % sizeof(word_t)) { 342 | /* unaligned */ 343 | ((unaligned_word_t*)(&a[k]))->unaligned = 344 | ( mask & ((const unaligned_word_t*)(&bTrue [k]))->unaligned) 345 | | (~mask & ((const unaligned_word_t*)(&bFalse[k]))->unaligned); 346 | } else { 347 | /* aligned */ 348 | *(word_t *)(a+k) = 349 | ( mask & *(const word_t*)(&bTrue [k])) 350 | | (~mask & *(const word_t*)(&bFalse[k])); 351 | } 352 | } 353 | } 354 | 355 | if (elem_bytes % sizeof(word_t)) { 356 | for (; k 13 | #include "word.h" 14 | #include "field.h" 15 | 16 | #define point_t ristretto255_point_t 17 | 18 | extern const int RISTRETTO255_EDWARDS_D; 19 | #define EDWARDS_D RISTRETTO255_EDWARDS_D 20 | 21 | extern const gf_25519_t RISTRETTO255_FACTOR; 22 | 23 | extern mask_t ristretto255_deisogenize ( 24 | gf_25519_t *__restrict__ s, 25 | gf_25519_t *__restrict__ inv_el_sum, 26 | gf_25519_t *__restrict__ inv_el_m1, 27 | const point_t *p, 28 | mask_t toggle_hibit_s, 29 | mask_t toggle_altx, 30 | mask_t toggle_rotation 31 | ); 32 | 33 | void ristretto255_point_from_hash_nonuniform ( 34 | point_t *p, 35 | const unsigned char ser[SER_BYTES] 36 | ) { 37 | gf_25519_t r0,r,a,b,c,N,e; 38 | const uint8_t mask = (uint8_t)(0xFE<<(6)); 39 | ignore_result(gf_deserialize(&r0,ser,0,mask)); 40 | gf_strong_reduce(&r0); 41 | gf_sqr(&a,&r0); 42 | gf_mul_qnr(&r,&a); 43 | 44 | /* Compute D@c := (dr+a-d)(dr-ar-d) with a=1 */ 45 | gf_sub(&a,&r,&ONE); 46 | gf_mulw(&b,&a,EDWARDS_D); /* dr-d */ 47 | gf_add(&a,&b,&ONE); 48 | gf_sub(&b,&b,&r); 49 | gf_mul(&c,&a,&b); 50 | 51 | /* compute N := (r+1)(a-2d) */ 52 | gf_add(&a,&r,&ONE); 53 | gf_mulw(&N,&a,1-2*EDWARDS_D); 54 | 55 | /* e = +-sqrt(1/ND) or +-r0 * sqrt(qnr/ND) */ 56 | gf_mul(&a,&c,&N); 57 | mask_t square = gf_isr(&b,&a); 58 | gf_cond_sel(&c,&r0,&ONE,square); /* r? = square ? 1 : r0 */ 59 | gf_mul(&e,&b,&c); 60 | 61 | /* s@a = +-|N.e| */ 62 | gf_mul(&a,&N,&e); 63 | gf_cond_neg(&a,gf_lobit(&a) ^ ~square); 64 | 65 | /* t@b = -+ cN(r-1)((a-2d)e)^2 - 1 */ 66 | gf_mulw(&c,&e,1-2*EDWARDS_D); /* (a-2d)e */ 67 | gf_sqr(&b,&c); 68 | gf_sub(&e,&r,&ONE); 69 | gf_mul(&c,&b,&e); 70 | gf_mul(&b,&c,&N); 71 | gf_cond_neg(&b,square); 72 | gf_sub(&b,&b,&ONE); 73 | 74 | /* isogenize */ 75 | gf_mul(&c,&a,&SQRT_MINUS_ONE); 76 | gf_copy(&a,&c); 77 | 78 | gf_sqr(&c,&a); /* s^2 */ 79 | gf_add(&a,&a,&a); /* 2s */ 80 | gf_add(&e,&c,&ONE); 81 | gf_mul(&p->t,&a,&e); /* 2s(1+s^2) */ 82 | gf_mul(&p->x,&a,&b); /* 2st */ 83 | gf_sub(&a,&ONE,&c); 84 | gf_mul(&p->y,&e,&a); /* (1+s^2)(1-s^2) */ 85 | gf_mul(&p->z,&a,&b); /* (1-s^2)t */ 86 | 87 | assert(ristretto255_point_valid(p)); 88 | } 89 | 90 | void ristretto255_point_from_hash_uniform ( 91 | point_t *pt, 92 | const unsigned char hashed_data[2*SER_BYTES] 93 | ) { 94 | point_t pt2; 95 | ristretto255_point_from_hash_nonuniform(pt,hashed_data); 96 | ristretto255_point_from_hash_nonuniform(&pt2,&hashed_data[SER_BYTES]); 97 | ristretto255_point_add(pt,pt,&pt2); 98 | } 99 | 100 | /* Elligator_onto: 101 | * Make elligator-inverse onto at the cost of roughly halving the success probability. 102 | * Currently no effect for curves with field size 1 bit mod 8 (where the top bit 103 | * is chopped off). FUTURE MAGIC: automatic at least for brainpool-style curves; support 104 | * log p == 1 mod 8 brainpool curves maybe? 105 | */ 106 | #define MAX(A,B) (((A)>(B)) ? (A) : (B)) 107 | 108 | ristretto_error_t 109 | ristretto255_invert_elligator_nonuniform ( 110 | unsigned char recovered_hash[SER_BYTES], 111 | const point_t *p, 112 | uint32_t hint_ 113 | ) { 114 | mask_t hint = hint_; 115 | mask_t sgn_s = -(hint & 1), 116 | sgn_altx = -(hint>>1 & 1), 117 | sgn_r0 = -(hint>>2 & 1), 118 | /* FUTURE MAGIC: eventually if there's a curve which needs sgn_ed_T but not sgn_r0, 119 | * change this mask extraction. 120 | */ 121 | sgn_ed_T = -(hint>>3 & 1); 122 | gf_25519_t a,b,c; 123 | ristretto255_deisogenize(&a,&b,&c,p,sgn_s,sgn_altx,sgn_ed_T); 124 | 125 | mask_t is_identity = gf_eq(&p->t,&ZERO); 126 | 127 | /* Terrible, terrible special casing due to lots of 0/0 is deisogenize 128 | * Basically we need to generate -D and +- i*RISTRETTO255_FACTOR 129 | */ 130 | gf_mul_i(&a,&RISTRETTO255_FACTOR); 131 | gf_cond_sel(&b,&b,&ONE,is_identity); 132 | gf_cond_neg(&a,sgn_altx); 133 | gf_cond_sel(&c,&c,&a,is_identity & sgn_ed_T); 134 | gf_cond_sel(&c,&c,&ZERO,is_identity & ~sgn_ed_T); 135 | gf_mulw(&a,&ONE,-EDWARDS_D); 136 | gf_cond_sel(&c,&c,&a,is_identity & ~sgn_ed_T &~ sgn_altx); 137 | 138 | gf_mulw(&a,&b,-EDWARDS_D); 139 | gf_add(&b,&a,&b); 140 | gf_sub(&a,&a,&c); 141 | gf_add(&b,&b,&c); 142 | gf_cond_swap(&a,&b,sgn_s); 143 | gf_mul_qnr(&c,&b); 144 | gf_mul(&b,&c,&a); 145 | mask_t succ = gf_isr(&c,&b); 146 | succ |= gf_eq(&b,&ZERO); 147 | gf_mul(&b,&c,&a); 148 | 149 | gf_cond_neg(&b, sgn_r0^gf_lobit(&b)); 150 | /* Eliminate duplicate values for identity ... */ 151 | succ &= ~(gf_eq(&b,&ZERO) & (sgn_r0 | sgn_s)); 152 | // succ &= ~(is_identity & sgn_ed_T); /* NB: there are no preimages of rotated identity. */ 153 | 154 | gf_serialize(recovered_hash,&b,1); 155 | recovered_hash[SER_BYTES-1] ^= (hint>>4)<<7; 156 | 157 | return ristretto_succeed_if(mask_to_bool(succ)); 158 | } 159 | 160 | ristretto_error_t 161 | ristretto255_invert_elligator_uniform ( 162 | unsigned char partial_hash[2*SER_BYTES], 163 | const point_t *p, 164 | uint32_t hint 165 | ) { 166 | point_t pt2; 167 | ristretto255_point_from_hash_nonuniform(&pt2,&partial_hash[SER_BYTES]); 168 | ristretto255_point_sub(&pt2,p,&pt2); 169 | return ristretto255_invert_elligator_nonuniform(partial_hash,&pt2,hint); 170 | } 171 | -------------------------------------------------------------------------------- /src/f_arithmetic.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @cond internal 3 | * @file f_arithmetic.c 4 | * @copyright 5 | * Copyright (c) 2014-2018 Ristretto Developers, Cryptography Research, Inc. \n 6 | * Released under the MIT License. See LICENSE.txt for license information. 7 | * @author Mike Hamburg 8 | * @brief Field arithmetic. 9 | */ 10 | 11 | #include 12 | #include "field.h" 13 | #include "constant_time.h" 14 | 15 | static const gf_25519_t MODULUS = FIELD_LITERAL( 16 | 0x7ffffffffffed, 0x7ffffffffffff, 0x7ffffffffffff, 0x7ffffffffffff, 0x7ffffffffffff 17 | ); 18 | 19 | const gf_25519_t SQRT_MINUS_ONE = FIELD_LITERAL( 20 | 0x61b274a0ea0b0, 0x0d5a5fc8f189d, 0x7ef5e9cbd0c60, 0x78595a6804c9e, 0x2b8324804fc1d 21 | ); 22 | 23 | /* Guarantee: a^2 x = 0 if x = 0; else a^2 x = 1 or SQRT_MINUS_ONE; */ 24 | mask_t gf_isr (gf_25519_t *a, const gf_25519_t *x) { 25 | gf_25519_t L0, L1, L2, L3; 26 | 27 | gf_sqr (&L0, x); 28 | gf_mul (&L1, &L0, x); 29 | gf_sqr (&L0, &L1); 30 | gf_mul (&L1, &L0, x); 31 | gf_sqrn(&L0, &L1, 3); 32 | gf_mul (&L2, &L0, &L1); 33 | gf_sqrn(&L0, &L2, 6); 34 | gf_mul (&L1, &L2, &L0); 35 | gf_sqr (&L2, &L1); 36 | gf_mul (&L0, &L2, x); 37 | gf_sqrn(&L2, &L0, 12); 38 | gf_mul (&L0, &L2, &L1); 39 | gf_sqrn(&L2, &L0, 25); 40 | gf_mul (&L3, &L2, &L0); 41 | gf_sqrn(&L2, &L3, 25); 42 | gf_mul (&L1, &L2, &L0); 43 | gf_sqrn(&L2, &L1, 50); 44 | gf_mul (&L0, &L2, &L3); 45 | gf_sqrn(&L2, &L0, 125); 46 | gf_mul (&L3, &L2, &L0); 47 | gf_sqrn(&L2, &L3, 2); 48 | gf_mul (&L0, &L2, x); 49 | 50 | gf_sqr (&L2, &L0); 51 | gf_mul (&L3, &L2, x); 52 | gf_add(&L1,&L3,&ONE); 53 | mask_t one = gf_eq(&L3,&ONE); 54 | mask_t succ = one | gf_eq(&L1, &ZERO); 55 | mask_t qr = one | gf_eq(&L3, &SQRT_MINUS_ONE); 56 | 57 | constant_time_select(&L2, &SQRT_MINUS_ONE, &ONE, sizeof(L2), qr, 0); 58 | gf_mul (a,&L2,&L0); 59 | return succ; 60 | } 61 | 62 | /** Serialize to wire format. */ 63 | void gf_serialize (uint8_t serial[SER_BYTES], const gf_25519_t *x, int with_hibit) { 64 | gf_25519_t red; 65 | gf_copy(&red, x); 66 | gf_strong_reduce(&red); 67 | if (!with_hibit) { assert(gf_hibit(&red) == 0); } 68 | 69 | unsigned int j=0, fill=0; 70 | dword_t buffer = 0; 71 | UNROLL for (unsigned int i=0; i>= 8; 80 | } 81 | } 82 | 83 | /** Return high bit of x = low bit of 2x mod p */ 84 | mask_t gf_hibit(const gf_25519_t *x) { 85 | gf_25519_t y; 86 | gf_add(&y,x,x); 87 | gf_strong_reduce(&y); 88 | return -(y.limb[0]&1); 89 | } 90 | 91 | /** Return high bit of x = low bit of 2x mod p */ 92 | mask_t gf_lobit(const gf_25519_t *x) { 93 | gf_25519_t y; 94 | gf_copy(&y,x); 95 | gf_strong_reduce(&y); 96 | return -(y.limb[0]&1); 97 | } 98 | 99 | /** Deserialize from wire format; return -1 on success and 0 on failure. */ 100 | mask_t gf_deserialize (gf_25519_t *x, const uint8_t serial[SER_BYTES], int with_hibit, uint8_t hi_nmask) { 101 | unsigned int j=0, fill=0; 102 | dword_t buffer = 0; 103 | dsword_t scarry = 0; 104 | UNROLL for (unsigned int i=0; ilimb[LIMBPERM(i)] = (i>= LIMB_PLACE_VALUE(LIMBPERM(i)); 115 | scarry = (scarry + x->limb[LIMBPERM(i)] - MODULUS.limb[LIMBPERM(i)]) >> (8*sizeof(word_t)); 116 | } 117 | mask_t succ = with_hibit ? -(mask_t)1 : ~gf_hibit(x); 118 | return succ & word_is_zero(buffer) & ~word_is_zero(scarry); 119 | } 120 | 121 | /** Reduce to canonical form. */ 122 | void gf_strong_reduce (gf_25519_t *a) { 123 | /* first, clear high */ 124 | gf_weak_reduce(a); /* Determined to have negligible perf impact. */ 125 | 126 | /* now the total is less than 2p */ 127 | 128 | /* compute total_value - p. No need to reduce mod p. */ 129 | dsword_t scarry = 0; 130 | for (unsigned int i=0; ilimb[LIMBPERM(i)] - MODULUS.limb[LIMBPERM(i)]; 132 | a->limb[LIMBPERM(i)] = scarry & LIMB_MASK(LIMBPERM(i)); 133 | scarry >>= LIMB_PLACE_VALUE(LIMBPERM(i)); 134 | } 135 | 136 | /* uncommon case: it was >= p, so now scarry = 0 and this = x 137 | * common case: it was < p, so now scarry = -1 and this = x - p + 2^255 138 | * so let's add back in p. will carry back off the top for 2^255. 139 | */ 140 | assert(word_is_zero(scarry) | word_is_zero(scarry+1)); 141 | 142 | word_t scarry_0 = scarry; 143 | dword_t carry = 0; 144 | 145 | /* add it back */ 146 | for (unsigned int i=0; ilimb[LIMBPERM(i)] + (scarry_0 & MODULUS.limb[LIMBPERM(i)]); 148 | a->limb[LIMBPERM(i)] = carry & LIMB_MASK(LIMBPERM(i)); 149 | carry >>= LIMB_PLACE_VALUE(LIMBPERM(i)); 150 | } 151 | 152 | assert(word_is_zero(carry + scarry_0)); 153 | } 154 | 155 | /** Subtract two gf elements d=a-b */ 156 | void gf_sub (gf_25519_t *d, const gf_25519_t *a, const gf_25519_t *b) { 157 | gf_sub_RAW ( d, a, b ); 158 | gf_bias( d, 2 ); 159 | gf_weak_reduce ( d ); 160 | } 161 | 162 | /** Add two field elements d = a+b */ 163 | void gf_add (gf_25519_t *d, const gf_25519_t *a, const gf_25519_t *b) { 164 | gf_add_RAW ( d, a, b ); 165 | gf_weak_reduce ( d ); 166 | } 167 | 168 | /** Compare a==b */ 169 | mask_t gf_eq(const gf_25519_t *a, const gf_25519_t *b) { 170 | gf_25519_t c; 171 | gf_sub(&c,a,b); 172 | gf_strong_reduce(&c); 173 | mask_t ret=0; 174 | for (unsigned int i=0; i 17 | #include 18 | 19 | #include "word.h" 20 | 21 | #define SER_BYTES RISTRETTO255_SER_BYTES 22 | #define GF_LIT_LIMB_BITS 51 23 | #define GF_BITS 255 24 | 25 | #define INLINE_UNUSED __inline__ __attribute__((unused,always_inline)) 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | /* Defined below in f_impl.h */ 32 | static INLINE_UNUSED void gf_copy (gf_25519_t *out, const gf_25519_t *a) { *out = *a; } 33 | static INLINE_UNUSED void gf_add_RAW (gf_25519_t *out, const gf_25519_t *a, const gf_25519_t *b); 34 | static INLINE_UNUSED void gf_sub_RAW (gf_25519_t *out, const gf_25519_t *a, const gf_25519_t *b); 35 | static INLINE_UNUSED void gf_bias (gf_25519_t *inout, int amount); 36 | static INLINE_UNUSED void gf_weak_reduce (gf_25519_t *inout); 37 | 38 | void gf_strong_reduce (gf_25519_t *inout); 39 | void gf_add (gf_25519_t *out, const gf_25519_t *a, const gf_25519_t *b); 40 | void gf_sub (gf_25519_t *out, const gf_25519_t *a, const gf_25519_t *b); 41 | void gf_mul (gf_25519_t *__restrict__ out, const gf_25519_t *a, const gf_25519_t *b); 42 | void gf_mulw_unsigned (gf_25519_t *__restrict__ out, const gf_25519_t *a, uint32_t b); 43 | void gf_sqr (gf_25519_t *__restrict__ out, const gf_25519_t *a); 44 | mask_t gf_isr(gf_25519_t *a, const gf_25519_t *x); /** a^2 x = 1, QNR, or 0 if x=0. Return true if successful */ 45 | mask_t gf_eq (const gf_25519_t *x, const gf_25519_t *y); 46 | mask_t gf_lobit (const gf_25519_t *x); 47 | mask_t gf_hibit (const gf_25519_t *x); 48 | 49 | void gf_serialize (uint8_t *serial, const gf_25519_t *x,int with_highbit); 50 | mask_t gf_deserialize (gf_25519_t *x, const uint8_t serial[SER_BYTES], int with_hibit, uint8_t hi_nmask); 51 | 52 | 53 | #ifdef __cplusplus 54 | } /* extern "C" */ 55 | #endif 56 | 57 | #include "f_impl.h" /* Bring in the inline implementations */ 58 | 59 | extern const gf_25519_t SQRT_MINUS_ONE; 60 | 61 | #ifndef LIMBPERM 62 | #define LIMBPERM(i) (i) 63 | #endif 64 | #define LIMB_MASK(i) (((1ull)< 16 | 17 | /** Square x, n times. */ 18 | static RISTRETTO_INLINE void gf_sqrn ( 19 | gf_25519_t *__restrict__ y, 20 | const gf_25519_t *x, 21 | int n 22 | ) { 23 | gf_25519_t tmp; 24 | assert(n>0); 25 | if (n&1) { 26 | gf_sqr(y,x); 27 | n--; 28 | } else { 29 | gf_sqr(&tmp,x); 30 | gf_sqr(y,&tmp); 31 | n-=2; 32 | } 33 | for (; n; n-=2) { 34 | gf_sqr(&tmp,y); 35 | gf_sqr(y,&tmp); 36 | } 37 | } 38 | 39 | #define gf_add_nr gf_add_RAW 40 | 41 | /** Subtract mod p. Bias by 2 and don't reduce */ 42 | static inline void gf_sub_nr ( gf_25519_t *c, const gf_25519_t *a, const gf_25519_t *b ) { 43 | gf_sub_RAW(c,a,b); 44 | gf_bias(c, 2); 45 | if (GF_HEADROOM < 3) gf_weak_reduce(c); 46 | } 47 | 48 | /** Subtract mod p. Bias by amt but don't reduce. */ 49 | static inline void gf_subx_nr ( gf_25519_t *c, const gf_25519_t *a, const gf_25519_t *b, int amt ) { 50 | gf_sub_RAW(c,a,b); 51 | gf_bias(c, amt); 52 | if (GF_HEADROOM < amt+1) gf_weak_reduce(c); 53 | } 54 | 55 | /** Mul by signed int. Not constant-time WRT the sign of that int. */ 56 | static inline void gf_mulw(gf_25519_t *c, const gf_25519_t *a, int32_t w) { 57 | if (w>0) { 58 | gf_mulw_unsigned(c, a, w); 59 | } else { 60 | gf_mulw_unsigned(c, a, -w); 61 | gf_sub(c,&ZERO,c); 62 | } 63 | } 64 | 65 | /** Constant time, x = is_z ? z : y */ 66 | static inline void gf_cond_sel(gf_25519_t *x, const gf_25519_t *y, const gf_25519_t *z, mask_t is_z) { 67 | constant_time_select(x,y,z,sizeof(gf_25519_t),is_z,0); 68 | } 69 | 70 | /** Constant time, if (neg) x=-x; */ 71 | static inline void gf_cond_neg(gf_25519_t *x, mask_t neg) { 72 | gf_25519_t y; 73 | gf_sub(&y,&ZERO,x); 74 | gf_cond_sel(x,x,&y,neg); 75 | } 76 | 77 | /** Constant time, if (swap) (x,y) = (y,x); */ 78 | static inline void 79 | gf_cond_swap(gf_25519_t *x, gf_25519_t *__restrict__ y, mask_t swap) { 80 | constant_time_cond_swap(x,y,sizeof(gf_25519_t),swap); 81 | } 82 | 83 | static RISTRETTO_INLINE void gf_mul_qnr(gf_25519_t *__restrict__ out, const gf_25519_t *x) { 84 | /* r = QNR * r0^2 */ 85 | gf_mul(out,x,&SQRT_MINUS_ONE); 86 | } 87 | 88 | static RISTRETTO_INLINE void gf_div_qnr(gf_25519_t *__restrict__ out, const gf_25519_t *x) { 89 | /* r = QNR * r0^2 */ 90 | gf_mul(out,x,&SQRT_MINUS_ONE); 91 | gf_sub(out,&ZERO,out); 92 | } 93 | 94 | #define gf_mul_i gf_mul_qnr 95 | #define gf_div_i gf_div_qnr 96 | 97 | 98 | #endif // __GF_H__ 99 | -------------------------------------------------------------------------------- /src/portable_endian.h: -------------------------------------------------------------------------------- 1 | /* Subset of Mathias Panzenböck's portable endian code, public domain */ 2 | 3 | #ifndef __PORTABLE_ENDIAN_H__ 4 | #define __PORTABLE_ENDIAN_H__ 5 | 6 | #if defined(__linux__) || defined(__CYGWIN__) 7 | # include 8 | #elif defined(__OpenBSD__) 9 | # include 10 | #elif defined(__APPLE__) 11 | # include 12 | # define htole64(x) OSSwapHostToLittleInt64(x) 13 | # define le64toh(x) OSSwapLittleToHostInt64(x) 14 | #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) 15 | # include 16 | # ifndef le64toh 17 | # define le64toh(x) letoh64(x) 18 | # endif 19 | #elif defined(__sun) && defined(__SVR4) 20 | # include 21 | # define htole64(x) LE_64(x) 22 | # define le64toh(x) LE_64(x) 23 | #elif defined(_WIN16) || defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) 24 | # if defined(_MSC_VER) 25 | # define __builtin_bswap64(x) _byteswap_uint64((x)) 26 | # else 27 | # include 28 | # endif 29 | # include 30 | # if BYTE_ORDER == LITTLE_ENDIAN 31 | # define htole64(x) (x) 32 | # define le64toh(x) (x) 33 | # elif BYTE_ORDER == BIG_ENDIAN 34 | # define htole64(x) __builtin_bswap64(x) 35 | # define le64toh(x) __builtin_bswap64(x) 36 | # else 37 | # error byte order not supported 38 | # endif 39 | #else 40 | # error platform not supported 41 | #endif 42 | 43 | #endif // __PORTABLE_ENDIAN_H__ 44 | -------------------------------------------------------------------------------- /src/ristretto_gen_tables.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ristretto_gen_tables.c 3 | * @author Mike Hamburg 4 | * 5 | * @copyright 6 | * Copyright (c) 2015-2018 Ristretto Developers, Cryptography Research, Inc. \n 7 | * Released under the MIT License. See LICENSE.txt for license information. 8 | * 9 | * @brief Ristretto255 global constant table precomputation. 10 | */ 11 | 12 | #define _XOPEN_SOURCE 600 /* for posix_memalign */ 13 | #include 14 | #include 15 | 16 | #include 17 | #include "field.h" 18 | #include "f_field.h" 19 | 20 | static const unsigned char base_point_ser_for_pregen[SER_BYTES] = { 21 | 0xe2, 0xf2, 0xae, 0x0a, 0x6a, 0xbc, 0x4e, 0x71, 0xa8, 0x84, 0xa9, 0x61, 0xc5, 0x00, 0x51, 0x5f, 0x58, 0xe3, 0x0b, 0x6a, 0xa5, 0x82, 0xdd, 0x8d, 0xb6, 0xa6, 0x59, 0x45, 0xe0, 0x8d, 0x2d, 0x76 22 | }; 23 | 24 | /* To satisfy linker. */ 25 | const gf_25519_t ristretto255_precomputed_base_as_fe[1]; 26 | const ristretto255_point_t ristretto255_point_base; 27 | 28 | struct niels_s; 29 | const gf_25519_t *ristretto255_precomputed_wnaf_as_fe; 30 | extern const size_t ristretto255_sizeof_precomputed_wnafs; 31 | 32 | void ristretto255_precompute_wnafs ( 33 | struct niels_s *out, 34 | const ristretto255_point_t *base 35 | ); 36 | static void field_print(const gf_25519_t *f) { 37 | unsigned char ser[SER_BYTES]; 38 | gf_serialize(ser,f,1); 39 | int b=0, i, comma=0; 40 | unsigned long long limb = 0; 41 | printf("FIELD_LITERAL("); 42 | for (i=0; i= GF_LIT_LIMB_BITS || i == SER_BYTES-1) { 46 | limb &= (1ull<>(8-b); 52 | } 53 | } 54 | printf(")"); 55 | assert(b<8); 56 | } 57 | 58 | int main(int argc, char **argv) { 59 | (void)argc; (void)argv; 60 | 61 | ristretto255_point_t real_point_base; 62 | int ret = ristretto255_point_decode(&real_point_base,base_point_ser_for_pregen,0); 63 | if (ret != RISTRETTO_SUCCESS) { 64 | fprintf(stderr, "Can't decode base point!\n"); 65 | return 1; 66 | } 67 | 68 | ristretto255_precomputed_s *pre; 69 | ret = posix_memalign((void**)&pre, ristretto255_alignof_precomputed_s, ristretto255_sizeof_precomputed_s); 70 | if (ret || !pre) { 71 | fprintf(stderr, "Can't allocate space for precomputed table\n"); 72 | return 1; 73 | } 74 | ristretto255_precompute(pre, &real_point_base); 75 | 76 | struct niels_s *pre_wnaf; 77 | ret = posix_memalign((void**)&pre_wnaf, ristretto255_alignof_precomputed_s, ristretto255_sizeof_precomputed_wnafs); 78 | if (ret || !pre_wnaf) { 79 | fprintf(stderr, "Can't allocate space for precomputed WNAF table\n"); 80 | return 1; 81 | } 82 | ristretto255_precompute_wnafs(pre_wnaf, &real_point_base); 83 | 84 | const gf_25519_t *output; 85 | unsigned i; 86 | 87 | printf("/** @warning: this file was automatically generated. */\n"); 88 | printf("#include \"field.h\"\n\n"); 89 | printf("#include \n\n"); 90 | printf("#define ristretto255__id ristretto255_##_id\n"); 91 | 92 | output = (const gf_25519_t *)&real_point_base; 93 | printf("const ristretto255_point_t ristretto255_point_base = {\n"); 94 | for (i=0; i < sizeof(ristretto255_point_t); i+=sizeof(gf_25519_t)) { 95 | if (i) printf(",\n "); 96 | field_print(output++); 97 | } 98 | printf("\n};\n"); 99 | 100 | output = (const gf_25519_t *)pre; 101 | printf("const gf_25519_t ristretto255_precomputed_base_as_fe[%d]\n", 102 | (int)(ristretto255_sizeof_precomputed_s / sizeof(gf_25519_t))); 103 | printf("VECTOR_ALIGNED = {\n "); 104 | 105 | for (i=0; i < ristretto255_sizeof_precomputed_s; i+=sizeof(gf_25519_t)) { 106 | if (i) printf(",\n "); 107 | field_print(output++); 108 | } 109 | printf("\n};\n"); 110 | 111 | output = (const gf_25519_t *)pre_wnaf; 112 | printf("const gf_25519_t ristretto255_precomputed_wnaf_as_fe[%d]\n", 113 | (int)(ristretto255_sizeof_precomputed_wnafs / sizeof(gf_25519_t))); 114 | printf("VECTOR_ALIGNED = {\n "); 115 | for (i=0; i < ristretto255_sizeof_precomputed_wnafs; i+=sizeof(gf_25519_t)) { 116 | if (i) printf(",\n "); 117 | field_print(output++); 118 | } 119 | printf("\n};\n"); 120 | 121 | return 0; 122 | } 123 | -------------------------------------------------------------------------------- /src/scalar.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file scalar.c 3 | * @author Mike Hamburg 4 | * 5 | * @copyright 6 | * Copyright (c) 2015-2018 Ristretto Developers, Cryptography Research, Inc. \n 7 | * Released under the MIT License. See LICENSE.txt for license information. 8 | * 9 | * @brief Ristretto255 high-level functions. 10 | */ 11 | #include "word.h" 12 | #include "constant_time.h" 13 | #include 14 | 15 | #define SCALAR_BITS RISTRETTO255_SCALAR_BITS 16 | #define SCALAR_SER_BYTES RISTRETTO255_SCALAR_BYTES 17 | #define SCALAR_LIMBS RISTRETTO255_SCALAR_LIMBS 18 | #define scalar_t ristretto255_scalar_t 19 | 20 | static const ristretto_word_t MONTGOMERY_FACTOR = (ristretto_word_t)0xd2b51da312547e1bull; 21 | static const scalar_t sc_p = {{ 22 | SC_LIMB(0x5812631a5cf5d3ed), SC_LIMB(0x14def9dea2f79cd6), SC_LIMB(0x0000000000000000), SC_LIMB(0x1000000000000000) 23 | }}, sc_r2 = {{ 24 | SC_LIMB(0xa40611e3449c0f01), SC_LIMB(0xd00e1ba768859347), SC_LIMB(0xceec73d217f5be65), SC_LIMB(0x0399411b7c309a3d) 25 | }}; 26 | 27 | #define WBITS RISTRETTO_WORD_BITS /* NB this may be different from ARCH_WORD_BITS */ 28 | 29 | const scalar_t ristretto255_scalar_one = {{1}}, ristretto255_scalar_zero = {{0}}; 30 | 31 | /** {extra,accum} - sub +? p 32 | * Must have extra <= 1 33 | */ 34 | static RISTRETTO_NOINLINE void sc_subx( 35 | scalar_t *out, 36 | const ristretto_word_t accum[SCALAR_LIMBS], 37 | const scalar_t *sub, 38 | const scalar_t *p, 39 | ristretto_word_t extra 40 | ) { 41 | ristretto_dsword_t chain = 0; 42 | unsigned int i; 43 | for (i=0; ilimb[i]; 45 | out->limb[i] = chain; 46 | chain >>= WBITS; 47 | } 48 | ristretto_word_t borrow = chain+extra; /* = 0 or -1 */ 49 | 50 | chain = 0; 51 | for (i=0; ilimb[i]) + (p->limb[i] & borrow); 53 | out->limb[i] = chain; 54 | chain >>= WBITS; 55 | } 56 | } 57 | 58 | static RISTRETTO_NOINLINE void sc_montmul ( 59 | scalar_t *out, 60 | const scalar_t *a, 61 | const scalar_t *b 62 | ) { 63 | unsigned int i,j; 64 | ristretto_word_t accum[SCALAR_LIMBS+1] = {0}; 65 | ristretto_word_t hi_carry = 0; 66 | 67 | for (i=0; ilimb[i]; 69 | const ristretto_word_t *mier = b->limb; 70 | 71 | ristretto_dword_t chain = 0; 72 | for (j=0; j>= WBITS; 76 | } 77 | accum[j] = chain; 78 | 79 | mand = accum[0] * MONTGOMERY_FACTOR; 80 | chain = 0; 81 | mier = sc_p.limb; 82 | for (j=0; j>= WBITS; 86 | } 87 | chain += accum[j]; 88 | chain += hi_carry; 89 | accum[j-1] = chain; 90 | hi_carry = chain >> WBITS; 91 | } 92 | 93 | sc_subx(out, accum, &sc_p, &sc_p, hi_carry); 94 | } 95 | 96 | void ristretto255_scalar_mul ( 97 | scalar_t *out, 98 | const scalar_t *a, 99 | const scalar_t *b 100 | ) { 101 | sc_montmul(out,a,b); 102 | sc_montmul(out,out,&sc_r2); 103 | } 104 | 105 | /* PERF: could implement this */ 106 | static RISTRETTO_INLINE void sc_montsqr (scalar_t *out, const scalar_t *a) { 107 | sc_montmul(out,a,a); 108 | } 109 | 110 | ristretto_error_t ristretto255_scalar_invert ( 111 | scalar_t *out, 112 | const scalar_t *a 113 | ) { 114 | /* Fermat's little theorem, sliding window. 115 | * Sliding window is fine here because the modulus isn't secret. 116 | */ 117 | const int SCALAR_WINDOW_BITS = 3; 118 | scalar_t precmp[1<<3]; // Rewritten from SCALAR_WINDOW_BITS for windows compatibility 119 | const int LAST = (1< 0) sc_montmul(&precmp[LAST],&precmp[0],&precmp[0]); 124 | 125 | int i; 126 | for (i=1; i<=LAST; i++) { 127 | sc_montmul(&precmp[i],&precmp[i-1],&precmp[LAST]); 128 | } 129 | 130 | /* Sliding window */ 131 | unsigned residue = 0, trailing = 0, started = 0; 132 | for (i=SCALAR_BITS-1; i>=-SCALAR_WINDOW_BITS; i--) { 133 | 134 | if (started) sc_montsqr(out,out); 135 | 136 | ristretto_word_t w = (i>=0) ? sc_p.limb[i/WBITS] : 0; 137 | if (i >= 0 && i= 2); 139 | w-=2; 140 | } 141 | 142 | residue = (residue<<1) | ((w>>(i%WBITS))&1); 143 | if (residue>>SCALAR_WINDOW_BITS != 0) { 144 | assert(trailing == 0); 145 | trailing = residue; 146 | residue = 0; 147 | } 148 | 149 | if (trailing > 0 && (trailing & ((1<>(SCALAR_WINDOW_BITS+1)]); 152 | } else { 153 | ristretto255_scalar_copy(out,&precmp[trailing>>(SCALAR_WINDOW_BITS+1)]); 154 | started = 1; 155 | } 156 | trailing = 0; 157 | } 158 | trailing <<= 1; 159 | 160 | } 161 | assert(residue==0); 162 | assert(trailing==0); 163 | 164 | /* Demontgomerize */ 165 | sc_montmul(out,out,&ristretto255_scalar_one); 166 | ristretto_bzero(&precmp, sizeof(precmp)); 167 | return ristretto_succeed_if(~ristretto255_scalar_eq(out,&ristretto255_scalar_zero)); 168 | } 169 | 170 | void ristretto255_scalar_sub ( 171 | scalar_t *out, 172 | const scalar_t *a, 173 | const scalar_t *b 174 | ) { 175 | sc_subx(out, a->limb, b, &sc_p, 0); 176 | } 177 | 178 | void ristretto255_scalar_add ( 179 | scalar_t *out, 180 | const scalar_t *a, 181 | const scalar_t *b 182 | ) { 183 | ristretto_dword_t chain = 0; 184 | unsigned int i; 185 | for (i=0; ilimb[i]) + b->limb[i]; 187 | out->limb[i] = chain; 188 | chain >>= WBITS; 189 | } 190 | sc_subx(out, out->limb, &sc_p, &sc_p, chain); 191 | } 192 | 193 | void 194 | ristretto255_scalar_set_unsigned ( 195 | scalar_t *out, 196 | uint64_t w 197 | ) { 198 | memset(out,0,sizeof(scalar_t)); 199 | unsigned int i = 0; 200 | for (; ilimb[i] = w; 202 | #if RISTRETTO_WORD_BITS < 64 203 | w >>= 8*sizeof(ristretto_word_t); 204 | #endif 205 | } 206 | } 207 | 208 | ristretto_bool_t 209 | ristretto255_scalar_eq ( 210 | const scalar_t *a, 211 | const scalar_t *b 212 | ) { 213 | ristretto_word_t diff = 0; 214 | unsigned int i; 215 | for (i=0; ilimb[i] ^ b->limb[i]; 217 | } 218 | return mask_to_bool(word_is_zero(diff)); 219 | } 220 | 221 | static RISTRETTO_INLINE void scalar_decode_short ( 222 | scalar_t *s, 223 | const unsigned char *ser, 224 | unsigned int nbytes 225 | ) { 226 | unsigned int i,j,k=0; 227 | for (i=0; ilimb[i] = out; 233 | } 234 | } 235 | 236 | ristretto_error_t ristretto255_scalar_decode( 237 | scalar_t *s, 238 | const unsigned char ser[SCALAR_SER_BYTES] 239 | ) { 240 | unsigned int i; 241 | scalar_decode_short(s, ser, SCALAR_SER_BYTES); 242 | ristretto_dsword_t accum = 0; 243 | for (i=0; ilimb[i] - sc_p.limb[i]) >> WBITS; 245 | } 246 | /* Here accum == 0 or -1 */ 247 | 248 | ristretto255_scalar_mul(s,s,&ristretto255_scalar_one); /* ham-handed reduce */ 249 | 250 | return ristretto_succeed_if(~word_is_zero(accum)); 251 | } 252 | 253 | void ristretto255_scalar_destroy ( 254 | scalar_t *scalar 255 | ) { 256 | ristretto_bzero(scalar, sizeof(scalar_t)); 257 | } 258 | 259 | void ristretto255_scalar_decode_long( 260 | scalar_t *s, 261 | const unsigned char *ser, 262 | size_t ser_len 263 | ) { 264 | if (ser_len == 0) { 265 | ristretto255_scalar_copy(s, &ristretto255_scalar_zero); 266 | return; 267 | } 268 | 269 | size_t i; 270 | scalar_t t1, t2; 271 | 272 | i = ser_len - (ser_len%SCALAR_SER_BYTES); 273 | if (i==ser_len) i -= SCALAR_SER_BYTES; 274 | 275 | scalar_decode_short(&t1, &ser[i], ser_len-i); 276 | 277 | if (ser_len == sizeof(scalar_t)) { 278 | assert(i==0); 279 | /* ham-handed reduce */ 280 | ristretto255_scalar_mul(s,&t1,&ristretto255_scalar_one); 281 | ristretto255_scalar_destroy(&t1); 282 | return; 283 | } 284 | 285 | while (i) { 286 | i -= SCALAR_SER_BYTES; 287 | sc_montmul(&t1,&t1,&sc_r2); 288 | ignore_result( ristretto255_scalar_decode(&t2, ser+i) ); 289 | ristretto255_scalar_add(&t1, &t1, &t2); 290 | } 291 | 292 | ristretto255_scalar_copy(s, &t1); 293 | ristretto255_scalar_destroy(&t1); 294 | ristretto255_scalar_destroy(&t2); 295 | } 296 | 297 | void ristretto255_scalar_encode( 298 | unsigned char ser[SCALAR_SER_BYTES], 299 | const scalar_t *s 300 | ) { 301 | unsigned int i,j,k=0; 302 | for (i=0; ilimb[i] >> (8*j); 305 | } 306 | } 307 | } 308 | 309 | void ristretto255_scalar_cond_sel ( 310 | scalar_t *out, 311 | const scalar_t *a, 312 | const scalar_t *b, 313 | ristretto_bool_t pick_b 314 | ) { 315 | constant_time_select(out,a,b,sizeof(scalar_t),bool_to_mask(pick_b),sizeof(out->limb[0])); 316 | } 317 | 318 | void ristretto255_scalar_halve ( 319 | scalar_t *out, 320 | const scalar_t *a 321 | ) { 322 | ristretto_word_t mask = -(a->limb[0] & 1); 323 | ristretto_dword_t chain = 0; 324 | unsigned int i; 325 | for (i=0; ilimb[i]) + (sc_p.limb[i] & mask); 327 | out->limb[i] = chain; 328 | chain >>= RISTRETTO_WORD_BITS; 329 | } 330 | for (i=0; ilimb[i] = out->limb[i]>>1 | out->limb[i+1]<<(WBITS-1); 332 | } 333 | out->limb[i] = out->limb[i]>>1 | chain<<(WBITS-1); 334 | } 335 | 336 | -------------------------------------------------------------------------------- /src/word.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014-2018 Ristretto Developers, Cryptography Research, Inc. 2 | * Released under the MIT License. See LICENSE.txt for license information. 3 | */ 4 | 5 | #ifndef __WORD_H__ 6 | #define __WORD_H__ 7 | 8 | /* for posix_memalign */ 9 | #define _XOPEN_SOURCE 600 10 | #define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s */ 11 | #include 12 | #if defined(__sun) && defined(__SVR4) 13 | extern int posix_memalign(void **, size_t, size_t); 14 | #endif 15 | 16 | // MSVC has no posix_memalign 17 | #if defined(_MSC_VER) || defined(__MINGW32__) 18 | #define posix_memalign(p, a, s) (((*(p)) = _aligned_malloc((s), (a))), *(p) ?0 :errno) 19 | #endif 20 | 21 | #include 22 | #include 23 | #include "arch_intrinsics.h" 24 | 25 | #include 26 | 27 | #ifndef _BSD_SOURCE 28 | #define _BSD_SOURCE 1 29 | #endif 30 | 31 | #ifndef _DEFAULT_SOURCE 32 | #define _DEFAULT_SOURCE 1 33 | #endif 34 | 35 | #include "portable_endian.h" 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #if defined(__ARM_NEON__) 42 | #include 43 | #elif defined(__SSE2__) 44 | #if !defined(__GNUC__) || __clang__ || __GNUC__ >= 5 || (__GNUC__==4 && __GNUC_MINOR__ >= 4) 45 | #include 46 | #else 47 | #include 48 | #endif 49 | #endif 50 | 51 | #if (ARCH_WORD_BITS == 64) 52 | typedef uint64_t word_t, mask_t; 53 | typedef __uint128_t dword_t; 54 | typedef int32_t hsword_t; 55 | typedef int64_t sword_t; 56 | typedef __int128_t dsword_t; 57 | #elif (ARCH_WORD_BITS == 32) 58 | typedef uint32_t word_t, mask_t; 59 | typedef uint64_t dword_t; 60 | typedef int16_t hsword_t; 61 | typedef int32_t sword_t; 62 | typedef int64_t dsword_t; 63 | #else 64 | #error "libristretto255 only supports 32-bit and 64-bit architectures." 65 | #endif 66 | 67 | /* Scalar limbs are keyed off of the API word size instead of the arch word size. */ 68 | #if RISTRETTO_WORD_BITS == 64 69 | #define SC_LIMB(x) (x##ull) 70 | #elif RISTRETTO_WORD_BITS == 32 71 | #define SC_LIMB(x) ((uint32_t)x##ull),(x##ull>>32) 72 | #else 73 | #error "libristretto255 only supports 32-bit and 64-bit architectures." 74 | #endif 75 | 76 | #ifdef __ARM_NEON__ 77 | typedef uint32x4_t vecmask_t; 78 | #elif __clang__ 79 | typedef uint64_t uint64x2_t __attribute__((ext_vector_type(2))); 80 | typedef int64_t int64x2_t __attribute__((ext_vector_type(2))); 81 | typedef uint64_t uint64x4_t __attribute__((ext_vector_type(4))); 82 | typedef int64_t int64x4_t __attribute__((ext_vector_type(4))); 83 | typedef uint32_t uint32x4_t __attribute__((ext_vector_type(4))); 84 | typedef int32_t int32x4_t __attribute__((ext_vector_type(4))); 85 | typedef uint32_t uint32x2_t __attribute__((ext_vector_type(2))); 86 | typedef int32_t int32x2_t __attribute__((ext_vector_type(2))); 87 | typedef uint32_t uint32x8_t __attribute__((ext_vector_type(8))); 88 | typedef int32_t int32x8_t __attribute__((ext_vector_type(8))); 89 | typedef word_t vecmask_t __attribute__((ext_vector_type(4))); 90 | #else /* GCC, hopefully? */ 91 | typedef uint64_t uint64x2_t __attribute__((vector_size(16))); 92 | typedef int64_t int64x2_t __attribute__((vector_size(16))); 93 | typedef uint64_t uint64x4_t __attribute__((vector_size(32))); 94 | typedef int64_t int64x4_t __attribute__((vector_size(32))); 95 | typedef uint32_t uint32x4_t __attribute__((vector_size(16))); 96 | typedef int32_t int32x4_t __attribute__((vector_size(16))); 97 | typedef uint32_t uint32x2_t __attribute__((vector_size(8))); 98 | typedef int32_t int32x2_t __attribute__((vector_size(8))); 99 | typedef uint32_t uint32x8_t __attribute__((vector_size(32))); 100 | typedef int32_t int32x8_t __attribute__((vector_size(32))); 101 | typedef word_t vecmask_t __attribute__((vector_size(32))); 102 | #endif 103 | 104 | #if __AVX2__ 105 | #define VECTOR_ALIGNED __attribute__((aligned(32))) 106 | typedef uint32x8_t big_register_t; 107 | typedef uint64x4_t uint64xn_t; 108 | typedef uint32x8_t uint32xn_t; 109 | 110 | static RISTRETTO_INLINE big_register_t 111 | br_set_to_mask(mask_t x) { 112 | uint32_t y = (uint32_t)x; 113 | big_register_t ret = {y,y,y,y,y,y,y,y}; 114 | return ret; 115 | } 116 | #elif __SSE2__ 117 | #define VECTOR_ALIGNED __attribute__((aligned(16))) 118 | typedef uint32x4_t big_register_t; 119 | typedef uint64x2_t uint64xn_t; 120 | typedef uint32x4_t uint32xn_t; 121 | 122 | static RISTRETTO_INLINE big_register_t 123 | br_set_to_mask(mask_t x) { 124 | uint32_t y = x; 125 | big_register_t ret = {y,y,y,y}; 126 | return ret; 127 | } 128 | #elif __ARM_NEON__ 129 | #define VECTOR_ALIGNED __attribute__((aligned(16))) 130 | typedef uint32x4_t big_register_t; 131 | typedef uint64x2_t uint64xn_t; 132 | typedef uint32x4_t uint32xn_t; 133 | 134 | static RISTRETTO_INLINE big_register_t 135 | br_set_to_mask(mask_t x) { 136 | return vdupq_n_u32(x); 137 | } 138 | #elif _WIN64 || __amd64__ || __X86_64__ || __aarch64__ 139 | #define VECTOR_ALIGNED __attribute__((aligned(8))) 140 | typedef uint64_t big_register_t, uint64xn_t; 141 | 142 | typedef uint32_t uint32xn_t; 143 | static RISTRETTO_INLINE big_register_t 144 | br_set_to_mask(mask_t x) { 145 | return (big_register_t)x; 146 | } 147 | #else 148 | #define VECTOR_ALIGNED __attribute__((aligned(4))) 149 | typedef uint64_t uint64xn_t; 150 | typedef uint32_t uint32xn_t; 151 | typedef uint32_t big_register_t; 152 | 153 | static RISTRETTO_INLINE big_register_t 154 | br_set_to_mask(mask_t x) { 155 | return (big_register_t)x; 156 | } 157 | #endif 158 | 159 | typedef struct { 160 | uint64xn_t unaligned; 161 | } __attribute__((packed)) unaligned_uint64xn_t; 162 | 163 | typedef struct { 164 | uint32xn_t unaligned; 165 | } __attribute__((packed)) unaligned_uint32xn_t; 166 | 167 | #if __AVX2__ 168 | static RISTRETTO_INLINE big_register_t 169 | br_is_zero(big_register_t x) { 170 | return (big_register_t)(x == br_set_to_mask(0)); 171 | } 172 | #elif __SSE2__ 173 | static RISTRETTO_INLINE big_register_t 174 | br_is_zero(big_register_t x) { 175 | return (big_register_t)_mm_cmpeq_epi32((__m128i)x, _mm_setzero_si128()); 176 | //return (big_register_t)(x == br_set_to_mask(0)); 177 | } 178 | #elif __ARM_NEON__ 179 | static RISTRETTO_INLINE big_register_t 180 | br_is_zero(big_register_t x) { 181 | return vceqq_u32(x,x^x); 182 | } 183 | #else 184 | #define br_is_zero word_is_zero 185 | #endif 186 | 187 | /** 188 | * Really call memset, in a way that prevents the compiler from optimizing it out. 189 | * @param p The object to zeroize. 190 | * @param c The char to set it to (probably zero). 191 | * @param s The size of the object. 192 | */ 193 | #if defined(__DARWIN_C_LEVEL) || defined(__STDC_LIB_EXT1__) 194 | #define HAS_MEMSET_S 195 | #endif 196 | 197 | #if !defined(__STDC_WANT_LIB_EXT1__) || __STDC_WANT_LIB_EXT1__ != 1 198 | #define NEED_MEMSET_S_EXTERN 199 | #endif 200 | 201 | #ifdef HAS_MEMSET_S 202 | #ifdef NEED_MEMSET_S_EXTERN 203 | extern int memset_s(void *, size_t, int, size_t); 204 | #endif 205 | static RISTRETTO_INLINE void 206 | really_memset(void *p, char c, size_t s) { 207 | memset_s(p, s, c, s); 208 | } 209 | #else 210 | /* PERF: use words? */ 211 | static RISTRETTO_INLINE void 212 | really_memset(void *p, char c, size_t s) { 213 | volatile char *pv = (volatile char *)p; 214 | size_t i; 215 | for (i=0; i 305 246 | #define UNROLL _Pragma("clang loop unroll(full)") 247 | #endif 248 | #endif 249 | 250 | #ifndef UNROLL 251 | #define UNROLL 252 | #endif 253 | 254 | /* The plan on booleans: 255 | * 256 | * The external interface uses ristretto_bool_t, but this might be a different 257 | * size than our particular arch's word_t (and thus mask_t). Also, the caller 258 | * isn't guaranteed to pass it as nonzero. So bool_to_mask converts word sizes 259 | * and checks nonzero. 260 | * 261 | * On the flip side, mask_t is always -1 or 0, but it might be a different size 262 | * than ristretto_bool_t. 263 | */ 264 | static RISTRETTO_INLINE ristretto_bool_t mask_to_bool (mask_t m) { 265 | return (ristretto_sword_t)(sword_t)m; 266 | } 267 | 268 | static RISTRETTO_INLINE mask_t bool_to_mask (ristretto_bool_t m) { 269 | /* On most arches this will be optimized to a simple cast. */ 270 | mask_t ret = 0; 271 | unsigned int limit = sizeof(ristretto_bool_t)/sizeof(mask_t); 272 | if (limit < 1) limit = 1; 273 | for (unsigned int i=0; i> (i*8*sizeof(word_t))); 275 | } 276 | return ret; 277 | } 278 | 279 | static RISTRETTO_INLINE void ignore_result ( ristretto_bool_t boo ) { 280 | (void)boo; 281 | } 282 | 283 | #endif /* __WORD_H__ */ 284 | -------------------------------------------------------------------------------- /tests/Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "arrayref" 3 | version = "0.3.4" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | 6 | [[package]] 7 | name = "bitflags" 8 | version = "1.0.3" 9 | source = "registry+https://github.com/rust-lang/crates.io-index" 10 | 11 | [[package]] 12 | name = "block-buffer" 13 | version = "0.3.3" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | dependencies = [ 16 | "arrayref 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", 17 | "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 18 | ] 19 | 20 | [[package]] 21 | name = "byte-tools" 22 | version = "0.2.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | 25 | [[package]] 26 | name = "byteorder" 27 | version = "1.2.4" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | 30 | [[package]] 31 | name = "cc" 32 | version = "1.0.18" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | 35 | [[package]] 36 | name = "clear_on_drop" 37 | version = "0.2.3" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | dependencies = [ 40 | "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", 41 | ] 42 | 43 | [[package]] 44 | name = "cloudabi" 45 | version = "0.0.3" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | dependencies = [ 48 | "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 49 | ] 50 | 51 | [[package]] 52 | name = "curve25519-dalek" 53 | version = "0.19.0" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | dependencies = [ 56 | "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", 57 | "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 58 | "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", 59 | "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 60 | "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", 61 | "subtle 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 62 | ] 63 | 64 | [[package]] 65 | name = "digest" 66 | version = "0.7.5" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | dependencies = [ 69 | "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 70 | ] 71 | 72 | [[package]] 73 | name = "fake-simd" 74 | version = "0.1.2" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | 77 | [[package]] 78 | name = "fuchsia-zircon" 79 | version = "0.3.3" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | dependencies = [ 82 | "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 83 | "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 84 | ] 85 | 86 | [[package]] 87 | name = "fuchsia-zircon-sys" 88 | version = "0.3.3" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | 91 | [[package]] 92 | name = "generic-array" 93 | version = "0.9.0" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | dependencies = [ 96 | "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 97 | ] 98 | 99 | [[package]] 100 | name = "hex" 101 | version = "0.3.2" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | 104 | [[package]] 105 | name = "libc" 106 | version = "0.2.43" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | 109 | [[package]] 110 | name = "libristretto255-sys" 111 | version = "0.0.0" 112 | 113 | [[package]] 114 | name = "libristretto255-tests" 115 | version = "0.0.0" 116 | dependencies = [ 117 | "curve25519-dalek 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", 118 | "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 119 | "libristretto255-sys 0.0.0", 120 | "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", 121 | "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 122 | ] 123 | 124 | [[package]] 125 | name = "rand" 126 | version = "0.5.5" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | dependencies = [ 129 | "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 130 | "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 131 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 132 | "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 133 | "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 134 | ] 135 | 136 | [[package]] 137 | name = "rand_core" 138 | version = "0.2.1" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | 141 | [[package]] 142 | name = "sha2" 143 | version = "0.7.1" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | dependencies = [ 146 | "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 147 | "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 148 | "digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", 149 | "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 150 | ] 151 | 152 | [[package]] 153 | name = "subtle" 154 | version = "0.7.0" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | 157 | [[package]] 158 | name = "typenum" 159 | version = "1.10.0" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | 162 | [[package]] 163 | name = "winapi" 164 | version = "0.3.5" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | dependencies = [ 167 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 168 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 169 | ] 170 | 171 | [[package]] 172 | name = "winapi-i686-pc-windows-gnu" 173 | version = "0.4.0" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | 176 | [[package]] 177 | name = "winapi-x86_64-pc-windows-gnu" 178 | version = "0.4.0" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | 181 | [metadata] 182 | "checksum arrayref 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0fd1479b7c29641adbd35ff3b5c293922d696a92f25c8c975da3e0acbc87258f" 183 | "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" 184 | "checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" 185 | "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" 186 | "checksum byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8389c509ec62b9fe8eca58c502a0acaf017737355615243496cde4994f8fa4f9" 187 | "checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275" 188 | "checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" 189 | "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 190 | "checksum curve25519-dalek 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc999958669630eca818b3d1fe5ed748573e40d2d1800ddd0e67d1c71d63205" 191 | "checksum digest 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5b29c278aa8fd30796bd977169e8004b4aa88cdcd2f32a6eb22bc2d5d38df94a" 192 | "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" 193 | "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 194 | "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 195 | "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" 196 | "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" 197 | "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" 198 | "checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" 199 | "checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" 200 | "checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" 201 | "checksum subtle 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8daf2e8fdde6bc5ae2d5f39716ec1f8b2c0435cda89211e3334071b5208e8515" 202 | "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" 203 | "checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" 204 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 205 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 206 | -------------------------------------------------------------------------------- /tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libristretto255-tests" 3 | description = "Tests for libristretto255" 4 | version = "0.0.0" 5 | 6 | [workspace] 7 | members = ["libristretto255-sys"] 8 | 9 | [dependencies] 10 | curve25519-dalek = "0.19" 11 | hex = "*" 12 | libristretto255-sys = { path = "libristretto255-sys" } 13 | rand = "0.5" 14 | sha2 = "*" 15 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # libristretto255-tests 2 | 3 | Rust-based test suite for libristretto255. 4 | 5 | Parts adapted from curve25519-dalek. 6 | -------------------------------------------------------------------------------- /tests/libristretto255-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libristretto255-sys" 3 | version = "0.0.0" 4 | -------------------------------------------------------------------------------- /tests/libristretto255-sys/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rustc-link-search=../build/lib"); 3 | println!("cargo:rustc-link-lib=static=ristretto255"); 4 | } 5 | -------------------------------------------------------------------------------- /tests/libristretto255-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Rust binding to libristretto255 intended for testing 2 | //! 3 | //! Automatically generated by rust-bindgen, however bindgen doesn't presently 4 | //! support `#[repr(align)]`, so the resulting bindings have been checked-in. 5 | 6 | #![crate_name = "libristretto255_sys"] 7 | #![crate_type = "rlib"] 8 | #![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)] 9 | 10 | #[cfg(not(target_pointer_width = "64"))] 11 | compile_error!("This binding assumes a 64-bit architecture"); 12 | 13 | pub const RISTRETTO_WORD_BITS: u32 = 64; 14 | pub const RISTRETTO255_SCALAR_LIMBS: u32 = 4; 15 | pub const RISTRETTO255_SCALAR_BITS: u32 = 253; 16 | pub const RISTRETTO255_SER_BYTES: u32 = 32; 17 | pub const RISTRETTO255_HASH_BYTES: u32 = 32; 18 | pub const RISTRETTO255_SCALAR_BYTES: u32 = 32; 19 | pub const RISTRETTO255_INVERT_ELLIGATOR_WHICH_BITS: u32 = 5; 20 | pub const RISTRETTO255_REMOVED_COFACTOR: u32 = 8; 21 | 22 | pub type ristretto_word_t = u64; 23 | pub type ristretto_sword_t = i64; 24 | pub type ristretto_bool_t = u64; 25 | pub type ristretto_dword_t = u128; 26 | pub type ristretto_dsword_t = i128; 27 | 28 | extern "C" { 29 | pub static mut RISTRETTO_TRUE: ristretto_bool_t; 30 | } 31 | 32 | extern "C" { 33 | pub static mut RISTRETTO_FALSE: ristretto_bool_t; 34 | } 35 | 36 | /// < The operation succeeded. 37 | pub const RISTRETTO_SUCCESS: ristretto_error_t = -1; 38 | 39 | /// < The operation failed. 40 | pub const RISTRETTO_FAILURE: ristretto_error_t = 0; 41 | /// Another boolean type used to indicate success or failure. 42 | 43 | pub type ristretto_error_t = i32; 44 | 45 | extern "C" { 46 | /// Overwrite data with zeros. Uses memset_s if available. 47 | pub fn ristretto_bzero(data: *mut ::std::os::raw::c_void, size: usize); 48 | } 49 | 50 | #[repr(C, align(32))] 51 | #[derive(Debug, Copy, Clone)] 52 | pub struct gf_25519_t { 53 | pub limb: [ristretto_word_t; 5usize], 54 | pub __bindgen_padding_0: [u64; 3usize], 55 | } 56 | 57 | #[test] 58 | fn bindgen_test_layout_gf_25519_t() { 59 | assert_eq!( 60 | ::std::mem::size_of::(), 61 | 64usize, 62 | concat!("Size of: ", stringify!(gf_25519_t)) 63 | ); 64 | assert_eq!( 65 | unsafe { &(*(::std::ptr::null::())).limb as *const _ as usize }, 66 | 0usize, 67 | concat!( 68 | "Offset of field: ", 69 | stringify!(gf_25519_t), 70 | "::", 71 | stringify!(limb) 72 | ) 73 | ); 74 | } 75 | 76 | /// Representation of a point on the elliptic curve. 77 | #[repr(C)] 78 | #[derive(Debug, Copy, Clone)] 79 | pub struct ristretto255_point_t { 80 | /// @cond internal 81 | pub x: gf_25519_t, 82 | /// @cond internal 83 | pub y: gf_25519_t, 84 | /// @cond internal 85 | pub z: gf_25519_t, 86 | /// @cond internal 87 | pub t: gf_25519_t, 88 | } 89 | 90 | #[test] 91 | fn bindgen_test_layout_ristretto255_point_t() { 92 | assert_eq!( 93 | ::std::mem::size_of::(), 94 | 256usize, 95 | concat!("Size of: ", stringify!(ristretto255_point_t)) 96 | ); 97 | assert_eq!( 98 | unsafe { &(*(::std::ptr::null::())).x as *const _ as usize }, 99 | 0usize, 100 | concat!( 101 | "Offset of field: ", 102 | stringify!(ristretto255_point_t), 103 | "::", 104 | stringify!(x) 105 | ) 106 | ); 107 | assert_eq!( 108 | unsafe { &(*(::std::ptr::null::())).y as *const _ as usize }, 109 | 64usize, 110 | concat!( 111 | "Offset of field: ", 112 | stringify!(ristretto255_point_t), 113 | "::", 114 | stringify!(y) 115 | ) 116 | ); 117 | assert_eq!( 118 | unsafe { &(*(::std::ptr::null::())).z as *const _ as usize }, 119 | 128usize, 120 | concat!( 121 | "Offset of field: ", 122 | stringify!(ristretto255_point_t), 123 | "::", 124 | stringify!(z) 125 | ) 126 | ); 127 | assert_eq!( 128 | unsafe { &(*(::std::ptr::null::())).t as *const _ as usize }, 129 | 192usize, 130 | concat!( 131 | "Offset of field: ", 132 | stringify!(ristretto255_point_t), 133 | "::", 134 | stringify!(t) 135 | ) 136 | ); 137 | } 138 | 139 | /// Precomputed table based on a point. Can be trivial implementation. 140 | #[repr(C)] 141 | #[derive(Debug, Copy, Clone)] 142 | pub struct ristretto255_precomputed_s { 143 | _unused: [u8; 0], 144 | } 145 | extern "C" { 146 | pub static mut ristretto255_sizeof_precomputed_s: usize; 147 | pub static mut ristretto255_alignof_precomputed_s: usize; 148 | } 149 | 150 | /// Representation of an element of the scalar field. 151 | #[repr(C)] 152 | #[derive(Debug, Copy, Clone)] 153 | pub struct ristretto255_scalar_t { 154 | /// @cond internal 155 | pub limb: [ristretto_word_t; 4usize], 156 | } 157 | 158 | #[test] 159 | fn bindgen_test_layout_ristretto255_scalar_t() { 160 | assert_eq!( 161 | ::std::mem::size_of::(), 162 | 32usize, 163 | concat!("Size of: ", stringify!(ristretto255_scalar_t)) 164 | ); 165 | assert_eq!( 166 | ::std::mem::align_of::(), 167 | 8usize, 168 | concat!("Alignment of ", stringify!(ristretto255_scalar_t)) 169 | ); 170 | assert_eq!( 171 | unsafe { &(*(::std::ptr::null::())).limb as *const _ as usize }, 172 | 0usize, 173 | concat!( 174 | "Offset of field: ", 175 | stringify!(ristretto255_scalar_t), 176 | "::", 177 | stringify!(limb) 178 | ) 179 | ); 180 | } 181 | 182 | extern "C" { 183 | pub static mut ristretto255_scalar_one: ristretto255_scalar_t; 184 | pub static mut ristretto255_scalar_zero: ristretto255_scalar_t; 185 | pub static mut ristretto255_point_identity: ristretto255_point_t; 186 | pub static mut ristretto255_point_base: ristretto255_point_t; 187 | pub static mut ristretto255_precomputed_base: *const ristretto255_precomputed_s; 188 | 189 | /// @brief Read a scalar from wire format or from bytes. 190 | /// 191 | /// @param [in] ser Serialized form of a scalar. 192 | /// @param [out] out Deserialized form. 193 | /// 194 | /// @retval RISTRETTO_SUCCESS The scalar was correctly encoded. 195 | /// @retval RISTRETTO_FAILURE The scalar was greater than the modulus, 196 | /// and has been reduced modulo that modulus. 197 | pub fn ristretto255_scalar_decode( 198 | out: *mut ristretto255_scalar_t, 199 | ser: *const ::std::os::raw::c_uchar, 200 | ) -> ristretto_error_t; 201 | 202 | /// @brief Read a scalar from wire format or from bytes. Reduces mod 203 | /// scalar prime. 204 | /// 205 | /// @param [in] ser Serialized form of a scalar. 206 | /// @param [in] ser_len Length of serialized form. 207 | /// @param [out] out Deserialized form. 208 | pub fn ristretto255_scalar_decode_long( 209 | out: *mut ristretto255_scalar_t, 210 | ser: *const ::std::os::raw::c_uchar, 211 | ser_len: usize, 212 | ); 213 | 214 | /// @brief Serialize a scalar to wire format. 215 | /// 216 | /// @param [out] ser Serialized form of a scalar. 217 | /// @param [in] s Deserialized scalar. 218 | pub fn ristretto255_scalar_encode( 219 | ser: *mut ::std::os::raw::c_uchar, 220 | s: *const ristretto255_scalar_t, 221 | ); 222 | 223 | /// @brief Add two scalars. The scalars may use the same memory. 224 | /// @param [in] a One scalar. 225 | /// @param [in] b Another scalar. 226 | /// @param [out] out a+b. 227 | pub fn ristretto255_scalar_add( 228 | out: *mut ristretto255_scalar_t, 229 | a: *const ristretto255_scalar_t, 230 | b: *const ristretto255_scalar_t, 231 | ); 232 | 233 | /// @brief Compare two scalars. 234 | /// @param [in] a One scalar. 235 | /// @param [in] b Another scalar. 236 | /// @retval RISTRETTO_TRUE The scalars are equal. 237 | /// @retval RISTRETTO_FALSE The scalars are not equal. 238 | pub fn ristretto255_scalar_eq( 239 | a: *const ristretto255_scalar_t, 240 | b: *const ristretto255_scalar_t, 241 | ) -> ristretto_bool_t; 242 | 243 | /// @brief Subtract two scalars. The scalars may use the same memory. 244 | /// @param [in] a One scalar. 245 | /// @param [in] b Another scalar. 246 | /// @param [out] out a-b. 247 | pub fn ristretto255_scalar_sub( 248 | out: *mut ristretto255_scalar_t, 249 | a: *const ristretto255_scalar_t, 250 | b: *const ristretto255_scalar_t, 251 | ); 252 | 253 | /// @brief Multiply two scalars. The scalars may use the same memory. 254 | /// @param [in] a One scalar. 255 | /// @param [in] b Another scalar. 256 | /// @param [out] out a*b. 257 | pub fn ristretto255_scalar_mul( 258 | out: *mut ristretto255_scalar_t, 259 | a: *const ristretto255_scalar_t, 260 | b: *const ristretto255_scalar_t, 261 | ); 262 | 263 | /// @brief Halve a scalar. The scalars may use the same memory. 264 | /// @param [in] a A scalar. 265 | /// @param [out] out a/2. 266 | pub fn ristretto255_scalar_halve( 267 | out: *mut ristretto255_scalar_t, 268 | a: *const ristretto255_scalar_t, 269 | ); 270 | 271 | /// @brief Invert a scalar. When passed zero, return 0. The input and output may alias. 272 | /// @param [in] a A scalar. 273 | /// @param [out] out 1/a. 274 | /// @return RISTRETTO_SUCCESS The input is nonzero. 275 | pub fn ristretto255_scalar_invert( 276 | out: *mut ristretto255_scalar_t, 277 | a: *const ristretto255_scalar_t, 278 | ) -> ristretto_error_t; 279 | 280 | /// @brief Set a scalar to an unsigned 64-bit integer. 281 | /// @param [in] a An integer. 282 | /// @param [out] out Will become equal to a. 283 | pub fn ristretto255_scalar_set_unsigned(out: *mut ristretto255_scalar_t, a: u64); 284 | 285 | /// @brief Encode a point as a sequence of bytes. 286 | /// 287 | /// @param [out] ser The byte representation of the point. 288 | /// @param [in] pt The point to encode. 289 | pub fn ristretto255_point_encode(ser: *mut u8, pt: *const ristretto255_point_t); 290 | 291 | /// @brief Decode a point from a sequence of bytes. 292 | /// 293 | /// Every point has a unique encoding, so not every 294 | /// sequence of bytes is a valid encoding. If an invalid 295 | /// encoding is given, the output is undefined. 296 | /// 297 | /// @param [out] pt The decoded point. 298 | /// @param [in] ser The serialized version of the point. 299 | /// @param [in] allow_identity RISTRETTO_TRUE if the identity is a legal input. 300 | /// @retval RISTRETTO_SUCCESS The decoding succeeded. 301 | /// @retval RISTRETTO_FAILURE The decoding didn't succeed, because 302 | /// ser does not represent a point. 303 | pub fn ristretto255_point_decode( 304 | pt: *mut ristretto255_point_t, 305 | ser: *const u8, 306 | allow_identity: ristretto_bool_t, 307 | ) -> ristretto_error_t; 308 | 309 | /// @brief Test whether two points are equal. If yes, return 310 | /// RISTRETTO_TRUE, else return RISTRETTO_FALSE. 311 | /// 312 | /// @param [in] a A point. 313 | /// @param [in] b Another point. 314 | /// @retval RISTRETTO_TRUE The points are equal. 315 | /// @retval RISTRETTO_FALSE The points are not equal. 316 | pub fn ristretto255_point_eq( 317 | a: *const ristretto255_point_t, 318 | b: *const ristretto255_point_t, 319 | ) -> ristretto_bool_t; 320 | 321 | /// @brief Add two points to produce a third point. The 322 | /// input points and output point can be pointers to the same 323 | /// memory. 324 | /// 325 | /// @param [out] sum The sum a+b. 326 | /// @param [in] a An addend. 327 | /// @param [in] b An addend. 328 | pub fn ristretto255_point_add( 329 | sum: *mut ristretto255_point_t, 330 | a: *const ristretto255_point_t, 331 | b: *const ristretto255_point_t, 332 | ); 333 | 334 | /// @brief Double a point. Equivalent to 335 | /// ristretto255_point_add(two_a,a,a), but potentially faster. 336 | /// 337 | /// @param [out] two_a The sum a+a. 338 | /// @param [in] a A point. 339 | pub fn ristretto255_point_double( 340 | two_a: *mut ristretto255_point_t, 341 | a: *const ristretto255_point_t, 342 | ); 343 | 344 | /// @brief Subtract two points to produce a third point. The 345 | /// input points and output point can be pointers to the same 346 | /// memory. 347 | /// 348 | /// @param [out] diff The difference a-b. 349 | /// @param [in] a The minuend. 350 | /// @param [in] b The subtrahend. 351 | pub fn ristretto255_point_sub( 352 | diff: *mut ristretto255_point_t, 353 | a: *const ristretto255_point_t, 354 | b: *const ristretto255_point_t, 355 | ); 356 | 357 | /// @brief Negate a point to produce another point. The input 358 | /// and output points can use the same memory. 359 | /// 360 | /// @param [out] nega The negated input point 361 | /// @param [in] a The input point. 362 | pub fn ristretto255_point_negate( 363 | nega: *mut ristretto255_point_t, 364 | a: *const ristretto255_point_t, 365 | ); 366 | 367 | /// @brief Multiply a base point by a scalar: scaled = scalar*base. 368 | /// 369 | /// @param [out] scaled The scaled point base*scalar 370 | /// @param [in] base The point to be scaled. 371 | /// @param [in] scalar The scalar to multiply by. 372 | pub fn ristretto255_point_scalarmul( 373 | scaled: *mut ristretto255_point_t, 374 | base: *const ristretto255_point_t, 375 | scalar: *const ristretto255_scalar_t, 376 | ); 377 | 378 | /// @brief Multiply a base point by a scalar: scaled = scalar*base. 379 | /// This function operates directly on serialized forms. 380 | /// 381 | /// @warning This function is experimental. It may not be supported 382 | /// long-term. 383 | /// 384 | /// @param [out] scaled The scaled point base*scalar 385 | /// @param [in] base The point to be scaled. 386 | /// @param [in] scalar The scalar to multiply by. 387 | /// @param [in] allow_identity Allow the input to be the identity. 388 | /// @param [in] short_circuit Allow a fast return if the input is illegal. 389 | /// 390 | /// @retval RISTRETTO_SUCCESS The scalarmul succeeded. 391 | /// @retval RISTRETTO_FAILURE The scalarmul didn't succeed, because 392 | /// base does not represent a point. 393 | pub fn ristretto255_direct_scalarmul( 394 | scaled: *mut u8, 395 | base: *const u8, 396 | scalar: *const ristretto255_scalar_t, 397 | allow_identity: ristretto_bool_t, 398 | short_circuit: ristretto_bool_t, 399 | ) -> ristretto_error_t; 400 | 401 | /// @brief Precompute a table for fast scalar multiplication. 402 | /// Some implementations do not include precomputed points; for 403 | /// those implementations, this implementation simply copies the 404 | /// point. 405 | /// 406 | /// @param [out] a A precomputed table of multiples of the point. 407 | /// @param [in] b Any point. 408 | pub fn ristretto255_precompute( 409 | a: *mut ristretto255_precomputed_s, 410 | b: *const ristretto255_point_t, 411 | ); 412 | 413 | /// @brief Multiply a precomputed base point by a scalar: 414 | /// scaled = scalar*base. 415 | /// Some implementations do not include precomputed points; for 416 | /// those implementations, this function is the same as 417 | /// ristretto255_point_scalarmul 418 | /// 419 | /// @param [out] scaled The scaled point base*scalar 420 | /// @param [in] base The point to be scaled. 421 | /// @param [in] scalar The scalar to multiply by. 422 | pub fn ristretto255_precomputed_scalarmul( 423 | scaled: *mut ristretto255_point_t, 424 | base: *const ristretto255_precomputed_s, 425 | scalar: *const ristretto255_scalar_t, 426 | ); 427 | 428 | /// @brief Multiply two base points by two scalars: 429 | /// scaled = scalar1*base1 + scalar2*base2. 430 | /// 431 | /// Equivalent to two calls to ristretto255_point_scalarmul, but may be 432 | /// faster. 433 | /// 434 | /// @param [out] combo The linear combination scalar1*base1 + scalar2*base2. 435 | /// @param [in] base1 A first point to be scaled. 436 | /// @param [in] scalar1 A first scalar to multiply by. 437 | /// @param [in] base2 A second point to be scaled. 438 | /// @param [in] scalar2 A second scalar to multiply by. 439 | pub fn ristretto255_point_double_scalarmul( 440 | combo: *mut ristretto255_point_t, 441 | base1: *const ristretto255_point_t, 442 | scalar1: *const ristretto255_scalar_t, 443 | base2: *const ristretto255_point_t, 444 | scalar2: *const ristretto255_scalar_t, 445 | ); 446 | 447 | /// Multiply one base point by two scalars: 448 | /// 449 | /// a1 = scalar1 * base 450 | /// a2 = scalar2 * base 451 | /// 452 | /// Equivalent to two calls to ristretto255_point_scalarmul, but may be 453 | /// faster. 454 | /// 455 | /// @param [out] a1 The first multiple. It may be the same as the input point. 456 | /// @param [out] a2 The second multiple. It may be the same as the input point. 457 | /// @param [in] base1 A point to be scaled. 458 | /// @param [in] scalar1 A first scalar to multiply by. 459 | /// @param [in] scalar2 A second scalar to multiply by. 460 | pub fn ristretto255_point_dual_scalarmul( 461 | a1: *mut ristretto255_point_t, 462 | a2: *mut ristretto255_point_t, 463 | base1: *const ristretto255_point_t, 464 | scalar1: *const ristretto255_scalar_t, 465 | scalar2: *const ristretto255_scalar_t, 466 | ); 467 | 468 | /// @brief Multiply two base points by two scalars: 469 | /// scaled = scalar1*ristretto255_point_base + scalar2*base2. 470 | /// 471 | /// Otherwise equivalent to ristretto255_point_double_scalarmul, but may be 472 | /// faster at the expense of being variable time. 473 | /// 474 | /// @param [out] combo The linear combination scalar1*base + scalar2*base2. 475 | /// @param [in] scalar1 A first scalar to multiply by. 476 | /// @param [in] base2 A second point to be scaled. 477 | /// @param [in] scalar2 A second scalar to multiply by. 478 | /// 479 | /// @warning: This function takes variable time, and may leak the scalars 480 | /// used. It is designed for signature verification. 481 | pub fn ristretto255_base_double_scalarmul_non_secret( 482 | combo: *mut ristretto255_point_t, 483 | scalar1: *const ristretto255_scalar_t, 484 | base2: *const ristretto255_point_t, 485 | scalar2: *const ristretto255_scalar_t, 486 | ); 487 | 488 | /// @brief Constant-time decision between two points. If pick_b 489 | /// is zero, out = a; else out = b. 490 | /// 491 | /// @param [out] out The output. It may be the same as either input. 492 | /// @param [in] a Any point. 493 | /// @param [in] b Any point. 494 | /// @param [in] pick_b If nonzero, choose point b. 495 | pub fn ristretto255_point_cond_sel( 496 | out: *mut ristretto255_point_t, 497 | a: *const ristretto255_point_t, 498 | b: *const ristretto255_point_t, 499 | pick_b: ristretto_word_t, 500 | ); 501 | 502 | /// @brief Constant-time decision between two scalars. If pick_b 503 | /// is zero, out = a; else out = b. 504 | /// 505 | /// @param [out] out The output. It may be the same as either input. 506 | /// @param [in] a Any scalar. 507 | /// @param [in] b Any scalar. 508 | /// @param [in] pick_b If nonzero, choose scalar b. 509 | pub fn ristretto255_scalar_cond_sel( 510 | out: *mut ristretto255_scalar_t, 511 | a: *const ristretto255_scalar_t, 512 | b: *const ristretto255_scalar_t, 513 | pick_b: ristretto_word_t, 514 | ); 515 | 516 | /// @brief Test that a point is valid, for debugging purposes. 517 | /// 518 | /// @param [in] to_test The point to test. 519 | /// @retval RISTRETTO_TRUE The point is valid. 520 | /// @retval RISTRETTO_FALSE The point is invalid. 521 | pub fn ristretto255_point_valid(to_test: *const ristretto255_point_t) -> ristretto_bool_t; 522 | 523 | /// @brief Torque a point, for debugging purposes. The output 524 | /// will be equal to the input. 525 | /// 526 | /// @param [out] q The point to torque. 527 | /// @param [in] p The point to torque. 528 | pub fn ristretto255_point_debugging_torque( 529 | q: *mut ristretto255_point_t, 530 | p: *const ristretto255_point_t, 531 | ); 532 | 533 | /// @brief Projectively scale a point, for debugging purposes. 534 | /// The output will be equal to the input, and will be valid 535 | /// even if the factor is zero. 536 | /// 537 | /// @param [out] q The point to scale. 538 | /// @param [in] p The point to scale. 539 | /// @param [in] factor Serialized GF factor to scale. 540 | pub fn ristretto255_point_debugging_pscale( 541 | q: *mut ristretto255_point_t, 542 | p: *const ristretto255_point_t, 543 | factor: *const ::std::os::raw::c_uchar, 544 | ); 545 | 546 | /// @brief Almost-Elligator-like hash to curve. 547 | /// 548 | /// Call this function with the output of a hash to make a hash to the curve. 549 | /// 550 | /// This function runs Elligator2 on the ristretto255 Jacobi quartic model. It then 551 | /// uses the isogeny to put the result in twisted Edwards form. As a result, 552 | /// it is safe (cannot produce points of order 4), and would be compatible with 553 | /// hypothetical other implementations of Decaf using a Montgomery or untwisted 554 | /// Edwards model. 555 | /// 556 | /// Unlike Elligator, this function may be up to 4:1 on [0,(p-1)/2]: 557 | /// A factor of 2 due to the isogeny. 558 | /// A factor of 2 because we quotient out the 2-torsion. 559 | /// 560 | /// This makes it about 8:1 overall, or 16:1 overall on curves with cofactor 8. 561 | /// 562 | /// Negating the input (mod q) results in the same point. Inverting the input 563 | /// (mod q) results in the negative point. This is the same as Elligator. 564 | /// 565 | /// This function isn't quite indifferentiable from a random oracle. 566 | /// However, it is suitable for many protocols, including SPEKE and SPAKE2 EE. 567 | /// Furthermore, calling it twice with independent seeds and adding the results 568 | /// is indifferentiable from a random oracle. 569 | /// 570 | /// @param [in] hashed_data Output of some hash function. 571 | /// @param [out] pt The data hashed to the curve. 572 | pub fn ristretto255_point_from_hash_nonuniform( 573 | pt: *mut ristretto255_point_t, 574 | hashed_data: *const ::std::os::raw::c_uchar, 575 | ); 576 | 577 | /// @brief Indifferentiable hash function encoding to curve. 578 | /// 579 | /// Equivalent to calling ristretto255_point_from_hash_nonuniform twice and adding. 580 | /// 581 | /// @param [in] hashed_data Output of some hash function. 582 | /// @param [out] pt The data hashed to the curve. 583 | pub fn ristretto255_point_from_hash_uniform( 584 | pt: *mut ristretto255_point_t, 585 | hashed_data: *const ::std::os::raw::c_uchar, 586 | ); 587 | 588 | /// @brief Inverse of elligator-like hash to curve. 589 | /// 590 | /// This function writes to the buffer, to make it so that 591 | /// ristretto255_point_from_hash_nonuniform(buffer) = pt if 592 | /// possible. Since there may be multiple preimages, the 593 | /// "which" parameter chooses between them. To ensure uniform 594 | /// inverse sampling, this function succeeds or fails 595 | /// independently for different "which" values. 596 | /// 597 | /// This function isn't guaranteed to find every possible 598 | /// preimage, but it finds all except a small finite number. 599 | /// In particular, when the number of bits in the modulus isn't 600 | /// a multiple of 8 (i.e. for curve25519), it sets the high bits 601 | /// independently, which enables the generated data to be uniform. 602 | /// But it doesn't add p, so you'll never get exactly p from this 603 | /// function. This might change in the future, especially if 604 | /// we ever support eg Brainpool curves, where this could cause 605 | /// real nonuniformity. 606 | /// 607 | /// @param [out] recovered_hash Encoded data. 608 | /// @param [in] pt The point to encode. 609 | /// @param [in] which A value determining which inverse point 610 | /// to return. 611 | /// 612 | /// @retval RISTRETTO_SUCCESS The inverse succeeded. 613 | /// @retval RISTRETTO_FAILURE The inverse failed. 614 | pub fn ristretto255_invert_elligator_nonuniform( 615 | recovered_hash: *mut ::std::os::raw::c_uchar, 616 | pt: *const ristretto255_point_t, 617 | which: u32, 618 | ) -> ristretto_error_t; 619 | 620 | /// @brief Inverse of elligator-like hash to curve. 621 | /// 622 | /// This function writes to the buffer, to make it so that 623 | /// ristretto255_point_from_hash_uniform(buffer) = pt if 624 | /// possible. Since there may be multiple preimages, the 625 | /// "which" parameter chooses between them. To ensure uniform 626 | /// inverse sampling, this function succeeds or fails 627 | /// independently for different "which" values. 628 | /// 629 | /// @param [out] recovered_hash Encoded data. 630 | /// @param [in] pt The point to encode. 631 | /// @param [in] which A value determining which inverse point 632 | /// to return. 633 | /// 634 | /// @retval RISTRETTO_SUCCESS The inverse succeeded. 635 | /// @retval RISTRETTO_FAILURE The inverse failed. 636 | pub fn ristretto255_invert_elligator_uniform( 637 | recovered_hash: *mut ::std::os::raw::c_uchar, 638 | pt: *const ristretto255_point_t, 639 | which: u32, 640 | ) -> ristretto_error_t; 641 | 642 | /// Securely erase a scalar. 643 | pub fn ristretto255_scalar_destroy(scalar: *mut ristretto255_scalar_t); 644 | 645 | /// Securely erase a point by overwriting it with zeros. 646 | /// @warning This causes the point object to become invalid. 647 | pub fn ristretto255_point_destroy(point: *mut ristretto255_point_t); 648 | 649 | /// Securely erase a precomputed table by overwriting it with zeros. 650 | /// @warning This causes the table object to become invalid. 651 | pub fn ristretto255_precomputed_destroy(pre: *mut ristretto255_precomputed_s); 652 | } 653 | -------------------------------------------------------------------------------- /tests/src/constants.rs: -------------------------------------------------------------------------------- 1 | #![allow(unknown_lints, unreadable_literal)] 2 | 3 | use libristretto255_sys::{gf_25519_t, ristretto255_point_t}; 4 | 5 | macro_rules! field_literal { 6 | ($($elem:tt)+) => { 7 | gf_25519_t { 8 | limb: [$($elem)+], 9 | #[cfg(target_pointer_width = "64")] 10 | __bindgen_padding_0: [0, 0, 0], 11 | } 12 | }; 13 | } 14 | 15 | /// Eight torsion table taken directly from curve25519-dalek 16 | /// TODO: this is probably completely bogus and only works on 64-bit architectures 17 | pub const EIGHT_TORSION: [ristretto255_point_t; 8] = [ 18 | ristretto255_point_t { 19 | x: field_literal!(0, 0, 0, 0, 0), 20 | y: field_literal!(1, 0, 0, 0, 0), 21 | z: field_literal!(1, 0, 0, 0, 0), 22 | t: field_literal!(0, 0, 0, 0, 0), 23 | }, 24 | ristretto255_point_t { 25 | x: field_literal!( 26 | 358744748052810, 27 | 1691584618240980, 28 | 977650209285361, 29 | 1429865912637724, 30 | 560044844278676 31 | ), 32 | y: field_literal!( 33 | 84926274344903, 34 | 473620666599931, 35 | 365590438845504, 36 | 1028470286882429, 37 | 2146499180330972 38 | ), 39 | z: field_literal!(1, 0, 0, 0, 0), 40 | t: field_literal!( 41 | 1448326834587521, 42 | 1857896831960481, 43 | 1093722731865333, 44 | 1677408490711241, 45 | 1915505153018406 46 | ), 47 | }, 48 | ristretto255_point_t { 49 | x: field_literal!( 50 | 533094393274173, 51 | 2016890930128738, 52 | 18285341111199, 53 | 134597186663265, 54 | 1486323764102114 55 | ), 56 | y: field_literal!(0, 0, 0, 0, 0), 57 | z: field_literal!(1, 0, 0, 0, 0), 58 | t: field_literal!(0, 0, 0, 0, 0), 59 | }, 60 | ristretto255_point_t { 61 | x: field_literal!( 62 | 358744748052810, 63 | 1691584618240980, 64 | 977650209285361, 65 | 1429865912637724, 66 | 560044844278676 67 | ), 68 | y: field_literal!( 69 | 2166873539340326, 70 | 1778179147085316, 71 | 1886209374839743, 72 | 1223329526802818, 73 | 105300633354275 74 | ), 75 | z: field_literal!(1, 0, 0, 0, 0), 76 | t: field_literal!( 77 | 803472979097708, 78 | 393902981724766, 79 | 1158077081819914, 80 | 574391322974006, 81 | 336294660666841 82 | ), 83 | }, 84 | ristretto255_point_t { 85 | x: field_literal!(0, 0, 0, 0, 0), 86 | y: field_literal!( 87 | 2251799813685228, 88 | 2251799813685247, 89 | 2251799813685247, 90 | 2251799813685247, 91 | 2251799813685247 92 | ), 93 | z: field_literal!(1, 0, 0, 0, 0), 94 | t: field_literal!(0, 0, 0, 0, 0), 95 | }, 96 | ristretto255_point_t { 97 | x: field_literal!( 98 | 1893055065632419, 99 | 560215195444267, 100 | 1274149604399886, 101 | 821933901047523, 102 | 1691754969406571 103 | ), 104 | y: field_literal!( 105 | 2166873539340326, 106 | 1778179147085316, 107 | 1886209374839743, 108 | 1223329526802818, 109 | 105300633354275 110 | ), 111 | z: field_literal!(1, 0, 0, 0, 0), 112 | t: field_literal!( 113 | 1448326834587521, 114 | 1857896831960481, 115 | 1093722731865333, 116 | 1677408490711241, 117 | 1915505153018406 118 | ), 119 | }, 120 | ristretto255_point_t { 121 | x: field_literal!( 122 | 1718705420411056, 123 | 234908883556509, 124 | 2233514472574048, 125 | 2117202627021982, 126 | 765476049583133 127 | ), 128 | y: field_literal!(0, 0, 0, 0, 0), 129 | z: field_literal!(1, 0, 0, 0, 0), 130 | t: field_literal!(0, 0, 0, 0, 0), 131 | }, 132 | ristretto255_point_t { 133 | x: field_literal!( 134 | 1893055065632419, 135 | 560215195444267, 136 | 1274149604399886, 137 | 821933901047523, 138 | 1691754969406571 139 | ), 140 | y: field_literal!( 141 | 84926274344903, 142 | 473620666599931, 143 | 365590438845504, 144 | 1028470286882429, 145 | 2146499180330972 146 | ), 147 | z: field_literal!(1, 0, 0, 0, 0), 148 | t: field_literal!( 149 | 803472979097708, 150 | 393902981724766, 151 | 1158077081819914, 152 | 574391322974006, 153 | 336294660666841 154 | ), 155 | }, 156 | ]; 157 | -------------------------------------------------------------------------------- /tests/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Tests for `libristretto255`. 2 | //! 3 | //! NOTE: If you are looking for a production-quality Rust implementation 4 | //! of Ristretto then these are not the droids, or rather daleks, that you 5 | //! are looking for! 6 | //! 7 | //! Please use curve25519-dalek's upstream pure-Rust implementation instead! 8 | //! 9 | //! https://docs.rs/curve25519-dalek/latest/curve25519_dalek/ristretto/index.html 10 | 11 | // Adapted from curve25519-dalek's ristretto.rs 12 | // Copyright (c) 2016-2018 Isis Agora Lovecruft, Henry de Valence. All rights reserved. 13 | // 14 | // BSD Revised License (https://spdx.org/licenses/BSD-3-Clause.html) 15 | // 16 | // Redistribution and use in source and binary forms, with or without 17 | // modification, are permitted provided that the following conditions are 18 | // met: 19 | // 20 | // 1. Redistributions of source code must retain the above copyright 21 | // notice, this list of conditions and the following disclaimer. 22 | // 23 | // 2. Redistributions in binary form must reproduce the above copyright 24 | // notice, this list of conditions and the following disclaimer in the 25 | // documentation and/or other materials provided with the distribution. 26 | // 27 | // 3. Neither the name of the copyright holder nor the names of its 28 | // contributors may be used to endorse or promote products derived from 29 | // this software without specific prior written permission. 30 | // 31 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 32 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 33 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 34 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 37 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 38 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 39 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 40 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | // 43 | // Authors: 44 | // - Isis Agora Lovecruft 45 | // - Henry de Valence 46 | 47 | extern crate curve25519_dalek; 48 | extern crate hex; 49 | extern crate libristretto255_sys; 50 | extern crate rand; 51 | extern crate sha2; 52 | 53 | pub mod constants; 54 | pub mod ristretto; 55 | pub mod scalar; 56 | pub mod util; 57 | #[cfg(test)] 58 | pub mod vectors; 59 | 60 | #[cfg(test)] 61 | #[allow(non_snake_case)] 62 | mod test { 63 | use rand::OsRng; 64 | 65 | use ristretto::{CompressedRistretto, RistrettoPoint}; 66 | use scalar::Scalar; 67 | 68 | #[test] 69 | fn scalarmult_ristrettopoint_works_both_ways() { 70 | let P = RistrettoPoint::basepoint(); 71 | let s = Scalar::from(999u64); 72 | 73 | let P1 = P * s; 74 | let P2 = s * P; 75 | 76 | assert!(P1.compress().as_bytes() == P2.compress().as_bytes()); 77 | } 78 | 79 | #[test] 80 | fn decompress_id() { 81 | let compressed_id = CompressedRistretto::identity(); 82 | let id = compressed_id.decompress().unwrap(); 83 | let mut identity_in_coset = false; 84 | 85 | for P in id.coset4().iter_mut() { 86 | if P.compress() == CompressedRistretto::identity() { 87 | identity_in_coset = true; 88 | } 89 | } 90 | 91 | assert!(identity_in_coset); 92 | } 93 | 94 | #[test] 95 | fn compress_id() { 96 | let id = RistrettoPoint::identity(); 97 | assert_eq!(id.compress(), CompressedRistretto::identity()); 98 | } 99 | 100 | #[test] 101 | fn basepoint_roundtrip() { 102 | let bp = RistrettoPoint::basepoint(); 103 | let bp_compressed_ristretto = bp.compress(); 104 | assert_eq!(bp_compressed_ristretto.decompress().unwrap(), bp); 105 | } 106 | 107 | #[test] 108 | fn random_roundtrip() { 109 | let mut rng = OsRng::new().unwrap(); 110 | let B = RistrettoPoint::basepoint(); 111 | 112 | for _ in 0..100 { 113 | let P = B * Scalar::random(&mut rng); 114 | let compressed_P = P.compress(); 115 | let Q = compressed_P.decompress().unwrap(); 116 | 117 | assert_eq!(P, Q); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /tests/src/ristretto.rs: -------------------------------------------------------------------------------- 1 | use curve25519_dalek; 2 | use libristretto255_sys::*; 3 | use std::{ 4 | fmt::{self, Debug}, 5 | mem, 6 | ops::{Add, Mul, Neg, Sub}, 7 | }; 8 | 9 | use constants; 10 | use scalar::Scalar; 11 | use util::{convert_bool, convert_result}; 12 | 13 | /// Compressed Ristretto255 point 14 | #[derive(Copy, Clone, Eq, PartialEq)] 15 | pub struct CompressedRistretto(pub [u8; 32]); 16 | 17 | impl CompressedRistretto { 18 | /// Copy the bytes of this `CompressedRistretto`. 19 | pub fn to_bytes(&self) -> [u8; 32] { 20 | self.0 21 | } 22 | 23 | /// View this `CompressedRistretto` as an array of bytes. 24 | pub fn as_bytes(&self) -> &[u8; 32] { 25 | &self.0 26 | } 27 | 28 | /// Attempt to decompress to an `RistrettoPoint`. 29 | /// 30 | /// # Return 31 | /// 32 | /// - `Some(RistrettoPoint)` if `self` was the canonical encoding of a point; 33 | /// 34 | /// - `None` if `self` was not the canonical encoding of a point. 35 | pub fn decompress(&self) -> Option { 36 | let mut point = uninitialized_point_t(); 37 | 38 | let error = unsafe { 39 | ristretto255_point_decode( 40 | &mut point, 41 | self.0.as_ptr(), 42 | RISTRETTO_TRUE, // Allow identity for testing 43 | ) 44 | }; 45 | 46 | convert_result(point.into(), error).ok() 47 | } 48 | } 49 | 50 | impl CompressedRistretto { 51 | pub fn identity() -> CompressedRistretto { 52 | CompressedRistretto([0u8; 32]) 53 | } 54 | } 55 | 56 | impl Default for CompressedRistretto { 57 | fn default() -> CompressedRistretto { 58 | Self::identity() 59 | } 60 | } 61 | 62 | /// Create an uninitialized (i.e. zero-initialized) `ristretto255_point_t` 63 | fn uninitialized_point_t() -> ristretto255_point_t { 64 | unsafe { mem::zeroed() } 65 | } 66 | 67 | /// A `RistrettoPoint` represents a point in the Ristretto group for 68 | /// Curve25519 (a.k.a. Ristretto255) 69 | #[derive(Copy, Clone)] 70 | #[repr(transparent)] 71 | pub struct RistrettoPoint(ristretto255_point_t); 72 | 73 | impl RistrettoPoint { 74 | /// Compress this point using the Ristretto encoding. 75 | pub fn compress(&self) -> CompressedRistretto { 76 | let mut bytes = [0u8; 32]; 77 | 78 | unsafe { 79 | ristretto255_point_encode(bytes.as_mut_ptr(), &self.0); 80 | } 81 | 82 | CompressedRistretto(bytes) 83 | } 84 | 85 | /// Construct a `RistrettoPoint` from 64 bytes of data. 86 | pub fn from_uniform_bytes(bytes: &[u8; 64]) -> RistrettoPoint { 87 | let mut point = uninitialized_point_t(); 88 | 89 | unsafe { 90 | ristretto255_point_from_hash_uniform(&mut point, bytes.as_ptr()); 91 | } 92 | 93 | RistrettoPoint(point) 94 | } 95 | 96 | /// Return the coset self + E[4], for debugging. 97 | /// TODO: double check the `EIGHT_TORSION` table is correct 98 | pub fn coset4(self) -> [Self; 4] { 99 | [ 100 | self, 101 | self + constants::EIGHT_TORSION[2].into(), 102 | self + constants::EIGHT_TORSION[4].into(), 103 | self + constants::EIGHT_TORSION[6].into(), 104 | ] 105 | } 106 | } 107 | 108 | impl RistrettoPoint { 109 | pub fn basepoint() -> RistrettoPoint { 110 | RistrettoPoint(unsafe { ristretto255_point_base }) 111 | } 112 | 113 | pub fn identity() -> RistrettoPoint { 114 | RistrettoPoint(unsafe { ristretto255_point_identity }) 115 | } 116 | } 117 | 118 | impl Default for RistrettoPoint { 119 | fn default() -> RistrettoPoint { 120 | Self::identity() 121 | } 122 | } 123 | 124 | impl From for RistrettoPoint { 125 | fn from(point: ristretto255_point_t) -> RistrettoPoint { 126 | RistrettoPoint(point) 127 | } 128 | } 129 | 130 | // ------------------------------------------------------------------------ 131 | // Equality 132 | // ------------------------------------------------------------------------ 133 | 134 | impl PartialEq for RistrettoPoint { 135 | fn eq(&self, other: &RistrettoPoint) -> bool { 136 | convert_bool(unsafe { ristretto255_point_eq(&self.0, &other.0) }) 137 | } 138 | } 139 | 140 | impl Eq for RistrettoPoint {} 141 | 142 | // ------------------------------------------------------------------------ 143 | // Arithmetic 144 | // ------------------------------------------------------------------------ 145 | 146 | impl Add for RistrettoPoint { 147 | type Output = RistrettoPoint; 148 | 149 | fn add(self, other: RistrettoPoint) -> RistrettoPoint { 150 | let mut result = uninitialized_point_t(); 151 | 152 | unsafe { 153 | ristretto255_point_add(&mut result, &self.0, &other.0); 154 | } 155 | 156 | RistrettoPoint(result) 157 | } 158 | } 159 | 160 | impl Sub for RistrettoPoint { 161 | type Output = RistrettoPoint; 162 | 163 | fn sub(self, other: RistrettoPoint) -> RistrettoPoint { 164 | let mut result = uninitialized_point_t(); 165 | 166 | unsafe { 167 | ristretto255_point_sub(&mut result, &self.0, &other.0); 168 | } 169 | 170 | RistrettoPoint(result) 171 | } 172 | } 173 | 174 | impl Neg for RistrettoPoint { 175 | type Output = RistrettoPoint; 176 | 177 | fn neg(self) -> RistrettoPoint { 178 | let mut result = uninitialized_point_t(); 179 | 180 | unsafe { 181 | ristretto255_point_negate(&mut result, &self.0); 182 | } 183 | 184 | RistrettoPoint(result) 185 | } 186 | } 187 | 188 | impl Mul for RistrettoPoint { 189 | type Output = RistrettoPoint; 190 | 191 | /// Scalar multiplication: compute `scalar * self`. 192 | fn mul(self, scalar: Scalar) -> RistrettoPoint { 193 | let mut result = uninitialized_point_t(); 194 | 195 | unsafe { 196 | ristretto255_point_scalarmul(&mut result, &self.0, &scalar.0); 197 | } 198 | 199 | RistrettoPoint(result) 200 | } 201 | } 202 | 203 | impl Mul for Scalar { 204 | type Output = RistrettoPoint; 205 | 206 | /// Scalar multiplication: compute `self * scalar`. 207 | fn mul(self, point: RistrettoPoint) -> RistrettoPoint { 208 | point * self 209 | } 210 | } 211 | 212 | // ------------------------------------------------------------------------ 213 | // Conversions from curve25519-dalek types (for debugging/testing) 214 | // ------------------------------------------------------------------------ 215 | 216 | impl From for RistrettoPoint { 217 | fn from(dalek_ristretto_point: curve25519_dalek::ristretto::RistrettoPoint) -> Self { 218 | panic!("unimplemented: dalek point is: {:?}", dalek_ristretto_point); 219 | } 220 | } 221 | 222 | // ------------------------------------------------------------------------ 223 | // Debug traits 224 | // ------------------------------------------------------------------------ 225 | 226 | impl Debug for CompressedRistretto { 227 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 228 | write!(f, "CompressedRistretto: {:?}", self.as_bytes()) 229 | } 230 | } 231 | 232 | impl Debug for RistrettoPoint { 233 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 234 | let coset = self.coset4(); 235 | write!( 236 | f, 237 | "RistrettoPoint: coset \n{:?}\n{:?}\n{:?}\n{:?}", 238 | coset[0].0, coset[1].0, coset[2].0, coset[3].0 239 | ) 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /tests/src/scalar.rs: -------------------------------------------------------------------------------- 1 | use rand::{CryptoRng, Rng}; 2 | use std::{ 3 | fmt::{self, Debug}, 4 | mem, 5 | ops::{Add, Mul, Sub}, 6 | }; 7 | 8 | use libristretto255_sys::*; 9 | use util::convert_bool; 10 | 11 | /// Scalars (i.e. wrapper around `ristretto255_scalar_t`) 12 | #[derive(Copy, Clone)] 13 | pub struct Scalar(pub(crate) ristretto255_scalar_t); 14 | 15 | impl Scalar { 16 | /// Return a randomly generated `Scalar` 17 | /// 18 | /// This implementation isn't great as it only generates random scalars 19 | /// within the 64-bit unsigned range. 20 | /// 21 | /// Ideally it could generate larger ones. 22 | pub fn random(rng: &mut T) -> Self { 23 | Scalar::from(rng.gen::()) 24 | } 25 | } 26 | 27 | // ------------------------------------------------------------------------ 28 | // Equality 29 | // ------------------------------------------------------------------------ 30 | 31 | impl PartialEq for Scalar { 32 | fn eq(&self, other: &Scalar) -> bool { 33 | convert_bool(unsafe { ristretto255_scalar_eq(&self.0, &other.0) }) 34 | } 35 | } 36 | 37 | impl Eq for Scalar {} 38 | 39 | // ------------------------------------------------------------------------ 40 | // Arithmetic 41 | // ------------------------------------------------------------------------ 42 | 43 | impl Add for Scalar { 44 | type Output = Scalar; 45 | 46 | fn add(self, other: Scalar) -> Scalar { 47 | let mut result = uninitialized_scalar_t(); 48 | 49 | unsafe { 50 | ristretto255_scalar_add(&mut result, &self.0, &other.0); 51 | } 52 | 53 | Scalar(result) 54 | } 55 | } 56 | 57 | impl Sub for Scalar { 58 | type Output = Scalar; 59 | 60 | fn sub(self, other: Scalar) -> Scalar { 61 | let mut result = uninitialized_scalar_t(); 62 | 63 | unsafe { 64 | ristretto255_scalar_sub(&mut result, &self.0, &other.0); 65 | } 66 | 67 | Scalar(result) 68 | } 69 | } 70 | 71 | impl Mul for Scalar { 72 | type Output = Scalar; 73 | 74 | fn mul(self, other: Scalar) -> Scalar { 75 | let mut result = uninitialized_scalar_t(); 76 | 77 | unsafe { 78 | ristretto255_scalar_mul(&mut result, &self.0, &other.0); 79 | } 80 | 81 | Scalar(result) 82 | } 83 | } 84 | 85 | // ------------------------------------------------------------------------ 86 | // Type conversions 87 | // ------------------------------------------------------------------------ 88 | 89 | impl From for Scalar { 90 | fn from(x: u64) -> Scalar { 91 | let mut scalar = uninitialized_scalar_t(); 92 | unsafe { 93 | ristretto255_scalar_set_unsigned(&mut scalar, x); 94 | } 95 | Scalar(scalar) 96 | } 97 | } 98 | 99 | // ------------------------------------------------------------------------ 100 | // Debug traits 101 | // ------------------------------------------------------------------------ 102 | 103 | impl Debug for Scalar { 104 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 105 | let mut bytes = [0u8; 32]; 106 | unsafe { 107 | ristretto255_scalar_encode(bytes.as_mut_ptr(), &self.0); 108 | } 109 | write!(f, "Scalar({:?})", bytes) 110 | } 111 | } 112 | 113 | /// Create an uninitialized (i.e. zero-initialized) `ristretto_scalar_t` 114 | fn uninitialized_scalar_t() -> ristretto255_scalar_t { 115 | unsafe { mem::zeroed() } 116 | } 117 | -------------------------------------------------------------------------------- /tests/src/util.rs: -------------------------------------------------------------------------------- 1 | use libristretto255_sys::{ 2 | ristretto_bool_t, ristretto_error_t, RISTRETTO_FAILURE, RISTRETTO_FALSE, RISTRETTO_SUCCESS, 3 | RISTRETTO_TRUE, 4 | }; 5 | 6 | /// Convert a `ristretto_bool_t` to a Rust boolean 7 | /// 8 | /// Panics if the value is unexpected 9 | pub fn convert_bool(value: ristretto_bool_t) -> bool { 10 | unsafe { 11 | if value == RISTRETTO_TRUE { 12 | return true; 13 | } else if value == RISTRETTO_FALSE { 14 | return false; 15 | } 16 | } 17 | 18 | panic!("unexpected ristretto_bool_t: {}", value); 19 | } 20 | 21 | /// Opaque error type 22 | #[derive(Debug)] 23 | pub struct Error; 24 | 25 | /// Convert a `ristretto_error_t` and the given value into a `Result 26 | pub fn convert_result(value: T, error: ristretto_error_t) -> Result { 27 | match error { 28 | RISTRETTO_SUCCESS => Ok(value), 29 | RISTRETTO_FAILURE => Err(Error), 30 | other => panic!("unexpected ristretto_error_t: {}", other), 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/src/vectors.rs: -------------------------------------------------------------------------------- 1 | //! Ristretto255 test vectors: 2 | //! 3 | //! https://ristretto.group/test_vectors/ristretto255.html 4 | 5 | #![allow(non_snake_case)] 6 | 7 | use ristretto::{CompressedRistretto, RistrettoPoint}; 8 | use hex; 9 | //use sha2::{Digest, Sha512}; 10 | 11 | /// Test the byte encodings of small multiples 12 | /// [0]B, [1]B, ..., [15]B 13 | /// of the basepoint, represented as hex strings. 14 | #[test] 15 | fn encodings_of_small_multiples() { 16 | let encodings_of_small_multiples = [ 17 | // This is the identity point 18 | "0000000000000000000000000000000000000000000000000000000000000000", 19 | // This is the basepoint 20 | "e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76", 21 | // These are small multiples of the basepoint 22 | "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919", 23 | "94741f5d5d52755ece4f23f044ee27d5d1ea1e2bd196b462166b16152a9d0259", 24 | "da80862773358b466ffadfe0b3293ab3d9fd53c5ea6c955358f568322daf6a57", 25 | "e882b131016b52c1d3337080187cf768423efccbb517bb495ab812c4160ff44e", 26 | "f64746d3c92b13050ed8d80236a7f0007c3b3f962f5ba793d19a601ebb1df403", 27 | "44f53520926ec81fbd5a387845beb7df85a96a24ece18738bdcfa6a7822a176d", 28 | "903293d8f2287ebe10e2374dc1a53e0bc887e592699f02d077d5263cdd55601c", 29 | "02622ace8f7303a31cafc63f8fc48fdc16e1c8c8d234b2f0d6685282a9076031", 30 | "20706fd788b2720a1ed2a5dad4952b01f413bcf0e7564de8cdc816689e2db95f", 31 | "bce83f8ba5dd2fa572864c24ba1810f9522bc6004afe95877ac73241cafdab42", 32 | "e4549ee16b9aa03099ca208c67adafcafa4c3f3e4e5303de6026e3ca8ff84460", 33 | "aa52e000df2e16f55fb1032fc33bc42742dad6bd5a8fc0be0167436c5948501f", 34 | "46376b80f409b29dc2b5f6f0c52591990896e5716f41477cd30085ab7f10301e", 35 | "e0c418f7c8d9c4cdd7395b93ea124f3ad99021bb681dfc3302a9d99a2e53e64e", 36 | ]; 37 | 38 | // Test the encodings of small multiples 39 | 40 | let B = RistrettoPoint::basepoint(); 41 | let mut P = RistrettoPoint::identity(); 42 | for i in 0..16 { 43 | assert_eq!( 44 | hex::encode(P.compress().as_bytes()), 45 | encodings_of_small_multiples[i], 46 | ); 47 | P = P + B; 48 | } 49 | } 50 | 51 | /// Test that bad encodings are rejected. These vectors are designed to test 52 | /// each of the checks during decoding. 53 | #[test] 54 | pub fn bad_encodings() { 55 | let bad_encodings = [ 56 | // These are all bad because they're non-canonical field encodings. 57 | "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 58 | "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 59 | "f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 60 | "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 61 | // These are all bad because they're negative field elements. 62 | "0100000000000000000000000000000000000000000000000000000000000000", 63 | "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 64 | "ed57ffd8c914fb201471d1c3d245ce3c746fcbe63a3679d51b6a516ebebe0e20", 65 | "c34c4e1826e5d403b78e246e88aa051c36ccf0aafebffe137d148a2bf9104562", 66 | "c940e5a4404157cfb1628b108db051a8d439e1a421394ec4ebccb9ec92a8ac78", 67 | "47cfc5497c53dc8e61c91d17fd626ffb1c49e2bca94eed052281b510b1117a24", 68 | "f1c6165d33367351b0da8f6e4511010c68174a03b6581212c71c0e1d026c3c72", 69 | "87260f7a2f12495118360f02c26a470f450dadf34a413d21042b43b9d93e1309", 70 | // These are all bad because they give a nonsquare x^2. 71 | "26948d35ca62e643e26a83177332e6b6afeb9d08e4268b650f1f5bbd8d81d371", 72 | "4eac077a713c57b4f4397629a4145982c661f48044dd3f96427d40b147d9742f", 73 | "de6a7b00deadc788eb6b6c8d20c0ae96c2f2019078fa604fee5b87d6e989ad7b", 74 | "bcab477be20861e01e4a0e295284146a510150d9817763caf1a6f4b422d67042", 75 | "2a292df7e32cababbd9de088d1d1abec9fc0440f637ed2fba145094dc14bea08", 76 | "f4a9e534fc0d216c44b218fa0c42d99635a0127ee2e53c712f70609649fdff22", 77 | "8268436f8c4126196cf64b3c7ddbda90746a378625f9813dd9b8457077256731", 78 | "2810e5cbc2cc4d4eece54f61c6f69758e289aa7ab440b3cbeaa21995c2f4232b", 79 | // These are all bad because they give a negative xy value. 80 | "3eb858e78f5a7254d8c9731174a94f76755fd3941c0ac93735c07ba14579630e", 81 | "a45fdc55c76448c049a1ab33f17023edfb2be3581e9c7aade8a6125215e04220", 82 | "d483fe813c6ba647ebbfd3ec41adca1c6130c2beeee9d9bf065c8d151c5f396e", 83 | "8a2e1d30050198c65a54483123960ccc38aef6848e1ec8f5f780e8523769ba32", 84 | "32888462f8b486c68ad7dd9610be5192bbeaf3b443951ac1a8118419d9fa097b", 85 | "227142501b9d4355ccba290404bde41575b037693cef1f438c47f8fbf35d1165", 86 | "5c37cc491da847cfeb9281d407efc41e15144c876e0170b499a96a22ed31e01e", 87 | "445425117cb8c90edcbc7c1cc0e74f747f2c1efa5630a967c64f287792a48a4b", 88 | // This is s = -1, which causes y = 0. 89 | "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 90 | ]; 91 | 92 | // Test that all of the bad encodings are rejected 93 | let mut bad_bytes = [0u8; 32]; 94 | for bad_encoding in &bad_encodings { 95 | bad_bytes.copy_from_slice(&hex::decode(bad_encoding).unwrap()); 96 | assert!(CompressedRistretto(bad_bytes).decompress().is_none()); 97 | } 98 | } 99 | 100 | // Test Elligator 2 by performing hash-to-point with SHA-512 on the byte 101 | // encodings of the following list of UTF-8 encoded strings 102 | // TODO: the vectors on the web site are wrong. get new ones! 103 | //#[test] 104 | //fn hash_to_point() { 105 | // let labels = [ 106 | // "Ristretto is traditionally a short shot of espresso coffee", 107 | // "made with the normal amount of ground coffee but extracted with", 108 | // "about half the amount of water in the same amount of time", 109 | // "by using a finer grind.", 110 | // "This produces a concentrated shot of coffee per volume.", 111 | // "Just pulling a normal shot short will produce a weaker shot", 112 | // "and is not a Ristretto as some believe.", 113 | // ]; 114 | // 115 | // let encoded_hash_to_points = [ 116 | // "5c827272de19f868edc97deac8a9b12dea4604807463b59b040d463b8fa7f77f", 117 | // "88c01ea47c9a049578adced99d439d0f09a847595c546d51c6082b891f9dbc65", 118 | // "722b48912cd619ad2d542e78293f11053f8d18dcae456c7c7c98923d5eda844d", 119 | // "fafc78dec2fd2565d8592320fe0632ec288ffd3acd55314e619fdb9884dabe1c", 120 | // "8ae1f2311f26c03f14bcc192c0dd7589f679019068e6c83907e01735810a817c", 121 | // "6a152dcc33dfda4554e4999b439fe734f11021502825f14a1745e44dd023423b", 122 | // "b2757b09bc0ab160b2965e8e6385b3238e04665159b65ba26f1526303ebda807", 123 | // ]; 124 | // 125 | // for i in 0..7 { 126 | // let point = RistrettoPoint::hash_from_bytes::(labels[i].as_bytes()); 127 | // assert_eq!( 128 | // hex::encode(point.compress().as_bytes()), 129 | // encoded_hash_to_points[i], 130 | // ); 131 | // } 132 | //} 133 | --------------------------------------------------------------------------------