├── .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 |
--------------------------------------------------------------------------------