diff --git a/net/gurk-rs/Makefile b/net/gurk-rs/Makefile new file mode 100644 index 0000000..33f6b87 --- /dev/null +++ b/net/gurk-rs/Makefile @@ -0,0 +1,41 @@ +COMMENT = Signal Messenger client for terminal + +V = 0.2.5 +GH_ACCOUNT = boxdot +GH_PROJECT = gurk-rs +GH_TAGNAME = v${V} + +CATEGORIES = net + +MAINTAINER = Stefan Hagen + +# LICENSE +PERMIT_PACKAGE = Yes + +# as devel/cargo MODULES adds DISTFILES, GH_* didn't +DISTFILES += ${DISTNAME}${EXTRACT_SUFX} + +MODULES = devel/cargo + +.include "crates.inc" + +WANTLIB = c c++abi pthread + +#LIB_DEPENDS = +#RUN_DEPENDS = +#BUILD_DEPENDS = + +#TEST_DEPENDS = + +CONFIGURE_STYLE = cargo + +#MAKE_FLAGS = + +#NO_TEST = Yes +#TEST_TARGET = + +pre-configure: + cat ${FILESDIR}/config >> ${WRKSRC}/.cargo/config.toml; \ + cp -rf ${FILESDIR}/vendor ${WRKSRC}/ + +.include diff --git a/net/gurk-rs/crates.inc b/net/gurk-rs/crates.inc new file mode 100644 index 0000000..2c12dd6 --- /dev/null +++ b/net/gurk-rs/crates.inc @@ -0,0 +1,360 @@ +# run: make modcargo-gen-crates-licenses +MODCARGO_CRATES += adler 1.0.2 +MODCARGO_CRATES += aead 0.4.2 +MODCARGO_CRATES += aes 0.7.4 +MODCARGO_CRATES += aes-gcm 0.9.2 +MODCARGO_CRATES += aes-gcm-siv 0.10.1 +MODCARGO_CRATES += aho-corasick 0.7.18 +MODCARGO_CRATES += android_system_properties 0.1.5 +MODCARGO_CRATES += ansi_term 0.11.0 +MODCARGO_CRATES += ansi_term 0.12.1 +MODCARGO_CRATES += anyhow 1.0.42 +MODCARGO_CRATES += arrayref 0.3.6 +MODCARGO_CRATES += arrayvec 0.5.2 +MODCARGO_CRATES += ascii 0.9.3 +MODCARGO_CRATES += async-broadcast 0.3.4 +MODCARGO_CRATES += async-channel 1.6.1 +MODCARGO_CRATES += async-executor 1.4.1 +MODCARGO_CRATES += async-io 1.6.0 +MODCARGO_CRATES += async-lock 2.5.0 +MODCARGO_CRATES += async-recursion 0.3.2 +MODCARGO_CRATES += async-task 4.2.0 +MODCARGO_CRATES += async-trait 0.1.51 +MODCARGO_CRATES += async-tungstenite 0.15.0 +MODCARGO_CRATES += atty 0.2.14 +MODCARGO_CRATES += autocfg 1.1.0 +MODCARGO_CRATES += base64 0.12.3 +MODCARGO_CRATES += base64 0.13.0 +MODCARGO_CRATES += bincode 1.3.3 +MODCARGO_CRATES += bitflags 1.2.1 +MODCARGO_CRATES += block 0.1.6 +MODCARGO_CRATES += block-buffer 0.7.3 +MODCARGO_CRATES += block-buffer 0.9.0 +MODCARGO_CRATES += block-modes 0.8.1 +MODCARGO_CRATES += block-padding 0.1.5 +MODCARGO_CRATES += block-padding 0.2.1 +MODCARGO_CRATES += bstr 0.2.16 +MODCARGO_CRATES += bumpalo 3.7.0 +MODCARGO_CRATES += byte-tools 0.3.1 +MODCARGO_CRATES += byteorder 1.4.3 +MODCARGO_CRATES += bytes 1.0.1 +MODCARGO_CRATES += cache-padded 1.1.1 +MODCARGO_CRATES += cassowary 0.3.0 +MODCARGO_CRATES += cc 1.0.69 +MODCARGO_CRATES += cesu8 1.1.0 +MODCARGO_CRATES += cfg-if 1.0.0 +MODCARGO_CRATES += checked_int_cast 1.0.0 +MODCARGO_CRATES += chrono 0.4.22 +MODCARGO_CRATES += cipher 0.3.0 +MODCARGO_CRATES += clap 2.33.3 +MODCARGO_CRATES += combine 3.8.1 +MODCARGO_CRATES += concurrent-queue 1.2.2 +MODCARGO_CRATES += core-foundation 0.9.1 +MODCARGO_CRATES += core-foundation-sys 0.8.3 +MODCARGO_CRATES += cpufeatures 0.1.5 +MODCARGO_CRATES += crc32fast 1.2.1 +MODCARGO_CRATES += crossbeam-channel 0.5.5 +MODCARGO_CRATES += crossbeam-epoch 0.9.5 +MODCARGO_CRATES += crossbeam-utils 0.8.9 +MODCARGO_CRATES += crossterm 0.19.0 +MODCARGO_CRATES += crossterm_winapi 0.7.0 +MODCARGO_CRATES += crypto-mac 0.7.0 +MODCARGO_CRATES += crypto-mac 0.11.1 +MODCARGO_CRATES += ct-logs 0.8.0 +MODCARGO_CRATES += ctr 0.7.0 +MODCARGO_CRATES += curve25519-dalek 3.1.0 +MODCARGO_CRATES += derivative 2.2.0 +MODCARGO_CRATES += digest 0.8.1 +MODCARGO_CRATES += digest 0.9.0 +MODCARGO_CRATES += dirs 3.0.2 +MODCARGO_CRATES += dirs-next 2.0.0 +MODCARGO_CRATES += dirs-sys 0.3.6 +MODCARGO_CRATES += dirs-sys-next 0.1.2 +MODCARGO_CRATES += displaydoc 0.2.3 +MODCARGO_CRATES += easy-parallel 3.2.0 +MODCARGO_CRATES += either 1.6.1 +MODCARGO_CRATES += emoji 0.2.1 +MODCARGO_CRATES += enumflags2 0.7.5 +MODCARGO_CRATES += enumflags2_derive 0.7.4 +MODCARGO_CRATES += env_logger 0.8.4 +MODCARGO_CRATES += error-chain 0.12.4 +MODCARGO_CRATES += event-listener 2.5.2 +MODCARGO_CRATES += fake-simd 0.1.2 +MODCARGO_CRATES += fastrand 1.4.1 +MODCARGO_CRATES += filetime 0.2.14 +MODCARGO_CRATES += fixedbitset 0.2.0 +MODCARGO_CRATES += fixedbitset 0.4.1 +MODCARGO_CRATES += flate2 1.0.20 +MODCARGO_CRATES += fnv 1.0.7 +MODCARGO_CRATES += form_urlencoded 1.0.1 +MODCARGO_CRATES += fs2 0.4.3 +MODCARGO_CRATES += futures 0.3.15 +MODCARGO_CRATES += futures-channel 0.3.15 +MODCARGO_CRATES += futures-core 0.3.15 +MODCARGO_CRATES += futures-executor 0.3.15 +MODCARGO_CRATES += futures-io 0.3.15 +MODCARGO_CRATES += futures-lite 1.12.0 +MODCARGO_CRATES += futures-macro 0.3.15 +MODCARGO_CRATES += futures-sink 0.3.15 +MODCARGO_CRATES += futures-task 0.3.15 +MODCARGO_CRATES += futures-util 0.3.15 +MODCARGO_CRATES += fuzzy-matcher 0.3.7 +MODCARGO_CRATES += fxhash 0.2.1 +MODCARGO_CRATES += generic-array 0.12.4 +MODCARGO_CRATES += generic-array 0.14.4 +MODCARGO_CRATES += getopts 0.2.21 +MODCARGO_CRATES += getrandom 0.1.16 +MODCARGO_CRATES += getrandom 0.2.3 +MODCARGO_CRATES += gh-emoji 1.0.3 +MODCARGO_CRATES += ghash 0.4.2 +MODCARGO_CRATES += hashbrown 0.11.2 +MODCARGO_CRATES += headers 0.3.4 +MODCARGO_CRATES += headers-core 0.2.0 +MODCARGO_CRATES += heck 0.3.3 +MODCARGO_CRATES += hermit-abi 0.1.19 +MODCARGO_CRATES += hex 0.4.3 +MODCARGO_CRATES += hkdf 0.11.0 +MODCARGO_CRATES += hmac 0.7.1 +MODCARGO_CRATES += hmac 0.11.0 +MODCARGO_CRATES += hostname 0.3.1 +MODCARGO_CRATES += http 0.2.4 +MODCARGO_CRATES += http-body 0.4.2 +MODCARGO_CRATES += httparse 1.4.1 +MODCARGO_CRATES += httpdate 1.0.1 +MODCARGO_CRATES += hyper 0.14.11 +MODCARGO_CRATES += hyper-rustls 0.22.1 +MODCARGO_CRATES += hyper-timeout 0.4.1 +MODCARGO_CRATES += iana-time-zone 0.1.47 +MODCARGO_CRATES += idna 0.2.3 +MODCARGO_CRATES += indexmap 1.7.0 +MODCARGO_CRATES += instant 0.1.10 +MODCARGO_CRATES += itertools 0.9.0 +MODCARGO_CRATES += itertools 0.10.1 +MODCARGO_CRATES += itoa 0.4.7 +MODCARGO_CRATES += itoa 1.0.2 +MODCARGO_CRATES += jni 0.16.0 +MODCARGO_CRATES += jni-sys 0.3.0 +MODCARGO_CRATES += js-sys 0.3.59 +MODCARGO_CRATES += lazy_static 1.4.0 +MODCARGO_CRATES += lexical-core 0.7.6 +MODCARGO_CRATES += libc 0.2.126 +MODCARGO_CRATES += linked-hash-map 0.5.4 +MODCARGO_CRATES += lock_api 0.4.7 +MODCARGO_CRATES += log 0.4.14 +MODCARGO_CRATES += log-panics 2.0.0 +MODCARGO_CRATES += lru-cache 0.1.2 +MODCARGO_CRATES += mac-notification-sys 0.5.2 +MODCARGO_CRATES += malloc_buf 0.0.6 +MODCARGO_CRATES += match_cfg 0.1.0 +MODCARGO_CRATES += matches 0.1.8 +MODCARGO_CRATES += memchr 2.4.0 +MODCARGO_CRATES += memoffset 0.6.4 +MODCARGO_CRATES += mime 0.3.16 +MODCARGO_CRATES += mime_guess 2.0.3 +MODCARGO_CRATES += miniz_oxide 0.4.4 +MODCARGO_CRATES += mio 0.7.13 +MODCARGO_CRATES += miow 0.3.7 +MODCARGO_CRATES += mpart-async 0.5.0 +MODCARGO_CRATES += multimap 0.8.3 +MODCARGO_CRATES += nix 0.23.1 +MODCARGO_CRATES += nom 5.1.2 +MODCARGO_CRATES += notify-rust 4.5.8 +MODCARGO_CRATES += ntapi 0.3.6 +MODCARGO_CRATES += num-integer 0.1.44 +MODCARGO_CRATES += num-traits 0.2.14 +MODCARGO_CRATES += num_cpus 1.13.0 +MODCARGO_CRATES += num_enum 0.5.2 +MODCARGO_CRATES += num_enum_derive 0.5.2 +MODCARGO_CRATES += num_threads 0.1.6 +MODCARGO_CRATES += objc 0.2.7 +MODCARGO_CRATES += objc-foundation 0.1.1 +MODCARGO_CRATES += objc_id 0.1.1 +MODCARGO_CRATES += once_cell 1.13.1 +MODCARGO_CRATES += oncemutex 0.1.1 +MODCARGO_CRATES += opaque-debug 0.2.3 +MODCARGO_CRATES += opaque-debug 0.3.0 +MODCARGO_CRATES += opener 0.5.0 +MODCARGO_CRATES += openssl-probe 0.1.4 +MODCARGO_CRATES += ordered-stream 0.0.1 +MODCARGO_CRATES += parking 2.0.0 +MODCARGO_CRATES += parking_lot 0.11.1 +MODCARGO_CRATES += parking_lot_core 0.8.3 +MODCARGO_CRATES += percent-encoding 2.1.0 +MODCARGO_CRATES += petgraph 0.5.1 +MODCARGO_CRATES += petgraph 0.6.0 +MODCARGO_CRATES += phf 0.8.0 +MODCARGO_CRATES += phf_generator 0.8.0 +MODCARGO_CRATES += phf_macros 0.8.0 +MODCARGO_CRATES += phf_shared 0.8.0 +MODCARGO_CRATES += phonenumber 0.3.1+8.12.9 +MODCARGO_CRATES += pin-project 1.0.7 +MODCARGO_CRATES += pin-project-internal 1.0.7 +MODCARGO_CRATES += pin-project-lite 0.2.7 +MODCARGO_CRATES += pin-utils 0.1.0 +MODCARGO_CRATES += polling 2.1.0 +MODCARGO_CRATES += polyval 0.5.1 +MODCARGO_CRATES += ppv-lite86 0.2.10 +MODCARGO_CRATES += proc-macro-crate 1.0.0 +MODCARGO_CRATES += proc-macro-error 1.0.4 +MODCARGO_CRATES += proc-macro-error-attr 1.0.4 +MODCARGO_CRATES += proc-macro-hack 0.5.19 +MODCARGO_CRATES += proc-macro-nested 0.1.7 +MODCARGO_CRATES += proc-macro2 1.0.27 +MODCARGO_CRATES += prost 0.8.0 +MODCARGO_CRATES += prost 0.9.0 +MODCARGO_CRATES += prost-build 0.8.0 +MODCARGO_CRATES += prost-build 0.9.0 +MODCARGO_CRATES += prost-derive 0.8.0 +MODCARGO_CRATES += prost-derive 0.9.0 +MODCARGO_CRATES += prost-types 0.8.0 +MODCARGO_CRATES += prost-types 0.9.0 +MODCARGO_CRATES += pulldown-cmark 0.8.0 +MODCARGO_CRATES += qr2term 0.2.2 +MODCARGO_CRATES += qrcode 0.12.0 +MODCARGO_CRATES += quick-xml 0.18.1 +MODCARGO_CRATES += quickcheck 1.0.3 +MODCARGO_CRATES += quickcheck_macros 1.0.0 +MODCARGO_CRATES += quote 1.0.9 +MODCARGO_CRATES += rand 0.7.3 +MODCARGO_CRATES += rand 0.8.4 +MODCARGO_CRATES += rand_chacha 0.2.2 +MODCARGO_CRATES += rand_chacha 0.3.1 +MODCARGO_CRATES += rand_core 0.5.1 +MODCARGO_CRATES += rand_core 0.6.3 +MODCARGO_CRATES += rand_hc 0.2.0 +MODCARGO_CRATES += rand_hc 0.3.1 +MODCARGO_CRATES += rand_pcg 0.2.1 +MODCARGO_CRATES += redox_syscall 0.2.9 +MODCARGO_CRATES += redox_users 0.4.0 +MODCARGO_CRATES += regex 1.5.6 +MODCARGO_CRATES += regex-automata 0.1.10 +MODCARGO_CRATES += regex-cache 0.2.1 +MODCARGO_CRATES += regex-syntax 0.6.26 +MODCARGO_CRATES += remove_dir_all 0.5.3 +MODCARGO_CRATES += ring 0.16.20 +MODCARGO_CRATES += rustls 0.19.1 +MODCARGO_CRATES += rustls-native-certs 0.5.0 +MODCARGO_CRATES += ryu 1.0.5 +MODCARGO_CRATES += same-file 1.0.6 +MODCARGO_CRATES += schannel 0.1.19 +MODCARGO_CRATES += scopeguard 1.1.0 +MODCARGO_CRATES += sct 0.6.1 +MODCARGO_CRATES += security-framework 2.3.1 +MODCARGO_CRATES += security-framework-sys 2.3.0 +MODCARGO_CRATES += semver 1.0.3 +MODCARGO_CRATES += serde 1.0.126 +MODCARGO_CRATES += serde_derive 1.0.126 +MODCARGO_CRATES += serde_json 1.0.64 +MODCARGO_CRATES += serde_repr 0.1.7 +MODCARGO_CRATES += sha-1 0.9.6 +MODCARGO_CRATES += sha1 0.6.1 +MODCARGO_CRATES += sha1_smol 1.0.0 +MODCARGO_CRATES += sha2 0.8.2 +MODCARGO_CRATES += sha2 0.9.5 +MODCARGO_CRATES += sharded-slab 0.1.4 +MODCARGO_CRATES += signal-hook 0.1.17 +MODCARGO_CRATES += signal-hook-registry 1.4.0 +MODCARGO_CRATES += siphasher 0.3.5 +MODCARGO_CRATES += slab 0.4.3 +MODCARGO_CRATES += sled 0.34.6 +MODCARGO_CRATES += smallvec 1.6.1 +MODCARGO_CRATES += smawk 0.3.1 +MODCARGO_CRATES += socket2 0.4.0 +MODCARGO_CRATES += spin 0.5.2 +MODCARGO_CRATES += static_assertions 1.1.0 +MODCARGO_CRATES += strsim 0.8.0 +MODCARGO_CRATES += structopt 0.3.22 +MODCARGO_CRATES += structopt-derive 0.4.15 +MODCARGO_CRATES += strum 0.22.0 +MODCARGO_CRATES += strum_macros 0.22.0 +MODCARGO_CRATES += subtle 1.0.0 +MODCARGO_CRATES += subtle 2.4.1 +MODCARGO_CRATES += syn 1.0.73 +MODCARGO_CRATES += synstructure 0.12.5 +MODCARGO_CRATES += tar 0.4.38 +MODCARGO_CRATES += tempfile 3.2.0 +MODCARGO_CRATES += textwrap 0.11.0 +MODCARGO_CRATES += textwrap 0.14.2 +MODCARGO_CRATES += thiserror 1.0.30 +MODCARGO_CRATES += thiserror-impl 1.0.30 +MODCARGO_CRATES += thread_local 1.1.4 +MODCARGO_CRATES += time 0.1.44 +MODCARGO_CRATES += time 0.3.9 +MODCARGO_CRATES += tinyvec 1.2.0 +MODCARGO_CRATES += tinyvec_macros 0.1.0 +MODCARGO_CRATES += tokio 1.16.1 +MODCARGO_CRATES += tokio-io-timeout 1.1.1 +MODCARGO_CRATES += tokio-macros 1.8.0 +MODCARGO_CRATES += tokio-rustls 0.22.0 +MODCARGO_CRATES += tokio-stream 0.1.7 +MODCARGO_CRATES += tokio-util 0.6.7 +MODCARGO_CRATES += toml 0.5.8 +MODCARGO_CRATES += tower-service 0.3.1 +MODCARGO_CRATES += tracing 0.1.35 +MODCARGO_CRATES += tracing-appender 0.2.2 +MODCARGO_CRATES += tracing-attributes 0.1.21 +MODCARGO_CRATES += tracing-core 0.1.27 +MODCARGO_CRATES += tracing-log 0.1.3 +MODCARGO_CRATES += tracing-subscriber 0.3.11 +MODCARGO_CRATES += try-lock 0.2.3 +MODCARGO_CRATES += tui 0.15.0 +MODCARGO_CRATES += tungstenite 0.15.0 +MODCARGO_CRATES += twoway 0.2.2 +MODCARGO_CRATES += typenum 1.13.0 +MODCARGO_CRATES += unchecked-index 0.2.2 +MODCARGO_CRATES += unicase 2.6.0 +MODCARGO_CRATES += unicode-bidi 0.3.5 +MODCARGO_CRATES += unicode-linebreak 0.1.1 +MODCARGO_CRATES += unicode-normalization 0.1.19 +MODCARGO_CRATES += unicode-segmentation 1.8.0 +MODCARGO_CRATES += unicode-width 0.1.8 +MODCARGO_CRATES += unicode-xid 0.2.2 +MODCARGO_CRATES += universal-hash 0.4.0 +MODCARGO_CRATES += unreachable 1.0.0 +MODCARGO_CRATES += untrusted 0.7.1 +MODCARGO_CRATES += url 2.2.2 +MODCARGO_CRATES += utf-8 0.7.6 +MODCARGO_CRATES += uuid 0.8.2 +MODCARGO_CRATES += valuable 0.1.0 +MODCARGO_CRATES += vec_map 0.8.2 +MODCARGO_CRATES += version_check 0.9.3 +MODCARGO_CRATES += void 1.0.2 +MODCARGO_CRATES += waker-fn 1.1.0 +MODCARGO_CRATES += walkdir 2.3.2 +MODCARGO_CRATES += want 0.3.0 +MODCARGO_CRATES += wasi 0.9.0+wasi-snapshot-preview1 +MODCARGO_CRATES += wasi 0.10.0+wasi-snapshot-preview1 +MODCARGO_CRATES += wasm-bindgen 0.2.82 +MODCARGO_CRATES += wasm-bindgen-backend 0.2.82 +MODCARGO_CRATES += wasm-bindgen-macro 0.2.82 +MODCARGO_CRATES += wasm-bindgen-macro-support 0.2.82 +MODCARGO_CRATES += wasm-bindgen-shared 0.2.82 +MODCARGO_CRATES += web-sys 0.3.51 +MODCARGO_CRATES += webpki 0.21.4 +MODCARGO_CRATES += wepoll-ffi 0.1.2 +MODCARGO_CRATES += which 4.1.0 +MODCARGO_CRATES += whoami 1.1.2 +MODCARGO_CRATES += winapi 0.3.9 +MODCARGO_CRATES += winapi-i686-pc-windows-gnu 0.4.0 +MODCARGO_CRATES += winapi-util 0.1.5 +MODCARGO_CRATES += winapi-x86_64-pc-windows-gnu 0.4.0 +MODCARGO_CRATES += windows 0.24.0 +MODCARGO_CRATES += windows_i686_gnu 0.24.0 +MODCARGO_CRATES += windows_i686_msvc 0.24.0 +MODCARGO_CRATES += windows_x86_64_gnu 0.24.0 +MODCARGO_CRATES += windows_x86_64_msvc 0.24.0 +MODCARGO_CRATES += winrt-notification 0.5.1 +MODCARGO_CRATES += x25519-dalek 1.1.1 +MODCARGO_CRATES += xattr 0.2.2 +MODCARGO_CRATES += xflags 0.2.2 +MODCARGO_CRATES += xflags-macros 0.2.2 +MODCARGO_CRATES += xml-rs 0.8.4 +MODCARGO_CRATES += xshell 0.1.14 +MODCARGO_CRATES += xshell-macros 0.1.14 +MODCARGO_CRATES += zbus 2.1.1 +MODCARGO_CRATES += zbus_macros 2.1.1 +MODCARGO_CRATES += zbus_names 2.1.0 +MODCARGO_CRATES += zeroize 1.3.0 +MODCARGO_CRATES += zeroize_derive 1.3.2 +MODCARGO_CRATES += zvariant 3.3.0 +MODCARGO_CRATES += zvariant_derive 3.3.0 diff --git a/net/gurk-rs/distinfo b/net/gurk-rs/distinfo new file mode 100644 index 0000000..8eac37f --- /dev/null +++ b/net/gurk-rs/distinfo @@ -0,0 +1,720 @@ +SHA256 (cargo/adler-1.0.2.tar.gz) = 8mIBYEyHseAb09mPjV2aj8u4FejO20H/zL60v1k6Nf4= +SHA256 (cargo/aead-0.4.2.tar.gz) = bj55iqDII5d29UQVvAbz10sYUPP4MLRcNc/IBVaXP3A= +SHA256 (cargo/aes-0.7.4.tar.gz) = SV7maUE7++noys6A9NPXjm2MjZlXn5f7k73jUbGF8tQ= +SHA256 (cargo/aes-gcm-0.9.2.tar.gz) = vDvpLhmn70dFe45vkHB+ErasXSDG84ZlhPo74Hh9g58= +SHA256 (cargo/aes-gcm-siv-0.10.1.tar.gz) = z96BRnYvPF88XNQaoXpx8xiN8J1YVxkrZYUQ2FDhYGg= +SHA256 (cargo/aho-corasick-0.7.18.tar.gz) = HjfP1edletpF90LW6ZyleIWAtcUp3Hj68R7ObccCZW8= +SHA256 (cargo/android_system_properties-0.1.5.tar.gz) = gZ5yGdvUEEOsJ5sZgw8u/IlxVkkNf9bqkWcgEX7mYxE= +SHA256 (cargo/ansi_term-0.11.0.tar.gz) = 7km69sthe4U6qNk79CDbI4P6tG0xRILKKAO0DV/el5s= +SHA256 (cargo/ansi_term-0.12.1.tar.gz) = 1Sqbt+wM9ITFUYMKfOJ70g1n6sZH4b77VrC+TuOaVdI= +SHA256 (cargo/anyhow-1.0.42.tar.gz) = WV08+npg1FVctQZ7mfBxQqCOp3jeXPmT97dcfY+rxIY= +SHA256 (cargo/arrayref-0.3.6.tar.gz) = pMUnFS43z3V6P3iq5aBvvu/bB8zFNcmAoyCO4wYN1UQ= +SHA256 (cargo/arrayvec-0.5.2.tar.gz) = I7Yvxl3o5Of1JTT7UrDz7QR0auJnUZ7vKoOUHoCFBos= +SHA256 (cargo/ascii-0.9.3.tar.gz) = 6rHASlcYQRAvU0Wo/A9rs9McMV3sh5tcbkLkDOf/o04= +SHA256 (cargo/async-broadcast-0.3.4.tar.gz) = kGImmKEhjgsvuEbJe18ZoIMfa63e5z2UVBVjZcz6Rzs= +SHA256 (cargo/async-channel-1.6.1.tar.gz) = IRTWRnIVHAxeql4THshKdPBuHlWYMNq7oByjBgXWYxk= +SHA256 (cargo/async-executor-1.4.1.tar.gz) = hx+bteCiLut+jPFmQf64fJ3GcDLM+P9J53LrmUHTqWU= +SHA256 (cargo/async-io-1.6.0.tar.gz) = qBHmpHnyQ58MBAOHlrXPs9KtVsIw4PLT97BNaM/uYHs= +SHA256 (cargo/async-lock-2.5.0.tar.gz) = 6XoXHRkXgvujG7kCsUrZTiSmgUUDK37t+HGrC8DQd7Y= +SHA256 (cargo/async-recursion-0.3.2.tar.gz) = 19eGVroB8bkwJLfDoEZ/FgjkvmfXJXSf3NfSx2eP16I= +SHA256 (cargo/async-task-4.2.0.tar.gz) = MGlqhNgXEH/AKOBJmA4J1eFA6NqPHK6xfo6VBlijzqk= +SHA256 (cargo/async-trait-0.1.51.tar.gz) = RDGOd232gRWogd6aj9G55TNo16SlzkzEhRfaM5MjOl4= +SHA256 (cargo/async-tungstenite-0.15.0.tar.gz) = dCzH3LILL4SkL0aRqpmQcOx+ePjn50OL8UvnAXtEkH4= +SHA256 (cargo/atty-0.2.14.tar.gz) = 2bOb4Ydw0RQhzbG5lHpF3T836TCSy/N3YUgooxnV/ug= +SHA256 (cargo/autocfg-1.1.0.tar.gz) = 1GiAK6sXy8DMV16bBT9B5yqja/prf1XjUp/6QxYbl/o= +SHA256 (cargo/base64-0.12.3.tar.gz) = NEHw97AniOlI5H9FfKAfHX5tksaTvBMsIrCH0xQcA/8= +SHA256 (cargo/base64-0.13.0.tar.gz) = kE3+rFDzzauij8b1f9zdt19J7WE0ZnanjE/+VYd4Av0= +SHA256 (cargo/bincode-1.3.3.tar.gz) = sfRelBfYcifHpW0i5HHGIGRiy6UUx1kMCa/0z20d3K0= +SHA256 (cargo/bitflags-1.2.1.tar.gz) = zx3i/ox1vBRaL1d63ZUfgTSIm0eV1HRmpUpchG1pFpM= +SHA256 (cargo/block-0.1.6.tar.gz) = DYwf72kJQdPneI0yhRdZH+zGhMCECEcC1v8WQemTaZo= +SHA256 (cargo/block-buffer-0.7.3.tar.gz) = wJQNxEHzFokmnhCscOsQAqOh060TkOAwBDZi63/kaIs= +SHA256 (cargo/block-buffer-0.9.0.tar.gz) = QVIRb9bp2tspGuGPwew1de1thMKWQtl4kPS0o0Fyl+Q= +SHA256 (cargo/block-modes-0.8.1.tar.gz) = LLA9G+0VXYnc4PhFt4mbGKmhY+FI/QBOHChCGng+LY4= +SHA256 (cargo/block-padding-0.1.5.tar.gz) = +nne27CR9Enx855T7fiNXb6V+JXa5hNajXuIH7Wvc/U= +SHA256 (cargo/block-padding-0.2.1.tar.gz) = jWlsNwx1DJSK2mHGmg7iy7ucULEBnduG2TFxV6mcLK4= +SHA256 (cargo/bstr-0.2.16.tar.gz) = kGgsjWE60zc+Zt6MZBHgriqyVx6HnS779zVYzGbyEnk= +SHA256 (cargo/bumpalo-3.7.0.tar.gz) = nFnnrwEscT9Snno+5Xzpsx3dhY1LUSkjYC90YIsAljE= +SHA256 (cargo/byte-tools-0.3.1.tar.gz) = 47XKegSJitS81ByQxShURf9beRiZuxsKvdKiqnkSEdc= +SHA256 (cargo/byteorder-1.4.3.tar.gz) = FMGJxT0JiUVJnN+n7MY1Z884hrMzKzEqW0WF2NOmphA= +SHA256 (cargo/bytes-1.0.1.tar.gz) = twDOQ3YEHc0KMn/QCXxBCVdDxMiviIcmWUL68RAL0EA= +SHA256 (cargo/cache-padded-1.1.1.tar.gz) = YxrlGYyb5edT5cwhXhvXPCtGajVlFz20M/UrudPmbbo= +SHA256 (cargo/cassowary-0.3.0.tar.gz) = 34ZwuMe52uF5M2Tq+t9yOcQNZpkEZgxZYNdM/YC0alM= +SHA256 (cargo/cc-1.0.69.tar.gz) = 5wzC9ixs4YaJY4J71nd2TGLQfD2aPh+xF37hqasZnrI= +SHA256 (cargo/cesu8-1.1.0.tar.gz) = bUOgTYdT81JYyR+Oxjn3kokfdIoe29dZzx3Oozgq2Dw= +SHA256 (cargo/cfg-if-1.0.0.tar.gz) = uvHeQzl2FYi8Bhnjy8ASDuWC67dLU7Tvv3kRe9LaQP0= +SHA256 (cargo/checked_int_cast-1.0.0.tar.gz) = F8xea1qwYzHDNYmEIHBBa6oTfosOuRKwCM/Up4raeRk= +SHA256 (cargo/chrono-0.4.22.tar.gz) = v9TRsx+qo6ideTTb3tMRHaDS7yjj68zbTwF59ZKdHvE= +SHA256 (cargo/cipher-0.3.0.tar.gz) = fuUgcuwVOG93CAWv0YmgHIhBvoaWvtJQ+i8TxMDW37c= +SHA256 (cargo/clap-2.33.3.tar.gz) = N+WKx4VzxAcI1FUi8NgPovAcxPm04r90mAclVFQxIAI= +SHA256 (cargo/combine-3.8.1.tar.gz) = 2j2muqMh7BnhzEHTG/WZ8Ax4PQUXCVza8DMuP+jSBoA= +SHA256 (cargo/concurrent-queue-1.2.2.tar.gz) = MO0HVQvgFZTGAmz/Kh1/6cj2g8qnmOEraGlKyeiChqM= +SHA256 (cargo/core-foundation-0.9.1.tar.gz) = ConirkJuqDFV3M8QwPprFGPvbV/LRM7gsiSkCPpkCmI= +SHA256 (cargo/core-foundation-sys-0.8.3.tar.gz) = WCfOv0ZwRouHct0ZGFZ2iu3LGwJ4oE+Yn3dmNRkXudw= +SHA256 (cargo/cpufeatures-0.1.5.tar.gz) = ZsmWlvbJ3X811Ia50E1+biAqo+jEDVU/L99efgxqce8= +SHA256 (cargo/crc32fast-1.2.1.tar.gz) = gRVv7OhKtqnyr9sQnOOuV35CsSKEQe3tmb139ieVOxo= +SHA256 (cargo/crossbeam-channel-0.5.5.tar.gz) = TAKk1xgZAJwZLPSHImU5FWP9aoTIH/LA8qcCbKTB2Fw= +SHA256 (cargo/crossbeam-epoch-0.9.5.tar.gz) = TsAuCRqmNOLDraSjkpiefDEWZz7wrFtyIyQ5CU1zt/0= +SHA256 (cargo/crossbeam-utils-0.8.9.tar.gz) = j/H5gJV3hyhqVUBS0Dx67pjZnMMuCfbUXwqBQTPIeXg= +SHA256 (cargo/crossterm-0.19.0.tar.gz) = fDbBATDfQksvNVL8wt3Nmyiiex5Us1i0WHT4jRymiIw= +SHA256 (cargo/crossterm_winapi-0.7.0.tar.gz) = DaiWSs5NPkoET9AnkZsiNwALJDFaN8kW9hgJ8f8hQLk= +SHA256 (cargo/crypto-mac-0.11.1.tar.gz) = sdGob0kjbCFfJx1AiS1fyVBJBVFACwLvNgaSwpgVxxQ= +SHA256 (cargo/crypto-mac-0.7.0.tar.gz) = RDRADfEdldVWusBo3f7dSCkV6xj+i+qJvIC25LHBeeU= +SHA256 (cargo/ct-logs-0.8.0.tar.gz) = wagWGG+mjZ5Cbjy0rk3/H82OSiw0t4G/eoIldKDQqsg= +SHA256 (cargo/ctr-0.7.0.tar.gz) = ojL5KgPzfdfX3SrcZxZsd+nNiN5bAZuanuz66ve/1IE= +SHA256 (cargo/curve25519-dalek-3.1.0.tar.gz) = Y5iR/eDb6oI/w9eYoP350vlECkLWSnirNIiwygJRF7M= +SHA256 (cargo/derivative-2.2.0.tar.gz) = /MPdXp6cCyldbh5NgR+28VfV/9eEuNIC/GLqyANadws= +SHA256 (cargo/digest-0.8.1.tar.gz) = 89DIyHUjEvlxPv05f/Y6y5+FWFr78XkoLnIOdwSVTdU= +SHA256 (cargo/digest-0.9.0.tar.gz) = 091g0QgKV6BasDI3cEngWRQV0rMa/XAoNW2/PMbcsGY= +SHA256 (cargo/dirs-3.0.2.tar.gz) = MLqgQxA8nQwqV89TfMLzViOIncDUBebDzM+tvIHHEwk= +SHA256 (cargo/dirs-next-2.0.0.tar.gz) = uYz46/GcPRsiPhUfmaT58GkNykFBR3M5D8gkGErIM+E= +SHA256 (cargo/dirs-sys-0.3.6.tar.gz) = A9hlNO02emdUjcaBE6D121VDL9+7bm+dd3BDl9ldV4A= +SHA256 (cargo/dirs-sys-next-0.1.2.tar.gz) = Tr2hRMT+AtH36hp9lkG2/GtYCtz6Akrkh5fs3raCW00= +SHA256 (cargo/displaydoc-0.2.3.tar.gz) = O/ldw/BGudpPLVGDPA01R9hWTvaRD1we0TAwanW5KIY= +SHA256 (cargo/easy-parallel-3.2.0.tar.gz) = aQfiU5PNzB9PP1E9mqwehA6xzDQaD8ywEXH30U0QuUY= +SHA256 (cargo/either-1.6.1.tar.gz) = 541PHMSuM7v8FX7V1aXvO8KSJzA9WVhh3rI4/OxOlFc= +SHA256 (cargo/emoji-0.2.1.tar.gz) = MukwmHA3H3+ndndS5QSPwMBnWwF6J9nGAd/+mh7+AwE= +SHA256 (cargo/enumflags2-0.7.5.tar.gz) = 511M0huVODREgxU5kJ+7FLncP9zrKm9dNldzKaH1XMs= +SHA256 (cargo/enumflags2_derive-0.7.4.tar.gz) = 9Y3DxeRoJZ8Z8tRjBKayjxw9A0RC4UsyLSuFDjb21a4= +SHA256 (cargo/env_logger-0.8.4.tar.gz) = oZGH/qOsfoTafaz0jeDEXWPGp2+UkNrjia6tFsJD/OM= +SHA256 (cargo/error-chain-0.12.4.tar.gz) = LS8GucrBUG7OmP4yMePMnEQQ7D1bHySuHIlG8HQs3vw= +SHA256 (cargo/event-listener-2.5.2.tar.gz) = d/MwlBeTjyi/gij8/3mko3EDmB4+GG0szRnHSzj063E= +SHA256 (cargo/fake-simd-0.1.2.tar.gz) = 6IqKzykdr7WcLZbo9Zgo84OLsacDmII63lGoTeam3u0= +SHA256 (cargo/fastrand-1.4.1.tar.gz) = d7cFgp0eh/diwt9toUCyavWDnhAzqoSqX1a7aI5OG9s= +SHA256 (cargo/filetime-0.2.14.tar.gz) = HTTPoTpjrgWL+mAf6eMTu9s3RkJ8FFkYVGTOD89i4eg= +SHA256 (cargo/fixedbitset-0.2.0.tar.gz) = N6s0dBboAt5ITk0DxzFsSPHstWV039SkaoDxc84d4E0= +SHA256 (cargo/fixedbitset-0.4.1.tar.gz) = J5+wKOILPEwyAxeVW3fF4MlwHwWh0wmQXW/HAs3FBT4= +SHA256 (cargo/flate2-1.0.20.tar.gz) = zTrsU94Q/pbX2MVl6xfyxoe7VRii7EU7WxJSlkUmq+A= +SHA256 (cargo/fnv-1.0.7.tar.gz) = P57skY0/JAad7LmvFVTK18iA4tokqa/YisoABTGrgsE= +SHA256 (cargo/form_urlencoded-1.0.1.tar.gz) = X8Jah/pP0glL/7BpJYUgNNkKF/DR4FGX1JVtNVV1IZE= +SHA256 (cargo/fs2-0.4.3.tar.gz) = lWT8dY4VAltGqmZDsbd9BH0aVqGupuAQAqwMcCaHYhM= +SHA256 (cargo/futures-0.3.15.tar.gz) = Dn5DqAPa4vo3wfao/hIeH3v5VItN/AUipC80FF2t/Cc= +SHA256 (cargo/futures-channel-0.3.15.tar.gz) = 5oKmiymogt8FRcFD3DZG2u/oC6R5vN7elNWnA94oceI= +SHA256 (cargo/futures-core-0.3.15.tar.gz) = BAL3ZdiomiYEO4ibJs48RnnSaPprsizXxqrZg0DhedE= +SHA256 (cargo/futures-executor-0.3.15.tar.gz) = utqmqQn6yecjbQYgovV/dmRkDFZXW3GnVS+9aN6vq3k= +SHA256 (cargo/futures-io-0.3.15.tar.gz) = rMSZ3vs7NI+Njz9mQVg1qRMYVv93FL8Q2t/E7EvbKaE= +SHA256 (cargo/futures-lite-1.12.0.tar.gz) = dpRIms05RSx32qSFFriUwVPxksNXjVqDm2LFgJn8v0g= +SHA256 (cargo/futures-macro-0.3.15.tar.gz) = pMQCmEhs31LMAM1taYeJK6UCx2VqFqQZKpmSsczt0SE= +SHA256 (cargo/futures-sink-0.3.15.tar.gz) = pXvq0M7/DW3ej0ZezZbJM4Ehu3cX0+exCAWVMYcMQoI= +SHA256 (cargo/futures-task-0.3.15.tar.gz) = iha++fwaTd21vuUcmJ4/u6Jlacuw4x9bMDwYTj3TPa4= +SHA256 (cargo/futures-util-0.3.15.tar.gz) = /rXCONJ+K/lP/f0nssKePfSmjEGTu2QnOEJZ4r8ZGWc= +SHA256 (cargo/fuzzy-matcher-0.3.7.tar.gz) = VGFKMxKTTQZnAagPIPFfo7VtZ6x3IrOe6ltMndHWbJQ= +SHA256 (cargo/fxhash-0.2.1.tar.gz) = wxttdRrix/ETIEAtNOQTSd0QFvjV1F5IxDEryGJa9Qw= +SHA256 (cargo/generic-array-0.12.4.tar.gz) = /9+fNPFEdEPTc5PMbCuDE6693NlpBsrzTlTGjY5X170= +SHA256 (cargo/generic-array-0.14.4.tar.gz) = UBRm7MijDR07f8kimxIrLOjtbp2SI/ETjUurslPlGBc= +SHA256 (cargo/getopts-0.2.21.tar.gz) = FNu/1ccdcCQez55vE3N/e1zoI4IQYxiNfkbEHTce69U= +SHA256 (cargo/getrandom-0.1.16.tar.gz) = j8PLTZH1O1AVW9z9I/akw5rhlpwq6FmCsTV1DMyvX84= +SHA256 (cargo/getrandom-0.2.3.tar.gz) = f82ZlGNSTFJllRf+LOqYSTz+SF0QVl57D7B9u6etJ1M= +SHA256 (cargo/gh-emoji-1.0.3.tar.gz) = oXoFC360IFUzROHPHbZI6LWEx56Yt05ubRGe7t2d3Lw= +SHA256 (cargo/ghash-0.4.2.tar.gz) = e71gyqMRI31QiSfbunWUtIPbPvBfqlUXL8+JsbzaeFM= +SHA256 (cargo/hashbrown-0.11.2.tar.gz) = q17w1JCe83JMyMzmzMhXLFyBdZLpKF9UZPjob4vTcm4= +SHA256 (cargo/headers-0.3.4.tar.gz) = 8LdZH7YpAnBq6Oeq/0FrGw+iwP0IeLRtwTuqNxLYqFU= +SHA256 (cargo/headers-core-0.2.0.tar.gz) = 5/Zkgb/uJzlXsfIEhaT/M2KYf4WywjZYDYG063oyZCk= +SHA256 (cargo/heck-0.3.3.tar.gz) = bWIe+yaGPw6ZJMasV36CdeXmt3RV22T/psZckE6eEyw= +SHA256 (cargo/hermit-abi-0.1.19.tar.gz) = YrRnNDuUukdtyyUA0kLa27OVV9+IkxCsd8XZkQCqrDM= +SHA256 (cargo/hex-0.4.3.tar.gz) = fyQlSqmlS1yFjq7i9bzNtGqvDkhqWV7V/Y+GulUjKnA= +SHA256 (cargo/hkdf-0.11.0.tar.gz) = AXBtV41cKBBYSA5nOuQIap9HENjfGtgKWwPjns5fiGs= +SHA256 (cargo/hmac-0.11.0.tar.gz) = KiojIOt+wOvo2o90TXgS2fxMtNCTRKwBiY28tqIK5ps= +SHA256 (cargo/hmac-0.7.1.tar.gz) = XcteZM2kwjEZq0G6lg0eFwp3TI5LnZ5qm8GKq/XllpU= +SHA256 (cargo/hostname-0.3.1.tar.gz) = PHMcPhBQTMjtNc/i8dtMknTD01+khuOzHfRvBo7z6Gc= +SHA256 (cargo/http-0.2.4.tar.gz) = Un6MmsdH4oVCaZqVFReqmmlFr1Bs0fLhtTpXbBe2zBE= +SHA256 (cargo/http-body-0.4.2.tar.gz) = YNqhS+DgeG2w8DqeV8tATJ11bu0rbGK56pjsV0Psdak= +SHA256 (cargo/httparse-1.4.1.tar.gz) = 86h7YW436Twi+xm804bwLzr16piiVnCtD853PeI8Xmg= +SHA256 (cargo/httpdate-1.0.1.tar.gz) = ZFa4psjzP+59lY/NG2DVWxGUCnnmOuhwE+bSLiYDREA= +SHA256 (cargo/hyper-0.14.11.tar.gz) = C2HPLRrrz25jUsl7gdwiRMopGUvhsnb12K1cYzD/+xE= +SHA256 (cargo/hyper-rustls-0.22.1.tar.gz) = X596lzFtRMCvmwMB5lAQVzqFOp/JcEbXMx1/a8D9WmQ= +SHA256 (cargo/hyper-timeout-0.4.1.tar.gz) = u7lYSC6Me+S8PPJyp2aisL8aZ1Xnpq53fwF6MdEbE7E= +SHA256 (cargo/iana-time-zone-0.1.47.tar.gz) = TElfFirwvxdlbQAUoO3tXzzS82X90gRUjChp24k1ncc= +SHA256 (cargo/idna-0.2.3.tar.gz) = QYoKb6uCFHX2NO/jzMRcAT90Lv4D2FPo0zVdXLhQ7Pg= +SHA256 (cargo/indexmap-1.7.0.tar.gz) = vGM2BUVBJd7EtmhDZz8Bx98riUebMuDtY05DqRz/YqU= +SHA256 (cargo/instant-0.1.10.tar.gz) = vuAyixIJ0VfvAByU3YW0+PZBOa2w6sJln0sIOCsvR00= +SHA256 (cargo/itertools-0.10.1.tar.gz) = ad24ifnQ0IpnM4Jx+ptimWvHiMd5alwYzwV0IKrtXq8= +SHA256 (cargo/itertools-0.9.0.tar.gz) = KE8Y+FZR/hHoqZGyrbQssHgyXJlu0CbZlHGe/Pyh1Us= +SHA256 (cargo/itoa-0.4.7.tar.gz) = 3SUDYCGw3oigr/a4UAUVY8ZRbQv1P4Y4k47bud5zJzY= +SHA256 (cargo/itoa-1.0.2.tar.gz) = ESxnjUBQr84jP08oUrsutRkjCzzxLzNYUnVTfX5BV40= +SHA256 (cargo/jni-0.16.0.tar.gz) = IrvcJbSTQLxPw9nJbdhNh4xL7so142Ue+lPbUaaNfU0= +SHA256 (cargo/jni-sys-0.3.0.tar.gz) = jq9LwC0Xy91/9MdDjK/N9/uaRhMxOtEbT4/v59P6ATA= +SHA256 (cargo/js-sys-0.3.59.tar.gz) = JYRRqxCzT4r1NBbR/atywi6AXwySoRNtWUcOwLEROLI= +SHA256 (cargo/lazy_static-1.4.0.tar.gz) = 4qutI/vEKzcA8vJ5hE3IMq2ysusGmy35GPRVxOGMxkY= +SHA256 (cargo/lexical-core-0.7.6.tar.gz) = ZgfGKqFh0j0XqQcsxdoL5nzfyJ06+x6NnIQr68JSX/4= +SHA256 (cargo/libc-0.2.126.tar.gz) = NJ1aWRzSi0nh0QN0cWF6Mt3NpXMbmUGQCAhfctWlODY= +SHA256 (cargo/linked-hash-map-0.5.4.tar.gz) = f7mzivkmCBQLhraTYEuf/MWCQkCkhNHs1HlbrLL+iPM= +SHA256 (cargo/lock_api-0.4.7.tar.gz) = Mn+ltqaUDkaZ7Empvq4epIRca6uTFOT4SsaHQhOdjFM= +SHA256 (cargo/log-0.4.14.tar.gz) = Ubm75sR9Ufw+GpuUWWWUa0xEFCq4eSxQg1qYDTYsJxA= +SHA256 (cargo/log-panics-2.0.0.tar.gz) = rgE2JX3yCSYdqhjWwWOUdXxj4DLieq/YsHeIsFEIK+8= +SHA256 (cargo/lru-cache-0.1.2.tar.gz) = MeJPGtgyHKDooeCsE/I8tmjm9UZsLFcxn2pc8cyOOxw= +SHA256 (cargo/mac-notification-sys-0.5.2.tar.gz) = BC90pgYXXXLKSD4U4Ic/4PbAA/evRYZbF7Fv2vrOcgM= +SHA256 (cargo/malloc_buf-0.0.6.tar.gz) = YruQf+iNVNjZzjKjzOq0IY7S9rfTVhfK/prfhOQ5Gcs= +SHA256 (cargo/match_cfg-0.1.0.tar.gz) = /77oY04NRdJYrLRI5+qrP856CkZzldTZ8ijjwfAfsuQ= +SHA256 (cargo/matches-0.1.8.tar.gz) = f/xcUzhGnU0+oX0mn6jqNRKtJHJHwwvS32nmgwntCgg= +SHA256 (cargo/memchr-2.4.0.tar.gz) = sWvUfZ4ylDXjCcWEaf4HkcLQ0bqW7AlUFSpa4rBDh9w= +SHA256 (cargo/memoffset-0.6.4.tar.gz) = WazMUH8TOANqBHfvYa/a4zzeYIQPTf5IExnOOtEW3fk= +SHA256 (cargo/mime-0.3.16.tar.gz) = KmDHzlAcceA6nJwNNbhhQTrpJb2XnMek4w0GAGmqrI0= +SHA256 (cargo/mime_guess-2.0.3.tar.gz) = JoTUwul9mYSNMLMksAyPzH5ciXt8u1gZsJ58kOi68hI= +SHA256 (cargo/miniz_oxide-0.4.4.tar.gz) = qSUY6YwHhYa8bJNAKK3MpMkqU9apWBlt6DUXCgHYTks= +SHA256 (cargo/mio-0.7.13.tar.gz) = jCvbYxTsEINc0yk90mhHOoNcArezUueIvniLPGymuxY= +SHA256 (cargo/miow-0.3.7.tar.gz) = ufHFsCXNqHb2bvQ6ET+R68n0zO80hDAA4K3267q4TiE= +SHA256 (cargo/mpart-async-0.5.0.tar.gz) = d9sv6n2EOcfmpiFhiQJjXLGEHmLV47F/f8SOLsymtGc= +SHA256 (cargo/multimap-0.8.3.tar.gz) = 5c5G/mSp1zvgfcvmkKOM4bKTvkSP2M4ebBuAYsn3LGo= +SHA256 (cargo/nix-0.23.1.tar.gz) = n4ZjF6y9OiQHEMY/Bl/7Hk/UZiWQRcy1BBMLf2aPNcY= +SHA256 (cargo/nom-5.1.2.tar.gz) = /7QmLSbtg6HAozo4/iuxV5cynIV3DaBea4KN23gmJ68= +SHA256 (cargo/notify-rust-4.5.8.tar.gz) = qZWj0oNM76OJIY56NRVujOVEvJX4NpANoB7gsmoH6dQ= +SHA256 (cargo/ntapi-0.3.6.tar.gz) = P2u5AuQ3tthuA8zhCn4q9mIpLF3+8jtliZ6jrJNUrUQ= +SHA256 (cargo/num-integer-0.1.44.tar.gz) = 0sxpimO1SacLwEcHPSlJzOJ80cewpKhi0IqAMbwoAds= +SHA256 (cargo/num-traits-0.2.14.tar.gz) = mmSx7FzaJYbihHIkhtgCrPH329xiPiv8V+Zcoc0JkpA= +SHA256 (cargo/num_cpus-1.13.0.tar.gz) = BUmfN1ZnHBWIX+6QNERpVv/z8kPWB3uR5XZ98WH3ZrM= +SHA256 (cargo/num_enum-0.5.2.tar.gz) = 5a3wGY1CfuUVM1Y58nXoBsoBrPnwfXzxS7NqEFMqYWk= +SHA256 (cargo/num_enum_derive-0.5.2.tar.gz) = sd71o/adRwfYoECxJ4W5gCmjnoxhCuaFx/YmVml2dII= +SHA256 (cargo/num_threads-0.1.6.tar.gz) = KBnOBB0u4TEDb0/J1q564SWjpA6XumTQT+eZrZ2ru0Q= +SHA256 (cargo/objc-0.2.7.tar.gz) = kVsbRyvCHFNGTWyEYcnTr4Bboe+DfhysJUQo9Kdxd7E= +SHA256 (cargo/objc-foundation-0.1.1.tar.gz) = Gt0bZZ42yWB8equGSnbHpMJ2DNDNLhIPP7i5UsfiK/k= +SHA256 (cargo/objc_id-0.1.1.tar.gz) = yS1N20vXtQ1zDCFf+HF1TQ2msheISfiioqtpcS0MBzs= +SHA256 (cargo/once_cell-1.13.1.tar.gz) = B0hk2iBrSXO4TrkWgwINvv1qjD8POOBU2TlU6JGTXk4= +SHA256 (cargo/oncemutex-0.1.1.tar.gz) = RNEd5Gb0owBv6KXn7ITpO3nHDLmSrgqg62Ma0t+Kv+I= +SHA256 (cargo/opaque-debug-0.2.3.tar.gz) = KDnnlmXxMb21eC5R8sbJWZwTPGCYmCpUx5Q1i/QyUpw= +SHA256 (cargo/opaque-debug-0.3.0.tar.gz) = YkqDQMOMG4D9VJCHhi2kukPgiFivAlsjblCbZkn8E9U= +SHA256 (cargo/opener-0.5.0.tar.gz) = TqPrzXKlRwH1Y0XxZ4Wm06wt9+mG0nPrQ5XAsB2xeVI= +SHA256 (cargo/openssl-probe-0.1.4.tar.gz) = KJiNhyq3YJWm5qyI2ZtU/SZ3AnNP1//mEMon9TPduVo= +SHA256 (cargo/ordered-stream-0.0.1.tar.gz) = RGMMBZ6s/W4IvapRsdss4zEZyqTdwSNekjEJql8lzLE= +SHA256 (cargo/parking-2.0.0.tar.gz) = Qnw4kvnng9kcwSgoUofnClniBspFJ3Ds6Ip296Pt3XI= +SHA256 (cargo/parking_lot-0.11.1.tar.gz) = bXdErAKd8i3KYoTv5OiYmR0o4whccGyXK819pKJ6Fes= +SHA256 (cargo/parking_lot_core-0.8.3.tar.gz) = +np4KTjnRXY/5pB/xrqGlG1y9J/n4h3gdOCBKKmfsBg= +SHA256 (cargo/percent-encoding-2.1.0.tar.gz) = 1P1WQdAcjxiiPae2/ikpj/S1WvzM33iXOyTPMXX+4y4= +SHA256 (cargo/petgraph-0.5.1.tar.gz) = Rn0WSm3lYnC9fE0HDfgdB76s4lAS1RA87U6f8I1q/bc= +SHA256 (cargo/petgraph-0.6.0.tar.gz) = ShOi+p0LY+XyIyiCh0HlI3Zv/w7p53kxaQIpDf8/gk8= +SHA256 (cargo/phf-0.8.0.tar.gz) = PfthIy40/LYz9D0SxY+Dwd+Cli3N+lZaToZv/Bfa/hI= +SHA256 (cargo/phf_generator-0.8.0.tar.gz) = FzZ/DMhvLSWAKywm7linsj+uzPeKOWCUwT3O0NAYJSY= +SHA256 (cargo/phf_macros-0.8.0.tar.gz) = f2/eGP9Cn/yP544r9/i3paWm4qi1i8WprGkZi72pGJw= +SHA256 (cargo/phf_shared-0.8.0.tar.gz) = wAz4uer+aN3l6eqizvjuhKkzakfVZuxVyhZYljO2Wvc= +SHA256 (cargo/phonenumber-0.3.1+8.12.9.tar.gz) = EmGgFOX14Ei/LG8acvpeTCIwCdxfKWo4W5X+GbRkYI8= +SHA256 (cargo/pin-project-1.0.7.tar.gz) = x1CcwQYEHECkUY0q96YVMOHu0OYoUpaj2MVHKAbMxKQ= +SHA256 (cargo/pin-project-internal-1.0.7.tar.gz) = SMlQEyWDtQBVax79cdRbMZAp8rcVGNl5/MII4WtCQm8= +SHA256 (cargo/pin-project-lite-0.2.7.tar.gz) = jTHRHGmmtSoXS0K9wMMOXhFnD5B4iyxHHDHB0X1ElEM= +SHA256 (cargo/pin-utils-0.1.0.tar.gz) = i4cNjBUbby+5PoShMUYTjwXQLtEcfnxU+IJqqvfJ8YQ= +SHA256 (cargo/polling-2.1.0.tar.gz) = kjQdd5+jTqhDfvTYLUQNXhzj8/9/gkqmRCTNSB+aHyU= +SHA256 (cargo/polyval-0.5.1.tar.gz) = 5ZdFDL8gl4fw5t6AvzeVxrI1ajgO6Hg3tUWt7Y28GCM= +SHA256 (cargo/ppv-lite86-0.2.10.tar.gz) = rHTGJNay0h9CX3UiYvQhiDZde4/xr/dMguRRNlEKSFc= +SHA256 (cargo/proc-macro-crate-1.0.0.tar.gz) = Qf29HfYhVvvFlF9HYmMlZNfQOBUwkcP88QZ/au98/5I= +SHA256 (cargo/proc-macro-error-1.0.4.tar.gz) = 2iVJD/mJKqs/z3w28Iz7kC3T5xyg+flRe+oCpzpc44w= +SHA256 (cargo/proc-macro-error-attr-1.0.4.tar.gz) = ob5AGA5S7MmK2AsYSTS689DSn5eVdOQ5r1pVJ0s1+Gk= +SHA256 (cargo/proc-macro-hack-0.5.19.tar.gz) = 2/DEi8HZE3WuXDzYHjci3/Grz4GjCWAkBkDSI/Wf4OU= +SHA256 (cargo/proc-macro-nested-0.1.7.tar.gz) = vIgbLCJoE3DGp4DkevmEDvhBg3vJgRhDHU4YaL0MEIY= +SHA256 (cargo/proc-macro2-1.0.27.tar.gz) = 8NjK9ymGwaWYcmrcmIu1mEeS74T17lqlAgkUXugHcDg= +SHA256 (cargo/prost-0.8.0.tar.gz) = 3l4lM/WdCPzzZP03Tr2gaSpwvW1+Zu+X8wb0XGxdgCA= +SHA256 (cargo/prost-0.9.0.tar.gz) = REh5J1y0/YSVixodVCDRXm/PfCNf5H8FPJwqgKzrYAE= +SHA256 (cargo/prost-build-0.8.0.tar.gz) = NV9jS0PN2Ack7nhI+Vdw5+cO76bc8U/qZ2IWVzuP1gM= +SHA256 (cargo/prost-build-0.9.0.tar.gz) = YpQXIvtnXUY2WeScTz/h/nkv8k/lu6qcCM07mKHDVPU= +SHA256 (cargo/prost-derive-0.8.0.tar.gz) = YA0vM0qgWssCp1XiF+8att6k1RtYt4RliLdH7ewE77o= +SHA256 (cargo/prost-derive-0.9.0.tar.gz) = +cwaMmPgfgv2jpYmjzdmUge0lWDZhzlmLN+q4hXHIP4= +SHA256 (cargo/prost-types-0.8.0.tar.gz) = YDu9Y5RwHRPz8lqtpZx96dNaaliHz8FWGBI0pEACdxs= +SHA256 (cargo/prost-types-0.9.0.tar.gz) = U0t6DoNuPEgtJpMHD5guOedhHalpXU0fWksYa1H67wo= +SHA256 (cargo/pulldown-cmark-0.8.0.tar.gz) = /63gJJXyJFPNWTFZ6i9Zgnquf1P6gyP3VnmbZwiB3Pg= +SHA256 (cargo/qr2term-0.2.2.tar.gz) = ljRHjodNQVPFLRDW+GYK0bF75dWkiqcobz1S/SybfDQ= +SHA256 (cargo/qrcode-0.12.0.tar.gz) = FtLxRV82MMblEHtPK5TnTXbeqAc23gmB/SdkQhbP9X8= +SHA256 (cargo/quick-xml-0.18.1.tar.gz) = PMRA7kgCqG41cWUCHj4lWpFDck2jHbHi6lQCFMlqD4I= +SHA256 (cargo/quickcheck-1.0.3.tar.gz) = WI9jeOTdmUWLYOwnW0R3rdQc5PqfZNy6bxWtzLGbUNY= +SHA256 (cargo/quickcheck_macros-1.0.0.tar.gz) = sippMiLXFqlYd4bzesP2tPrttbgMI5FOcwP/Wh2AFuk= +SHA256 (cargo/quote-1.0.9.tar.gz) = w9C5dF3C3r9QfIQi3gXXImzB8GRCFt/f6tmI+bGrMqc= +SHA256 (cargo/rand-0.7.3.tar.gz) = amsWedSbJLv+DIA0KaoYdEcvUNmzYxMfDon8NWtUTQM= +SHA256 (cargo/rand-0.8.4.tar.gz) = LnVzYy5kVM9rmdeqxMzKVL4G2gWsou90I9ItJ9TUvNg= +SHA256 (cargo/rand_chacha-0.2.2.tar.gz) = 9MjthWJ5yXNyBr9yW/NpNdhmbq16pptSvlWvNp0ZNAI= +SHA256 (cargo/rand_chacha-0.3.1.tar.gz) = 5sEKY6D6MiUr5J0h53CdTUuvjSMcLbzh6qgUG5sSfYg= +SHA256 (cargo/rand_core-0.5.1.tar.gz) = kL3lKW/IkbDO8SptA93MwWLOeyr/VBYK+TOPjUDfbRk= +SHA256 (cargo/rand_core-0.6.3.tar.gz) = 008UCPVSlEU3kMSLLx67scW0t1Y+sfQYvPz9uwbrtOc= +SHA256 (cargo/rand_hc-0.2.0.tar.gz) = yjEpr3uSoXES1ZrUmMb4Hq9GMlN2a5A5bTnqejnWYTw= +SHA256 (cargo/rand_hc-0.3.1.tar.gz) = 1R6fWW3iJ/2i6myEYH9VWOGW7q9DyYa3JLpPuP30l+c= +SHA256 (cargo/rand_pcg-0.2.1.tar.gz) = FqvQwbY56etNfFDAuBALDQ+Em+I0mCnHQP6ObrSBZCk= +SHA256 (cargo/redox_syscall-0.2.9.tar.gz) = WrSaut8/nhxLxJnohF4VKth9KtLTA3GEEXEWnp11/u4= +SHA256 (cargo/redox_users-0.4.0.tar.gz) = UoUy89gByHrsne8q3ZyoAv5WnkSlRK/mM3ZSZ4QKvmQ= +SHA256 (cargo/regex-1.5.6.tar.gz) = 2D8SfZS9vNpMjMLlD2+E9LYR9pyQJpnKOFo5w6dfn/E= +SHA256 (cargo/regex-automata-0.1.10.tar.gz) = bCMNc/uNjBucCzE1xRQqis7joFWPuNtc8ctl+NeGITI= +SHA256 (cargo/regex-cache-0.2.1.tar.gz) = L3ti1pdDuLlPNTtrfD3rTFWCgoMovLjV/t8hQ3OAh5M= +SHA256 (cargo/regex-syntax-0.6.26.tar.gz) = SbPensXcCjQX2jcaqxfXKZl8FQEOf9JP9wd3OjO922Q= +SHA256 (cargo/remove_dir_all-0.5.3.tar.gz) = Os0SVmVCKXOjOsnT3S34XtrQ9K6bANr7GgXkOp9e+Oc= +SHA256 (cargo/ring-0.16.20.tar.gz) = MFPPUuI2o+10bfx0WqnKzxt5HYRr2vQS9gqNfW4XyPw= +SHA256 (cargo/rustls-0.19.1.tar.gz) = Ne22df7uOa7JyZ+l/5hQgZlaBtWUEUrhTL55ete3ptc= +SHA256 (cargo/rustls-native-certs-0.5.0.tar.gz) = Wge3wYhb2O04McKJt4cLE+9G/g6FbSiMMNnMF9daIJI= +SHA256 (cargo/ryu-1.0.5.tar.gz) = cdMB1Bk9Axq915/3491yEWipVy7z/lGhUXq6I1vY+G4= +SHA256 (cargo/same-file-1.0.6.tar.gz) = k/wdw6qpv+2V4C5urau0uvfjB4sL0bTXtrC2g3iQBQI= +SHA256 (cargo/schannel-0.1.19.tar.gz) = jwW6YJwjTmC+4NVH/pSkx+nacz0cliz25Z76TNnIvHU= +SHA256 (cargo/scopeguard-1.1.0.tar.gz) = 0pqwxtP8Dukv5m4tmfcA6rF6jVfRwdO3SDgPsguqeM0= +SHA256 (cargo/sct-0.6.1.tar.gz) = s2K4OJjg5p84UVuC7hWqgGNr7+R8O209iakR54/CKM4= +SHA256 (cargo/security-framework-2.3.1.tar.gz) = I6KshRR6OhHXfs8bxxZuwLkv6/pEYcN5ROGA8xns5Gc= +SHA256 (cargo/security-framework-sys-2.3.0.tar.gz) = fk7/uRtLi2+3cy5nC2zuFgJ4/45r9IXHgF2eMZ124oQ= +SHA256 (cargo/semver-1.0.3.tar.gz) = XzqsV+5/MnLYOVxuT1AvQ08OKJ/NYodvcNqgCMINyr4= +SHA256 (cargo/serde-1.0.126.tar.gz) = 7HUFq+rK7HSuR3jZ2TKP5aXQQlMiCoXE7gIiOfyZbQM= +SHA256 (cargo/serde_derive-1.0.126.tar.gz) = ljp9vJiVrqx6yQ5080pdUmGCj3nfNcvtQeEBidOATUM= +SHA256 (cargo/serde_json-1.0.64.tar.gz) = eZ6X3J/a42pci48srpzi7p/c4gWMV6k+YJnZGf2YL3k= +SHA256 (cargo/serde_repr-0.1.7.tar.gz) = mNBRaQBRjCnvohfCmPofTmxv/IWuKf1/TuSPF24antU= +SHA256 (cargo/sha-1-0.9.6.tar.gz) = jEz6dBxYMtDvf6tGyr7SnCqukm2wsRuyBp7djbXmThY= +SHA256 (cargo/sha1-0.6.1.tar.gz) = wdoFyXRFyqEtBehIxKT8u+op50isKPfoDpsBA5IGN3A= +SHA256 (cargo/sha1_smol-1.0.0.tar.gz) = rhpHGGwDoyF3BC5V28X9Wu6QC44AaajXD7qWqTdc0BI= +SHA256 (cargo/sha2-0.8.2.tar.gz) = olb0bqeKDA2f8AB3UEkDrIgaHa/cINpmVFaZ53drPmk= +SHA256 (cargo/sha2-0.9.5.tar.gz) = s2KuV1L9ITdzH5+iX9TZBYrzRmbKGWb7lpEZzDVxnxI= +SHA256 (cargo/sharded-slab-0.1.4.tar.gz) = kA+6gG9wxjCwo4LQ2CXheg8Z/NBZoq3h/yN7zd9EazE= +SHA256 (cargo/signal-hook-0.1.17.tar.gz) = fjHUQsFvBHpnG1px4hYdbmiBQBK39TedJp69kV+sJyk= +SHA256 (cargo/signal-hook-registry-1.4.0.tar.gz) = 5R5zMo3ErAx8y9o6SU36A98d4vRgGBJ/YMaT8mSEVbA= +SHA256 (cargo/siphasher-0.3.5.tar.gz) = y85tRQfH5KOWIJFDblbpUpDLcfowLQ0nDjITC3X7/yc= +SHA256 (cargo/slab-0.4.3.tar.gz) = 8XOsPRp+OygAP0DeC1zn/icQ+bncP8OGZM6+5Gs7ZSc= +SHA256 (cargo/sled-0.34.6.tar.gz) = HQEy8+OTvLc5DGC7RXaUmM9FULy3oh1/lcArafY2LNw= +SHA256 (cargo/smallvec-1.6.1.tar.gz) = /g83yejzxaSmatZVqTx02qxK0AxEFTO/XG55kLtCYE4= +SHA256 (cargo/smawk-0.3.1.tar.gz) = 9nrSJHZ/qjx9i22RmFt45woTJECKvLHPzCvkwGvAYEM= +SHA256 (cargo/socket2-0.4.0.tar.gz) = nj38IHxSYBXGMkcqd74JzxtuRoZlga7K5cw4+0I13qI= +SHA256 (cargo/spin-0.5.2.tar.gz) = bmPP8yCuLFeQRnm6fLYygKPcRhOIW+r7FI7nv5qpBC0= +SHA256 (cargo/static_assertions-1.1.0.tar.gz) = ouuTSbZESzJocuFA6xz158UiFU1p56D/sPuBwGs3VD8= +SHA256 (cargo/strsim-0.8.0.tar.gz) = jqURnNtMVbVdQyq7UToEKThIeMFd3mDMd7HJneGpWmo= +SHA256 (cargo/structopt-0.3.22.tar.gz) = abBBzctnImrKMH5ue+RMiAZCPYPgGL1mI2CpPavOTXE= +SHA256 (cargo/structopt-derive-0.4.15.tar.gz) = eBOTSuz19RpUd14ABowjfemEiUY5aCMaUXRru8A/nBA= +SHA256 (cargo/strum-0.22.0.tar.gz) = 96yJPH1HHIoh8xz+IT7E9tmv7tJVN8dy4I7z8AX4cp4= +SHA256 (cargo/strum_macros-0.22.0.tar.gz) = M595nYtUnjdEx6x/6yFjg+QAXZS9siVhs6uPO4CK6fs= +SHA256 (cargo/subtle-1.0.0.tar.gz) = LWelpium4ByyGS/zCTJMtIddDEUdVf4jGUM6vnoFqO4= +SHA256 (cargo/subtle-2.4.1.tar.gz) = a97zLoFQwqCBEQtCdy/+fXyQMrYGvCJsgmD9l+CXZgE= +SHA256 (cargo/syn-1.0.73.tar.gz) = 9xSJ/zADDSrlmFJPYTJrkCRm9yoPsahWTAAcxjQlvMc= +SHA256 (cargo/synstructure-0.12.5.tar.gz) = R0qqkm+qFgPEC3iFqerqKbRE0csoUMt8Dje7GkGC9Po= +SHA256 (cargo/tar-0.4.38.tar.gz) = S1WAfANE4ebATXyWX1KJw5qNlK4j7VwLV6q6xUn4ccY= +SHA256 (cargo/tempfile-3.2.0.tar.gz) = 2sHGY8/JOBD4iu2biUHUjKv4VqGxEcKaQEOQGNhw6yI= +SHA256 (cargo/textwrap-0.11.0.tar.gz) = 0yZhD0CMek629Rw3wzDklrCFBslFfJ00KH7MOICfsGA= +SHA256 (cargo/textwrap-0.14.2.tar.gz) = AGbI0Sr4tazSHgBUfDeX/eToZ3JUp+5CkXbM676T3YA= +SHA256 (cargo/thiserror-1.0.30.tar.gz) = hUur5S5N8WU3BrmPz8BYQwEAObQGh1kwpw5NlkTlxBc= +SHA256 (cargo/thiserror-impl-1.0.30.tar.gz) = qjL9P2J/Nn/hb4k+JZeuPAUCD4u6Jmak5upz03flcUs= +SHA256 (cargo/thread_local-1.1.4.tar.gz) = VRbCe3gxHFC/QsBxQlxWCseZsRwwsx+H4wgZZf5eAYA= +SHA256 (cargo/time-0.1.44.tar.gz) = bbnmkUq4sa4cJgpK56SbbFYRtAMopzWyGGJWdoXnMlU= +SHA256 (cargo/time-0.3.9.tar.gz) = wnAuCKeoYPAFgmxoFdysEBsZteszDCf+Slko/sHSDd0= +SHA256 (cargo/tinyvec-1.2.0.tar.gz) = W1Ig8Fu33n8/U8fAZeEZmzFyaW/i25+cTYrZtO50w0I= +SHA256 (cargo/tinyvec_macros-0.1.0.tar.gz) = zadNp+GmZPeVux+Kh+xAb7iaAlIs9uUGINAWrdbbv1w= +SHA256 (cargo/tokio-1.16.1.tar.gz) = DCemS2Jd5tMJ6MV3FrqTAh3M8bO1yX7dbT3S0hNa/Ao= +SHA256 (cargo/tokio-io-timeout-1.1.1.tar.gz) = kMSfEGviQN4VRXHdMfvkissQumxt1vZRetYDq/+kLek= +SHA256 (cargo/tokio-macros-1.8.0.tar.gz) = lyT5qXX7mH73o82b4DUO3L4TBpivW496Yx4j1C0FJIQ= +SHA256 (cargo/tokio-rustls-0.22.0.tar.gz) = vGhE3nLlffGYAFSzi+Op9HAqukhYvmTdcAGBqKbQ4bY= +SHA256 (cargo/tokio-stream-0.1.7.tar.gz) = ey8/aYJT8DEZrAECvqpk9npn4IB00Doi0YeEEEVDcn8= +SHA256 (cargo/tokio-util-0.6.7.tar.gz) = HKoLDI2UoEnbVrWs+MupncBiOqsbJtW19eLZRYRrNZI= +SHA256 (cargo/toml-0.5.8.tar.gz) = oxFClwgmcz34JB7zXcBA75jGeasU18PlTYJwmbOs7Ko= +SHA256 (cargo/tower-service-0.3.1.tar.gz) = Ng39HW0w4F/aMqziyMcOnAqdpxMnV3f1pNu4oYk5MMY= +SHA256 (cargo/tracing-0.1.35.tar.gz) = pADjGqYLnUSlKo7gNDtbGFZrA6gyHg0yH2lc9W6UAWA= +SHA256 (cargo/tracing-appender-0.2.2.tar.gz) = CdSPcaeRY4UZUFzvr+FiYG9wbCVZLkveTZdgDAGVMS4= +SHA256 (cargo/tracing-attributes-0.1.21.tar.gz) = zGuK01Z0mfmKHbenUrB6fIx8fDTDMuwA7/srACeXS3w= +SHA256 (cargo/tracing-core-0.1.27.tar.gz) = dwlZW4h4pJZc5eh+v4gKfTnJr8aDdyGyGlqBaoEX2SE= +SHA256 (cargo/tracing-log-0.1.3.tar.gz) = eN2tM9LRCx7X650fUYpWdHE4dul+W7m3NFp5hPu0+SI= +SHA256 (cargo/tracing-subscriber-0.3.11.tar.gz) = S8KPk7r/OAN/ZOb0PTTPoWBfJ6ScNOigTF54sLq/JZY= +SHA256 (cargo/try-lock-0.2.3.tar.gz) = WVR7znHZw4uD2cDpK2BmxCUzcfFQBd7www2WV/UMdkI= +SHA256 (cargo/tui-0.15.0.tar.gz) = hh2POtMU7eYhm8squEQFSx3iee43qbw449YG+dP7KnE= +SHA256 (cargo/tungstenite-0.15.0.tar.gz) = mD1AdHvOh40vtn2RDcuL0+yisjWFQMPMG5jAJ0B6OuM= +SHA256 (cargo/twoway-0.2.2.tar.gz) = xX/7Rg18JM1u2kNpQRAYkDCj0d/kGEFtlGj9HB0pC0c= +SHA256 (cargo/typenum-1.13.0.tar.gz) = h59pBkkqfNIVv6TPWVtgAUbM+sDHm8vR8wABYq9eiwY= +SHA256 (cargo/unchecked-index-0.2.2.tar.gz) = 7rqG1CLOGBpxlEXlGHL6MPH3QTtivstS6V7JGqJi2Fw= +SHA256 (cargo/unicase-2.6.0.tar.gz) = UPN75hd5RgKqu+7gvk8lncF3j6vgXi1n7o95Mm1ctPY= +SHA256 (cargo/unicode-bidi-0.3.5.tar.gz) = 7ri+IJuxyWt8F3x0INJuBOzKyw7q5rmA41/LdGeBB+A= +SHA256 (cargo/unicode-linebreak-0.1.1.tar.gz) = BaMfRdGKMhO5GAGfeP5qc6FKuJaAfwqvViKqBoR0lFU= +SHA256 (cargo/unicode-normalization-0.1.19.tar.gz) = 1UWQkylBqekmbwgy3u2E6+G/LkyeSjVU05PRj16FS/k= +SHA256 (cargo/unicode-segmentation-1.8.0.tar.gz) = iJWEmpSeeEXga9bcGqUXMaEDxCcHAQpbWRwAOPtzOFs= +SHA256 (cargo/unicode-width-0.1.8.tar.gz) = kzdZGJOhm4jY2H8s7B5z+tXN/RDlpvNJ9JitbqL/seM= +SHA256 (cargo/unicode-xid-0.2.2.tar.gz) = jMuC1h+ApmPv4feHpRsWtaUeMxTWrDZbCGOfUjh7M/M= +SHA256 (cargo/universal-hash-0.4.0.tar.gz) = gyayxlSTLj5PkZbmnQj998/XGOHcb2azR+YCSgyWFAI= +SHA256 (cargo/unreachable-1.0.0.tar.gz) = OCgQh3/kSJkd/H8N1uOuXVgIj9DqXjUYllX4TmgU+lY= +SHA256 (cargo/untrusted-0.7.1.tar.gz) = oVbGhMkep9YmJlCbzjy04dntXE2Xj3tDUmWPlqTCa0o= +SHA256 (cargo/url-2.2.2.tar.gz) = pQfDg7LTO1/DXRhh535rOD0Viy2l4U/lG4Pf7fb9V4w= +SHA256 (cargo/utf-8-0.7.6.tar.gz) = CcyO5y0qm+zy8v6+AgW77Y/GYVt8tCmtBi3Ht93QNqk= +SHA256 (cargo/uuid-0.8.2.tar.gz) = vFz5jYGGJEQUyEgBfw4mdrP8tGgH9maKl9/mc1mjxLc= +SHA256 (cargo/valuable-0.1.0.tar.gz) = gwt+XU2QA0AylA5Kzg2amgV+ekXNlObAB4MuOe24L20= +SHA256 (cargo/vec_map-0.8.2.tar.gz) = 8b3fEYe+aS55xf/quJETLfsPI27TakPH7TnxFl7iAZE= +SHA256 (cargo/version_check-0.9.3.tar.gz) = X+zcqaUpHMK43PfcAkU/7nkaKA83Q8sJBfiCKuRjs/4= +SHA256 (cargo/void-1.0.2.tar.gz) = agLkiF7TvA8t6Q6m3UXry7ZtrP/gNUf627DuridwiH0= +SHA256 (cargo/waker-fn-1.1.0.tar.gz) = nVssYrQBKj4eylp+B30Ts79JjEBz4zzNWGJmB3SM7so= +SHA256 (cargo/walkdir-2.3.2.tar.gz) = gIzyc1zUtoZhE/ZIt5HGrcVxRTe8Ii2TR7sgM4b/2lY= +SHA256 (cargo/want-0.3.0.tar.gz) = HOipaMsc0RDRNv+LgZpVbW+22Rk2PGFTT2hgx+sXK6A= +SHA256 (cargo/wasi-0.10.0+wasi-snapshot-preview1.tar.gz) = GhQ1l8p8d5Pv95Te81LUF5KpPEgesQQkI/9/9yuiwx8= +SHA256 (cargo/wasi-0.9.0+wasi-snapshot-preview1.tar.gz) = zM3fMlVP7MastYX4KjKnLii0j4xMGIPd/u6qlvfY5Rk= +SHA256 (cargo/wasm-bindgen-0.2.82.tar.gz) = /HZS4/bEcGyNnNVIMsSkzLm1M24sO9FU1czPvxwfX30= +SHA256 (cargo/wasm-bindgen-backend-0.2.82.tar.gz) = ZizUSAVYa9UpcblYax34XNu9kRLk702PQVWcM03GrD8= +SHA256 (cargo/wasm-bindgen-macro-0.2.82.tar.gz) = smDxPTASBx37FRKEnAM7GSUDg3OupIztMBLAnflSxgI= +SHA256 (cargo/wasm-bindgen-macro-support-0.2.82.tar.gz) = W+jmVL3Zt5IWwpKauQchqoL69lxIzfCL3E5/UTV7gNo= +SHA256 (cargo/wasm-bindgen-shared-0.2.82.tar.gz) = ZZjdC9PH1RCV/2UxpbI+AqzcgYBOMNjwevt3tyFaFAo= +SHA256 (cargo/web-sys-0.3.51.tar.gz) = 6ChBezefPfcRHToqnldTcGyuKcQffEAp7p/Xfz4J5YI= +SHA256 (cargo/webpki-0.21.4.tar.gz) = uOOMBggmLEbUpWIC66vesJTO9+VgynoibGvwVRiKpOo= +SHA256 (cargo/wepoll-ffi-0.1.2.tar.gz) = 10P97cXGQ3e1/CvANrAcf9ZCIFoNljVgNK40BNSet/s= +SHA256 (cargo/which-4.1.0.tar.gz) = tVVR5Cy98s4r7dIgPQzAjboALCdRD4battDOMEy6Pf4= +SHA256 (cargo/whoami-1.1.2.tar.gz) = SrrPMlyVjf6vEEaTHTfyqQG23+CWjullop6UxnZrKvY= +SHA256 (cargo/winapi-0.3.9.tar.gz) = XIOaZ0/NepiVLlkyQupACr6TmSdGdh44ZBQF0osA9Bk= +SHA256 (cargo/winapi-i686-pc-windows-gnu-0.4.0.tar.gz) = rDuHxjYgQm3ZuZHlzgMp7/VFvMu7NPO+Cf9vtqtRt7Y= +SHA256 (cargo/winapi-util-0.1.5.tar.gz) = cOxs6FuxWBUcrl5ch/lajpfSwMSwASI/M6M0485d4Xg= +SHA256 (cargo/winapi-x86_64-pc-windows-gnu-0.4.0.tar.gz) = cS4ieEHQV8HuHNL7Ivp+WlRhro5I+iynnsQs/BkxGD8= +SHA256 (cargo/windows-0.24.0.tar.gz) = qfOTRa4MirBywKx/6Ki0EWNqo0+Jvhnd0NkiZUTxOUQ= +SHA256 (cargo/windows_i686_gnu-0.24.0.tar.gz) = wIZlEKPsqa7XOgd0kLu/A+XqrE4f1whJ2JU55YMFAf0= +SHA256 (cargo/windows_i686_msvc-0.24.0.tar.gz) = vw/+1Wt+k2mikHjSqzquzupI61iZnSz/OqJJSidblcY= +SHA256 (cargo/windows_x86_64_gnu-0.24.0.tar.gz) = OEoXNjBYgEQgWimTtoZKL1blqMHnZowHuT7BjPSIjcQ= +SHA256 (cargo/windows_x86_64_msvc-0.24.0.tar.gz) = m9jwYtjKVEY1gVnXmpC+EsVDs6llyEfI8+7fFLMh05k= +SHA256 (cargo/winrt-notification-0.5.1.tar.gz) = AHoDU4QLI+DG3HPluWL/WO1/a8nO/zzn/m+62NSW7fQ= +SHA256 (cargo/x25519-dalek-1.1.1.tar.gz) = WgwQUVIQfjuW9qAKZehs6C2bElIw4cQwKUDspY/3H08= +SHA256 (cargo/xattr-0.2.2.tar.gz) = JEw3QfQkDvRidIYDl8fHTlDrI2JJlpMOSEwWZ5YzpUw= +SHA256 (cargo/xflags-0.2.2.tar.gz) = oluFyg/PLQA/Kwz9znOJfFTsPXk9/gCKZN5QQCCTY8k= +SHA256 (cargo/xflags-macros-0.2.2.tar.gz) = AAVSCNiDnxFokBL+y0K7wCTiW/OvkbO5h5c5082mW/A= +SHA256 (cargo/xml-rs-0.8.4.tar.gz) = 0tfTlIYT91yY/ZMoz9zEWsxNNgZVKJ0KfU7JMTkiAKM= +SHA256 (cargo/xshell-0.1.14.tar.gz) = xkA2LxsVDhhrduiGBuSwGnsvHVbMUPzBhN22g/tWfCM= +SHA256 (cargo/xshell-macros-0.1.14.tar.gz) = BgfAlclsHYQgzkoBiglU+xXXPV61m1IaBaDwTP/AUFk= +SHA256 (cargo/zbus-2.1.1.tar.gz) = e7hvPUWS4mpIsnGXQq7JT4rmI4694g2YGD7hhdEnXpo= +SHA256 (cargo/zbus_macros-2.1.1.tar.gz) = NoI8wQ/dw8axnwSJAyYtrK+CdBcOmiVXhL3YtFcKgEA= +SHA256 (cargo/zbus_names-2.1.0.tar.gz) = Rd/Nz4e3Ha1QXTDMJ7G3uIpkttHENWSPSPnbwf3Et+E= +SHA256 (cargo/zeroize-1.3.0.tar.gz) = R1b32z97VXSTjD6xwRcDi44H+V7mcYwO+tSsIVCPHv0= +SHA256 (cargo/zeroize_derive-1.3.2.tar.gz) = P48YdkHa1PaA0lxL/EIltBgWWYQXnybKduxPtkQdOhc= +SHA256 (cargo/zvariant-3.3.0.tar.gz) = 43TG/IyEvVOSKBKF7JrAA7ChFZ2YXY6T6hfIeW0DNU0= +SHA256 (cargo/zvariant_derive-3.3.0.tar.gz) = r0BiVSsT8Ql7XlOsc2nDTv7lkS/cGcdoBSRPXk7V+g4= +SHA256 (gurk-rs-0.2.5.tar.gz) = 6kVJP1rLAd/+F+Snq/j/mYAqgHP3ffafQG/pphpxLWM= +SIZE (cargo/adler-1.0.2.tar.gz) = 12778 +SIZE (cargo/aead-0.4.2.tar.gz) = 14654 +SIZE (cargo/aes-0.7.4.tar.gz) = 128509 +SIZE (cargo/aes-gcm-0.9.2.tar.gz) = 148403 +SIZE (cargo/aes-gcm-siv-0.10.1.tar.gz) = 26723 +SIZE (cargo/aho-corasick-0.7.18.tar.gz) = 112923 +SIZE (cargo/android_system_properties-0.1.5.tar.gz) = 5243 +SIZE (cargo/ansi_term-0.11.0.tar.gz) = 17087 +SIZE (cargo/ansi_term-0.12.1.tar.gz) = 24838 +SIZE (cargo/anyhow-1.0.42.tar.gz) = 34827 +SIZE (cargo/arrayref-0.3.6.tar.gz) = 10035 +SIZE (cargo/arrayvec-0.5.2.tar.gz) = 27838 +SIZE (cargo/ascii-0.9.3.tar.gz) = 28283 +SIZE (cargo/async-broadcast-0.3.4.tar.gz) = 18539 +SIZE (cargo/async-channel-1.6.1.tar.gz) = 12574 +SIZE (cargo/async-executor-1.4.1.tar.gz) = 15490 +SIZE (cargo/async-io-1.6.0.tar.gz) = 32282 +SIZE (cargo/async-lock-2.5.0.tar.gz) = 15656 +SIZE (cargo/async-recursion-0.3.2.tar.gz) = 10774 +SIZE (cargo/async-task-4.2.0.tar.gz) = 28496 +SIZE (cargo/async-trait-0.1.51.tar.gz) = 25531 +SIZE (cargo/async-tungstenite-0.15.0.tar.gz) = 31533 +SIZE (cargo/atty-0.2.14.tar.gz) = 5470 +SIZE (cargo/autocfg-1.1.0.tar.gz) = 13272 +SIZE (cargo/base64-0.12.3.tar.gz) = 57545 +SIZE (cargo/base64-0.13.0.tar.gz) = 62070 +SIZE (cargo/bincode-1.3.3.tar.gz) = 28958 +SIZE (cargo/bitflags-1.2.1.tar.gz) = 16745 +SIZE (cargo/block-0.1.6.tar.gz) = 4077 +SIZE (cargo/block-buffer-0.7.3.tar.gz) = 7179 +SIZE (cargo/block-buffer-0.9.0.tar.gz) = 7108 +SIZE (cargo/block-modes-0.8.1.tar.gz) = 16961 +SIZE (cargo/block-padding-0.1.5.tar.gz) = 7342 +SIZE (cargo/block-padding-0.2.1.tar.gz) = 7672 +SIZE (cargo/bstr-0.2.16.tar.gz) = 330346 +SIZE (cargo/bumpalo-3.7.0.tar.gz) = 134261 +SIZE (cargo/byte-tools-0.3.1.tar.gz) = 5526 +SIZE (cargo/byteorder-1.4.3.tar.gz) = 22512 +SIZE (cargo/bytes-1.0.1.tar.gz) = 48142 +SIZE (cargo/cache-padded-1.1.1.tar.gz) = 8798 +SIZE (cargo/cassowary-0.3.0.tar.gz) = 22876 +SIZE (cargo/cc-1.0.69.tar.gz) = 56044 +SIZE (cargo/cesu8-1.1.0.tar.gz) = 10555 +SIZE (cargo/cfg-if-1.0.0.tar.gz) = 7934 +SIZE (cargo/checked_int_cast-1.0.0.tar.gz) = 2669 +SIZE (cargo/chrono-0.4.22.tar.gz) = 185570 +SIZE (cargo/cipher-0.3.0.tar.gz) = 12756 +SIZE (cargo/clap-2.33.3.tar.gz) = 201925 +SIZE (cargo/combine-3.8.1.tar.gz) = 103773 +SIZE (cargo/concurrent-queue-1.2.2.tar.gz) = 15859 +SIZE (cargo/core-foundation-0.9.1.tar.gz) = 25985 +SIZE (cargo/core-foundation-sys-0.8.3.tar.gz) = 17519 +SIZE (cargo/cpufeatures-0.1.5.tar.gz) = 10419 +SIZE (cargo/crc32fast-1.2.1.tar.gz) = 38172 +SIZE (cargo/crossbeam-channel-0.5.5.tar.gz) = 90326 +SIZE (cargo/crossbeam-epoch-0.9.5.tar.gz) = 43883 +SIZE (cargo/crossbeam-utils-0.8.9.tar.gz) = 39818 +SIZE (cargo/crossterm-0.19.0.tar.gz) = 104572 +SIZE (cargo/crossterm_winapi-0.7.0.tar.gz) = 15187 +SIZE (cargo/crypto-mac-0.11.1.tar.gz) = 9551 +SIZE (cargo/crypto-mac-0.7.0.tar.gz) = 7636 +SIZE (cargo/ct-logs-0.8.0.tar.gz) = 19766 +SIZE (cargo/ctr-0.7.0.tar.gz) = 16949 +SIZE (cargo/curve25519-dalek-3.1.0.tar.gz) = 511442 +SIZE (cargo/derivative-2.2.0.tar.gz) = 48076 +SIZE (cargo/digest-0.8.1.tar.gz) = 9449 +SIZE (cargo/digest-0.9.0.tar.gz) = 13247 +SIZE (cargo/dirs-3.0.2.tar.gz) = 12184 +SIZE (cargo/dirs-next-2.0.0.tar.gz) = 11689 +SIZE (cargo/dirs-sys-0.3.6.tar.gz) = 10626 +SIZE (cargo/dirs-sys-next-0.1.2.tar.gz) = 10681 +SIZE (cargo/displaydoc-0.2.3.tar.gz) = 17060 +SIZE (cargo/easy-parallel-3.2.0.tar.gz) = 9276 +SIZE (cargo/either-1.6.1.tar.gz) = 13641 +SIZE (cargo/emoji-0.2.1.tar.gz) = 6475871 +SIZE (cargo/enumflags2-0.7.5.tar.gz) = 15117 +SIZE (cargo/enumflags2_derive-0.7.4.tar.gz) = 8166 +SIZE (cargo/env_logger-0.8.4.tar.gz) = 33342 +SIZE (cargo/error-chain-0.12.4.tar.gz) = 29274 +SIZE (cargo/event-listener-2.5.2.tar.gz) = 15225 +SIZE (cargo/fake-simd-0.1.2.tar.gz) = 5398 +SIZE (cargo/fastrand-1.4.1.tar.gz) = 11224 +SIZE (cargo/filetime-0.2.14.tar.gz) = 14358 +SIZE (cargo/fixedbitset-0.2.0.tar.gz) = 13597 +SIZE (cargo/fixedbitset-0.4.1.tar.gz) = 15551 +SIZE (cargo/flate2-1.0.20.tar.gz) = 74036 +SIZE (cargo/fnv-1.0.7.tar.gz) = 11266 +SIZE (cargo/form_urlencoded-1.0.1.tar.gz) = 8773 +SIZE (cargo/fs2-0.4.3.tar.gz) = 13138 +SIZE (cargo/futures-0.3.15.tar.gz) = 46425 +SIZE (cargo/futures-channel-0.3.15.tar.gz) = 31867 +SIZE (cargo/futures-core-0.3.15.tar.gz) = 14514 +SIZE (cargo/futures-executor-0.3.15.tar.gz) = 17166 +SIZE (cargo/futures-io-0.3.15.tar.gz) = 9058 +SIZE (cargo/futures-lite-1.12.0.tar.gz) = 36032 +SIZE (cargo/futures-macro-0.3.15.tar.gz) = 10872 +SIZE (cargo/futures-sink-0.3.15.tar.gz) = 7672 +SIZE (cargo/futures-task-0.3.15.tar.gz) = 11811 +SIZE (cargo/futures-util-0.3.15.tar.gz) = 141962 +SIZE (cargo/fuzzy-matcher-0.3.7.tar.gz) = 18047 +SIZE (cargo/fxhash-0.2.1.tar.gz) = 4102 +SIZE (cargo/generic-array-0.12.4.tar.gz) = 18212 +SIZE (cargo/generic-array-0.14.4.tar.gz) = 28916 +SIZE (cargo/getopts-0.2.21.tar.gz) = 18457 +SIZE (cargo/getrandom-0.1.16.tar.gz) = 25077 +SIZE (cargo/getrandom-0.2.3.tar.gz) = 26261 +SIZE (cargo/gh-emoji-1.0.3.tar.gz) = 21768 +SIZE (cargo/ghash-0.4.2.tar.gz) = 8865 +SIZE (cargo/hashbrown-0.11.2.tar.gz) = 85713 +SIZE (cargo/headers-0.3.4.tar.gz) = 67384 +SIZE (cargo/headers-core-0.2.0.tar.gz) = 2380 +SIZE (cargo/heck-0.3.3.tar.gz) = 10260 +SIZE (cargo/hermit-abi-0.1.19.tar.gz) = 9979 +SIZE (cargo/hex-0.4.3.tar.gz) = 13299 +SIZE (cargo/hkdf-0.11.0.tar.gz) = 171707 +SIZE (cargo/hmac-0.11.0.tar.gz) = 11385 +SIZE (cargo/hmac-0.7.1.tar.gz) = 9765 +SIZE (cargo/hostname-0.3.1.tar.gz) = 9272 +SIZE (cargo/http-0.2.4.tar.gz) = 105489 +SIZE (cargo/http-body-0.4.2.tar.gz) = 7603 +SIZE (cargo/httparse-1.4.1.tar.gz) = 25592 +SIZE (cargo/httpdate-1.0.1.tar.gz) = 10293 +SIZE (cargo/hyper-0.14.11.tar.gz) = 169467 +SIZE (cargo/hyper-rustls-0.22.1.tar.gz) = 26718 +SIZE (cargo/hyper-timeout-0.4.1.tar.gz) = 13805 +SIZE (cargo/iana-time-zone-0.1.47.tar.gz) = 16974 +SIZE (cargo/idna-0.2.3.tar.gz) = 271023 +SIZE (cargo/indexmap-1.7.0.tar.gz) = 50363 +SIZE (cargo/instant-0.1.10.tar.gz) = 5218 +SIZE (cargo/itertools-0.10.1.tar.gz) = 116219 +SIZE (cargo/itertools-0.9.0.tar.gz) = 96429 +SIZE (cargo/itoa-0.4.7.tar.gz) = 12099 +SIZE (cargo/itoa-1.0.2.tar.gz) = 11112 +SIZE (cargo/jni-0.16.0.tar.gz) = 59922 +SIZE (cargo/jni-sys-0.3.0.tar.gz) = 10232 +SIZE (cargo/js-sys-0.3.59.tar.gz) = 78849 +SIZE (cargo/lazy_static-1.4.0.tar.gz) = 10443 +SIZE (cargo/lexical-core-0.7.6.tar.gz) = 494385 +SIZE (cargo/libc-0.2.126.tar.gz) = 590481 +SIZE (cargo/linked-hash-map-0.5.4.tar.gz) = 16166 +SIZE (cargo/lock_api-0.4.7.tar.gz) = 25371 +SIZE (cargo/log-0.4.14.tar.gz) = 34582 +SIZE (cargo/log-panics-2.0.0.tar.gz) = 6781 +SIZE (cargo/lru-cache-0.1.2.tar.gz) = 9307 +SIZE (cargo/mac-notification-sys-0.5.2.tar.gz) = 10585 +SIZE (cargo/malloc_buf-0.0.6.tar.gz) = 1239 +SIZE (cargo/match_cfg-0.1.0.tar.gz) = 7153 +SIZE (cargo/matches-0.1.8.tar.gz) = 2216 +SIZE (cargo/memchr-2.4.0.tar.gz) = 63392 +SIZE (cargo/memoffset-0.6.4.tar.gz) = 7664 +SIZE (cargo/mime-0.3.16.tar.gz) = 15206 +SIZE (cargo/mime_guess-2.0.3.tar.gz) = 27437 +SIZE (cargo/miniz_oxide-0.4.4.tar.gz) = 49938 +SIZE (cargo/mio-0.7.13.tar.gz) = 87027 +SIZE (cargo/miow-0.3.7.tar.gz) = 24563 +SIZE (cargo/mpart-async-0.5.0.tar.gz) = 30154 +SIZE (cargo/multimap-0.8.3.tar.gz) = 13518 +SIZE (cargo/nix-0.23.1.tar.gz) = 240531 +SIZE (cargo/nom-5.1.2.tar.gz) = 136174 +SIZE (cargo/notify-rust-4.5.8.tar.gz) = 48098 +SIZE (cargo/ntapi-0.3.6.tar.gz) = 127221 +SIZE (cargo/num-integer-0.1.44.tar.gz) = 22216 +SIZE (cargo/num-traits-0.2.14.tar.gz) = 45476 +SIZE (cargo/num_cpus-1.13.0.tar.gz) = 14704 +SIZE (cargo/num_enum-0.5.2.tar.gz) = 10479 +SIZE (cargo/num_enum_derive-0.5.2.tar.gz) = 7670 +SIZE (cargo/num_threads-0.1.6.tar.gz) = 7334 +SIZE (cargo/objc-0.2.7.tar.gz) = 22036 +SIZE (cargo/objc-foundation-0.1.1.tar.gz) = 9063 +SIZE (cargo/objc_id-0.1.1.tar.gz) = 3258 +SIZE (cargo/once_cell-1.13.1.tar.gz) = 31335 +SIZE (cargo/oncemutex-0.1.1.tar.gz) = 2476 +SIZE (cargo/opaque-debug-0.2.3.tar.gz) = 5643 +SIZE (cargo/opaque-debug-0.3.0.tar.gz) = 5767 +SIZE (cargo/opener-0.5.0.tar.gz) = 12350 +SIZE (cargo/openssl-probe-0.1.4.tar.gz) = 7066 +SIZE (cargo/ordered-stream-0.0.1.tar.gz) = 9081 +SIZE (cargo/parking-2.0.0.tar.gz) = 9714 +SIZE (cargo/parking_lot-0.11.1.tar.gz) = 39854 +SIZE (cargo/parking_lot_core-0.8.3.tar.gz) = 32147 +SIZE (cargo/percent-encoding-2.1.0.tar.gz) = 9748 +SIZE (cargo/petgraph-0.5.1.tar.gz) = 147173 +SIZE (cargo/petgraph-0.6.0.tar.gz) = 182063 +SIZE (cargo/phf-0.8.0.tar.gz) = 3902 +SIZE (cargo/phf_generator-0.8.0.tar.gz) = 7604 +SIZE (cargo/phf_macros-0.8.0.tar.gz) = 5814 +SIZE (cargo/phf_shared-0.8.0.tar.gz) = 2860 +SIZE (cargo/phonenumber-0.3.1+8.12.9.tar.gz) = 2362619 +SIZE (cargo/pin-project-1.0.7.tar.gz) = 54847 +SIZE (cargo/pin-project-internal-1.0.7.tar.gz) = 27884 +SIZE (cargo/pin-project-lite-0.2.7.tar.gz) = 27212 +SIZE (cargo/pin-utils-0.1.0.tar.gz) = 7580 +SIZE (cargo/polling-2.1.0.tar.gz) = 17682 +SIZE (cargo/polyval-0.5.1.tar.gz) = 17257 +SIZE (cargo/ppv-lite86-0.2.10.tar.gz) = 20915 +SIZE (cargo/proc-macro-crate-1.0.0.tar.gz) = 8442 +SIZE (cargo/proc-macro-error-1.0.4.tar.gz) = 25293 +SIZE (cargo/proc-macro-error-attr-1.0.4.tar.gz) = 7971 +SIZE (cargo/proc-macro-hack-0.5.19.tar.gz) = 15556 +SIZE (cargo/proc-macro-nested-0.1.7.tar.gz) = 6495 +SIZE (cargo/proc-macro2-1.0.27.tar.gz) = 38625 +SIZE (cargo/prost-0.8.0.tar.gz) = 25532 +SIZE (cargo/prost-0.9.0.tar.gz) = 25584 +SIZE (cargo/prost-build-0.8.0.tar.gz) = 8407464 +SIZE (cargo/prost-build-0.9.0.tar.gz) = 9947797 +SIZE (cargo/prost-derive-0.8.0.tar.gz) = 15203 +SIZE (cargo/prost-derive-0.9.0.tar.gz) = 15266 +SIZE (cargo/prost-types-0.8.0.tar.gz) = 27271 +SIZE (cargo/prost-types-0.9.0.tar.gz) = 27403 +SIZE (cargo/pulldown-cmark-0.8.0.tar.gz) = 106330 +SIZE (cargo/qr2term-0.2.2.tar.gz) = 42424 +SIZE (cargo/qrcode-0.12.0.tar.gz) = 58072 +SIZE (cargo/quick-xml-0.18.1.tar.gz) = 103957 +SIZE (cargo/quickcheck-1.0.3.tar.gz) = 28069 +SIZE (cargo/quickcheck_macros-1.0.0.tar.gz) = 5275 +SIZE (cargo/quote-1.0.9.tar.gz) = 25042 +SIZE (cargo/rand-0.7.3.tar.gz) = 112246 +SIZE (cargo/rand-0.8.4.tar.gz) = 87406 +SIZE (cargo/rand_chacha-0.2.2.tar.gz) = 13267 +SIZE (cargo/rand_chacha-0.3.1.tar.gz) = 15251 +SIZE (cargo/rand_core-0.5.1.tar.gz) = 21116 +SIZE (cargo/rand_core-0.6.3.tar.gz) = 21938 +SIZE (cargo/rand_hc-0.2.0.tar.gz) = 11670 +SIZE (cargo/rand_hc-0.3.1.tar.gz) = 11891 +SIZE (cargo/rand_pcg-0.2.1.tar.gz) = 11291 +SIZE (cargo/redox_syscall-0.2.9.tar.gz) = 23533 +SIZE (cargo/redox_users-0.4.0.tar.gz) = 13023 +SIZE (cargo/regex-1.5.6.tar.gz) = 238593 +SIZE (cargo/regex-automata-0.1.10.tar.gz) = 114533 +SIZE (cargo/regex-cache-0.2.1.tar.gz) = 6346 +SIZE (cargo/regex-syntax-0.6.26.tar.gz) = 293912 +SIZE (cargo/remove_dir_all-0.5.3.tar.gz) = 9184 +SIZE (cargo/ring-0.16.20.tar.gz) = 5082615 +SIZE (cargo/rustls-0.19.1.tar.gz) = 208143 +SIZE (cargo/rustls-native-certs-0.5.0.tar.gz) = 18482 +SIZE (cargo/ryu-1.0.5.tar.gz) = 49570 +SIZE (cargo/same-file-1.0.6.tar.gz) = 10183 +SIZE (cargo/schannel-0.1.19.tar.gz) = 42755 +SIZE (cargo/scopeguard-1.1.0.tar.gz) = 11470 +SIZE (cargo/sct-0.6.1.tar.gz) = 26825 +SIZE (cargo/security-framework-2.3.1.tar.gz) = 61581 +SIZE (cargo/security-framework-sys-2.3.0.tar.gz) = 12561 +SIZE (cargo/semver-1.0.3.tar.gz) = 28918 +SIZE (cargo/serde-1.0.126.tar.gz) = 75138 +SIZE (cargo/serde_derive-1.0.126.tar.gz) = 54189 +SIZE (cargo/serde_json-1.0.64.tar.gz) = 115138 +SIZE (cargo/serde_repr-0.1.7.tar.gz) = 10173 +SIZE (cargo/sha-1-0.9.6.tar.gz) = 13758 +SIZE (cargo/sha1-0.6.1.tar.gz) = 2931 +SIZE (cargo/sha1_smol-1.0.0.tar.gz) = 9782 +SIZE (cargo/sha2-0.8.2.tar.gz) = 19851 +SIZE (cargo/sha2-0.9.5.tar.gz) = 19912 +SIZE (cargo/sharded-slab-0.1.4.tar.gz) = 52479 +SIZE (cargo/signal-hook-0.1.17.tar.gz) = 27085 +SIZE (cargo/signal-hook-registry-1.4.0.tar.gz) = 17912 +SIZE (cargo/siphasher-0.3.5.tar.gz) = 9455 +SIZE (cargo/slab-0.4.3.tar.gz) = 15681 +SIZE (cargo/sled-0.34.6.tar.gz) = 485861 +SIZE (cargo/smallvec-1.6.1.tar.gz) = 26444 +SIZE (cargo/smawk-0.3.1.tar.gz) = 12840 +SIZE (cargo/socket2-0.4.0.tar.gz) = 37949 +SIZE (cargo/spin-0.5.2.tar.gz) = 12004 +SIZE (cargo/static_assertions-1.1.0.tar.gz) = 18480 +SIZE (cargo/strsim-0.8.0.tar.gz) = 9309 +SIZE (cargo/structopt-0.3.22.tar.gz) = 51665 +SIZE (cargo/structopt-derive-0.4.15.tar.gz) = 20861 +SIZE (cargo/strum-0.22.0.tar.gz) = 5413 +SIZE (cargo/strum_macros-0.22.0.tar.gz) = 16501 +SIZE (cargo/subtle-1.0.0.tar.gz) = 8097 +SIZE (cargo/subtle-2.4.1.tar.gz) = 12630 +SIZE (cargo/syn-1.0.73.tar.gz) = 232706 +SIZE (cargo/synstructure-0.12.5.tar.gz) = 18020 +SIZE (cargo/tar-0.4.38.tar.gz) = 49158 +SIZE (cargo/tempfile-3.2.0.tar.gz) = 25892 +SIZE (cargo/textwrap-0.11.0.tar.gz) = 17322 +SIZE (cargo/textwrap-0.14.2.tar.gz) = 52016 +SIZE (cargo/thiserror-1.0.30.tar.gz) = 17748 +SIZE (cargo/thiserror-impl-1.0.30.tar.gz) = 15230 +SIZE (cargo/thread_local-1.1.4.tar.gz) = 13106 +SIZE (cargo/time-0.1.44.tar.gz) = 28885 +SIZE (cargo/time-0.3.9.tar.gz) = 81412 +SIZE (cargo/tinyvec-1.2.0.tar.gz) = 41625 +SIZE (cargo/tinyvec_macros-0.1.0.tar.gz) = 1817 +SIZE (cargo/tokio-1.16.1.tar.gz) = 552194 +SIZE (cargo/tokio-io-timeout-1.1.1.tar.gz) = 8853 +SIZE (cargo/tokio-macros-1.8.0.tar.gz) = 9346 +SIZE (cargo/tokio-rustls-0.22.0.tar.gz) = 22706 +SIZE (cargo/tokio-stream-0.1.7.tar.gz) = 30323 +SIZE (cargo/tokio-util-0.6.7.tar.gz) = 73201 +SIZE (cargo/toml-0.5.8.tar.gz) = 54219 +SIZE (cargo/tower-service-0.3.1.tar.gz) = 6299 +SIZE (cargo/tracing-0.1.35.tar.gz) = 72680 +SIZE (cargo/tracing-appender-0.2.2.tar.gz) = 17208 +SIZE (cargo/tracing-attributes-0.1.21.tar.gz) = 27552 +SIZE (cargo/tracing-core-0.1.27.tar.gz) = 58328 +SIZE (cargo/tracing-log-0.1.3.tar.gz) = 20549 +SIZE (cargo/tracing-subscriber-0.3.11.tar.gz) = 184827 +SIZE (cargo/try-lock-0.2.3.tar.gz) = 4158 +SIZE (cargo/tui-0.15.0.tar.gz) = 139975 +SIZE (cargo/tungstenite-0.15.0.tar.gz) = 59529 +SIZE (cargo/twoway-0.2.2.tar.gz) = 30454 +SIZE (cargo/typenum-1.13.0.tar.gz) = 40238 +SIZE (cargo/unchecked-index-0.2.2.tar.gz) = 8325 +SIZE (cargo/unicase-2.6.0.tar.gz) = 23478 +SIZE (cargo/unicode-bidi-0.3.5.tar.gz) = 33423 +SIZE (cargo/unicode-linebreak-0.1.1.tar.gz) = 65230 +SIZE (cargo/unicode-normalization-0.1.19.tar.gz) = 107353 +SIZE (cargo/unicode-segmentation-1.8.0.tar.gz) = 94011 +SIZE (cargo/unicode-width-0.1.8.tar.gz) = 16732 +SIZE (cargo/unicode-xid-0.2.2.tar.gz) = 14955 +SIZE (cargo/universal-hash-0.4.0.tar.gz) = 8386 +SIZE (cargo/unreachable-1.0.0.tar.gz) = 6355 +SIZE (cargo/untrusted-0.7.1.tar.gz) = 7924 +SIZE (cargo/url-2.2.2.tar.gz) = 68555 +SIZE (cargo/utf-8-0.7.6.tar.gz) = 10422 +SIZE (cargo/uuid-0.8.2.tar.gz) = 37909 +SIZE (cargo/valuable-0.1.0.tar.gz) = 27718 +SIZE (cargo/vec_map-0.8.2.tar.gz) = 14466 +SIZE (cargo/version_check-0.9.3.tar.gz) = 12547 +SIZE (cargo/void-1.0.2.tar.gz) = 2356 +SIZE (cargo/waker-fn-1.1.0.tar.gz) = 7114 +SIZE (cargo/walkdir-2.3.2.tar.gz) = 23516 +SIZE (cargo/want-0.3.0.tar.gz) = 6550 +SIZE (cargo/wasi-0.10.0+wasi-snapshot-preview1.tar.gz) = 26964 +SIZE (cargo/wasi-0.9.0+wasi-snapshot-preview1.tar.gz) = 31521 +SIZE (cargo/wasm-bindgen-0.2.82.tar.gz) = 166376 +SIZE (cargo/wasm-bindgen-backend-0.2.82.tar.gz) = 25764 +SIZE (cargo/wasm-bindgen-macro-0.2.82.tar.gz) = 11808 +SIZE (cargo/wasm-bindgen-macro-support-0.2.82.tar.gz) = 18529 +SIZE (cargo/wasm-bindgen-shared-0.2.82.tar.gz) = 7197 +SIZE (cargo/web-sys-0.3.51.tar.gz) = 651133 +SIZE (cargo/webpki-0.21.4.tar.gz) = 58505 +SIZE (cargo/wepoll-ffi-0.1.2.tar.gz) = 31309 +SIZE (cargo/which-4.1.0.tar.gz) = 7684 +SIZE (cargo/whoami-1.1.2.tar.gz) = 10583 +SIZE (cargo/winapi-0.3.9.tar.gz) = 1200382 +SIZE (cargo/winapi-i686-pc-windows-gnu-0.4.0.tar.gz) = 2918815 +SIZE (cargo/winapi-util-0.1.5.tar.gz) = 10164 +SIZE (cargo/winapi-x86_64-pc-windows-gnu-0.4.0.tar.gz) = 2947998 +SIZE (cargo/windows-0.24.0.tar.gz) = 12674875 +SIZE (cargo/windows_i686_gnu-0.24.0.tar.gz) = 774447 +SIZE (cargo/windows_i686_msvc-0.24.0.tar.gz) = 732279 +SIZE (cargo/windows_x86_64_gnu-0.24.0.tar.gz) = 743223 +SIZE (cargo/windows_x86_64_msvc-0.24.0.tar.gz) = 668947 +SIZE (cargo/winrt-notification-0.5.1.tar.gz) = 34163 +SIZE (cargo/x25519-dalek-1.1.1.tar.gz) = 84499 +SIZE (cargo/xattr-0.2.2.tar.gz) = 11750 +SIZE (cargo/xflags-0.2.2.tar.gz) = 10099 +SIZE (cargo/xflags-macros-0.2.2.tar.gz) = 10624 +SIZE (cargo/xml-rs-0.8.4.tar.gz) = 52690 +SIZE (cargo/xshell-0.1.14.tar.gz) = 20415 +SIZE (cargo/xshell-macros-0.1.14.tar.gz) = 2677 +SIZE (cargo/zbus-2.1.1.tar.gz) = 103818 +SIZE (cargo/zbus_macros-2.1.1.tar.gz) = 23945 +SIZE (cargo/zbus_names-2.1.0.tar.gz) = 8481 +SIZE (cargo/zeroize-1.3.0.tar.gz) = 15913 +SIZE (cargo/zeroize_derive-1.3.2.tar.gz) = 10299 +SIZE (cargo/zvariant-3.3.0.tar.gz) = 67332 +SIZE (cargo/zvariant_derive-3.3.0.tar.gz) = 10932 +SIZE (gurk-rs-0.2.5.tar.gz) = 243867 diff --git a/net/gurk-rs/files/config b/net/gurk-rs/files/config new file mode 100644 index 0000000..61c95e0 --- /dev/null +++ b/net/gurk-rs/files/config @@ -0,0 +1,32 @@ +[source."https://github.com/boxdot/libsignal-service-rs"] +git = "https://github.com/boxdot/libsignal-service-rs" +rev = "8be91da2" +replace-with = "vendored-sources" + +[source."https://github.com/boxdot/presage.git"] +git = "https://github.com/boxdot/presage.git" +rev = "f908e8f" +replace-with = "vendored-sources" + +[source."https://github.com/signalapp/curve25519-dalek.git"] +git = "https://github.com/signalapp/curve25519-dalek.git" +branch = "lizard2" +replace-with = "vendored-sources" + +[source."https://github.com/signalapp/libsignal-client"] +git = "https://github.com/signalapp/libsignal-client" +tag = "v0.11.0" +replace-with = "vendored-sources" + +[source."https://github.com/signalapp/poksho.git"] +git = "https://github.com/signalapp/poksho.git" +tag = "v0.7.0" +replace-with = "vendored-sources" + +[source."https://github.com/signalapp/zkgroup"] +git = "https://github.com/signalapp/zkgroup" +tag = "v0.7.3" +replace-with = "vendored-sources" + +[source.vendored-sources] +directory = "vendor" diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/.cargo-checksum.json b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/.cargo-checksum.json new file mode 100644 index 0000000..8c26b50 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"90461f680fbff6e35854621055254d473ce1e7fca887b74e74ccbce3e7610e4e","CONTRIBUTING.md":"10b88528724037ed24627bf7ed3fe4e9efc615309dfb37ebc3ff6f4493f6def5","Cargo.toml":"566b415d6fb7a8f7e92e74c2acbbf4e072fa5e4f92bd7bcc568aada50b5bc8b6","LICENSE":"aa9c248214cbbc0cfef3e2037cdc27d7fad62908caaa0eefdc6e372b43df7bd1","Makefile":"3bdd6d7b89b2a1d0e69feab4b8f11514aef2b14c180726750e5de413b728d544","README.md":"e84e25ff7c25f45b9af235568bc2f9b4a35e5296c59b72d1296a295211eeeabf","benches/dalek_benchmarks.rs":"e7aef2227fa024b4d211cd867fbc5c1301bcb085e0eeaac8e6114b29793e167f","docs/assets/dalek-logo-clear.png":"6babf6c1cdb10af05142501af2c4947765ef7839f87b91bc683165a8369fc3f4","docs/assets/dalek-logo.png":"a4a0451c5a2c0417584dc7d7d1388283b3bf9aeef89ee64ee073cdcd83c1a0f1","docs/assets/dalek-logo.svg":"22534b6935cfb8ccd6512ee13006700c451b28feb13acc137668caf00901633f","docs/assets/rustdoc-include-katex-header.html":"348752aa412e1dc774427f20d8d51ca0b2923979d4829cbd493d76e499f2674e","docs/avx2-notes.md":"5aa2bc7462c26631cc18d7b8f62e83caa9479672efc34046db7c78f650fb03aa","docs/ifma-notes.md":"7ca18607cafca402b832c313de42763df9cf1f8c9ca0ac58621322b5e33e8461","docs/parallel-formulas.md":"df2f4633055ba7d0594d3e6b53252ac3f5ca0454e20d7a971527b6509d136e43","src/backend/mod.rs":"667288065b88b72e320cfb9c77061f03df5b21193effbf1eacf8e5cf37956bdd","src/backend/serial/curve_models/mod.rs":"207b0669ab38fa00417d03e80c61f014b9232aa6f9827832950032fb057df179","src/backend/serial/mod.rs":"8d64f8575e7d7fe71614ca83702bf4dd2473dc7e35edf65dbe3e64ab4f6e6241","src/backend/serial/scalar_mul/mod.rs":"ac3359bd199ab18eebad34bb8abe6e83831c489ed4f0e62fdde32e284ba7409a","src/backend/serial/scalar_mul/pippenger.rs":"bfab409306c0f88bbbe0bffedf3f66ccc011e9c1f6caa46aef1ce9727c48d3b6","src/backend/serial/scalar_mul/precomputed_straus.rs":"b735367646cd08a31d127882b623d22e77fda4197557d2e5f1bbf34e8da587db","src/backend/serial/scalar_mul/straus.rs":"7c0e5d9218c51397de3d43e6bc173784a900336cf57f079c028fd893938ea2af","src/backend/serial/scalar_mul/variable_base.rs":"8511829f2324d1483a98bbd1fa9fe7fd6920bedb39ba5facfc380690289c612a","src/backend/serial/scalar_mul/vartime_double_base.rs":"24d3fdd1d8c957d02e513fec446726038ead042f59ec33b705d6645a030321d9","src/backend/serial/u32/constants.rs":"841c98daa3f08713b5544c9b1d361541498b811df85b69edb453929fd33e7218","src/backend/serial/u32/field.rs":"c1e1e097335f3b0e0cd84d726e43e1b2123fc73c4f5d926d5982ea225ff452b5","src/backend/serial/u32/mod.rs":"c3694fd2a4324ee1a1889d29b3d08fd472afcbf9358227d10a68ddf98f46a167","src/backend/serial/u32/scalar.rs":"a797284c92f36626e70c877cf32da6b79b44c0ca634a3bc8754803f0cae7f600","src/backend/serial/u64/constants.rs":"c0ee51f1300a5b3b7178a74acddcabed06ff05353e83e78fcf50a98033b93ddd","src/backend/serial/u64/field.rs":"e51b138c298099042584ae2d59433f4daed703a995d87ae35ac909eb5c188327","src/backend/serial/u64/mod.rs":"e310c81ec51f08f6824b3ef4378d6e492c4b46b36351de918438fa33e6db552a","src/backend/serial/u64/scalar.rs":"75c7f05daafea7778c6a44a448edcac8330f813787314b9b03b61b46e9b07384","src/backend/vector/avx2/constants.rs":"1bf0d0c1749cc4f0c95025ba13f9ed0cd6820f05135e52b457e1219843129d7d","src/backend/vector/avx2/edwards.rs":"57cc5cd12b4c20c0254a66686c98d62536f0ac4d79ae880f337f3a578d6b0dc6","src/backend/vector/avx2/field.rs":"30ae1c7ea1c03aae24dea971480d1921d621df2abf009104fc651d46b14aa842","src/backend/vector/avx2/mod.rs":"532e755195caa53b6acf21cfc39341b570f37553c77ad19c2908d5fa8d1e4a9a","src/backend/vector/ifma/constants.rs":"b1acd2c8674a5e710d753dfb159f0ea507585f2903f49f6f97802e53f5584bcf","src/backend/vector/ifma/edwards.rs":"c3b55fa23b117a83dee32201131f64bc4a050d3e96de29be345ef41b0291ea39","src/backend/vector/ifma/field.rs":"b95de5f0140f043b31cac506b713d3d3359f052092760e06effb2b743b2531ea","src/backend/vector/ifma/mod.rs":"385c894444884ec90052143502b8e37d7f36416e1dfd7e31ec588914d1a26527","src/backend/vector/mod.rs":"2c9121c1907a5a7fe34e130a3c21ef537a7abcd900df1b0c072d12e9eae0295b","src/backend/vector/scalar_mul/mod.rs":"e7a4980586ef8527ec4ddfe22e0c3128f6407d2cd54a24c5756975e8e3ae8d4f","src/backend/vector/scalar_mul/pippenger.rs":"e87703ea516006fadc567fa5b75b6c5fee6ec5a9ad27368726fae0747e471368","src/backend/vector/scalar_mul/precomputed_straus.rs":"982acacbf478c5ee0f7e0bc5650b22960655550ac08b888e3477fc786ce0c959","src/backend/vector/scalar_mul/straus.rs":"e2b65fae01d77433ccf54cc6994ba2e59701527d8ff721e8b223e784bb4f6285","src/backend/vector/scalar_mul/variable_base.rs":"c638bb2975b421d2bb6f29589c2e9b46831592b835851fed43569a8a5204c36e","src/backend/vector/scalar_mul/vartime_double_base.rs":"47ec101016a9c2126f934060bef57a5aef77a7ad05bff183cd13e56bf782e49f","src/constants.rs":"deeb7a7eef8ab83ce9777aaf30c901c273c4b2e6172b39d1febc2210affc290c","src/edwards.rs":"ab9f2ef59be48282d791556a25ef07d5b8c5da6a5f23c3790ea5bbc47bba757f","src/field.rs":"db8b3ccd985a691db290ca4ad9e765c166003906caf1c5f2dfc103a55d6686ce","src/lib.rs":"f9e5e3d31d10cac9a230d17f268b04546f9080ec27916ebd3f0c452ad152e8c9","src/lizard/LICENSE":"84da1cdd704d51e2ca03719df50c4e5b400fde68eb39dd70a976ab6122283f29","src/lizard/jacobi_quartic.rs":"8beb8b33dda13a76a376e0af51930b7beee95aa986c65ba844fb895404e1cf19","src/lizard/lizard_constants.rs":"feefcbfc0f3958ed2c2e089c255d1c68c639d6f5e5939c6996080a33a7189a65","src/lizard/lizard_ristretto.rs":"7e260163ea6bd7d26f5c34fe902d512f6ed23d3a73032e66cf2c82fb49bd44be","src/lizard/mod.rs":"cab61bc4f15f10370f3b378eddf3083650b95aead44d91549a210dbcf0fa5a0a","src/lizard/u32_constants.rs":"443b9b4755625a7f939f09138d1c1fe9664a49fc33272186df02e5d2e193490a","src/lizard/u64_constants.rs":"915218db4cf072a000c26bb6e0d7690b76480dd3f906571a321970cfc04e0471","src/macros.rs":"e2df1086f1b1c72ab72eb5a1153938a3d02cd92d4cb20629fd072ff79b886ffe","src/montgomery.rs":"b5c2244b0fe69fee3f0167aa6641eadfb2fb786f1047c358eda33298ed7f8c82","src/prelude.rs":"2a4cbed499e17a2aff657f6287abe0f6d242414f5fdbf40e15668691b680ad3e","src/ristretto.rs":"742088bfa780c4fe9ed82a25e481c335733335b3ce6a855e04fe125165502023","src/scalar.rs":"e14450460b7bda95bfcdae92e6e4b68fc9346482a444770ce8c909c8d4c14da3","src/traits.rs":"795e88e021efd3beb1a4ff1c137369ecf5ac13c4ed0e2559d67a486259ee3c75","src/window.rs":"2176f6b40306b4b4b02c302b227c4a0f1ef0062dd1535438cc5a905666241433","vendor/ristretto.sage":"a2f4309ada0afa4156f5a660be4384a0f1f332c12f836199124f48e89310344d"},"package":null} \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/CHANGELOG.md b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/CHANGELOG.md new file mode 100644 index 0000000..a46b2ff --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/CHANGELOG.md @@ -0,0 +1,104 @@ +# Changelog + +Entries are listed in reverse chronological order. + +## 2.0.0 + +* Fix a data modeling error in the `serde` feature pointed out by Trevor Perrin + which caused points and scalars to be serialized with length fields rather + than as fixed-size 32-byte arrays. This is a breaking change, but it fixes + compatibility with `serde-json` and ensures that the `serde-bincode` encoding + matches the conventional encoding for X/Ed25519. +* Update `rand_core` to `0.5`, allowing use with new `rand` versions. +* Switch from `clear_on_drop` to `zeroize` (by Tony Arcieri). +* Require `subtle = ^2.2.1` and remove the note advising nightly Rust, which is + no longer required as of that version of `subtle`. See the `subtle` + changelog for more details. +* Update `README.md` for `2.x` series. +* Remove the `build.rs` hack which loaded the entire crate into its own + `build.rs` to generate constants, and keep the constants in the source code. + +The only significant change is the data model change to the `serde` feature; +besides the `rand_core` version bump, there are no other user-visible changes. + +## 1.2.3 + +* Fix an issue identified by a Quarkslab audit (and Jack Grigg), where manually + constructing unreduced `Scalar` values, as needed for X/Ed25519, and then + performing scalar/scalar arithmetic could compute incorrect results. +* Switch to upstream Rust intrinsics for the IFMA backend now that they exist in + Rust and don't need to be defined locally. +* Ensure that the NAF computation works correctly, even for parameters never + used elsewhere in the codebase. +* Minor refactoring to EdwardsPoint decompression. +* Fix broken links in documentation. +* Fix compilation on nightly broken due to changes to the `#[doc(include)]` path + root (not quite correctly done in 1.2.2). + +## 1.2.2 + +* Fix a typo in an internal doc-comment. +* Add the "crypto" tag to crate metadata. +* Fix compilation on nightly broken due to changes to the `#[doc(include)]` path + root. + +## 1.2.1 + +* Fix a bug in bucket index calculations in the Pippenger multiscalar algorithm + for very large input sizes. +* Add a more extensive randomized multiscalar multiplication consistency check + to the test suite to prevent regressions. +* Ensure that that multiscalar and NAF computations work correctly on extremal + `Scalar` values constructed via `from_bits`. + +## 1.2.0 + +* New multiscalar multiplication algorithm with better performance for + large problem sizes. The backend algorithm is selected + transparently using the size hints of the input iterators, so no + changes are required for client crates to start using it. +* Equality of Edwards points is now checked in projective coordinates. +* Serde can now be used with `no_std`. + +## 1.1.4 + +* Fix typos in documentation comments. +* Remove unnecessary `Default` bound on `Scalar::from_hash`. + +## 1.1.3 + +* Reverts the change in 1.1.0 to allow owned and borrowed RNGs, which caused a breakage due to a subtle interaction with ownership rules. (The `RngCore` change is retained). + +## 1.1.2 + +* Disabled KaTeX on `docs.rs` pending proper [support upstream](https://github.com/rust-lang/docs.rs/issues/302). + +## 1.1.1 + +* Fixed an issue related to `#[cfg(rustdoc)]` which prevented documenting multiple backends. + +## 1.1.0 + +* Adds support for precomputation for multiscalar multiplication. +* Restructures the internal source tree into `serial` and `vector` backends (no change to external API). +* Adds a new IFMA backend which sets speed records. +* The `avx2_backend` feature is now an alias for the `simd_backend` feature, which autoselects an appropriate vector backend (currently AVX2 or IFMA). +* Replaces the `rand` dependency with `rand_core`. +* Generalizes trait bounds on `RistrettoPoint::random()` and `Scalar::random()` to allow owned and borrowed RNGs and to allow `RngCore` instead of `Rng`. + +## 1.0.3 + +* Adds `ConstantTimeEq` implementation for compressed points. + +## 1.0.2 + +* Fixes a typo in the naming of variables in Ristretto formulas (no change to functionality). + +## 1.0.1 + +* Depends on the stable `2.0` version of `subtle` instead of `2.0.0-pre.0`. + +## 1.0.0 + +Initial stable release. Yanked due to a dependency mistake (see above). + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/CONTRIBUTING.md b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/CONTRIBUTING.md new file mode 100644 index 0000000..86622d4 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# Contributing to curve25519-dalek + +If you have questions or comments, please feel free to email the +authors. + +For feature requests, suggestions, and bug reports, please open an issue on +[our Github](https://github.com/dalek-cryptography/curve25519-dalek). (Or, send us +an email if you're opposed to using Github for whatever reason.) + +Patches are welcomed as pull requests on +[our Github](https://github.com/dalek-cryptography/curve25519-dalek), as well as by +email (preferably sent to all of the authors listed in `Cargo.toml`). + +All issues on curve25519-dalek are mentored, if you want help with a bug just +ask @isislovecruft or @hdevalence. + +Some issues are easier than others. The `easy` label can be used to find the +easy issues. If you want to work on an issue, please leave a comment so that we +can assign it to you! + +# Code of Conduct + +We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html), +with the following additional clauses: + +* We respect the rights to privacy and anonymity for contributors and people in + the community. If someone wishes to contribute under a pseudonym different to + their primary identity, that wish is to be respected by all contributors. diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/Cargo.toml b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/Cargo.toml new file mode 100644 index 0000000..bbc354f --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/Cargo.toml @@ -0,0 +1,61 @@ +[package] +name = "curve25519-dalek" +version = "2.0.0" +authors = ["Isis Lovecruft ", + "Henry de Valence "] +readme = "README.md" +license = "BSD-3-Clause" +repository = "https://github.com/dalek-cryptography/curve25519-dalek" +homepage = "https://dalek.rs/curve25519-dalek" +documentation = "https://docs.rs/curve25519-dalek" +categories = ["cryptography", "no-std"] +keywords = ["cryptography", "crypto", "ristretto", "curve25519", "ristretto255"] +description = "A pure-Rust implementation of group operations on ristretto255 and Curve25519" +exclude = [ + "**/.gitignore", + ".gitignore", + ".travis.yml", +] + +[package.metadata.docs.rs] +# Disabled for now since this is borked; tracking https://github.com/rust-lang/docs.rs/issues/302 +# rustdoc-args = ["--html-in-header", ".cargo/registry/src/github.com-1ecc6299db9ec823/curve25519-dalek-0.13.2/rustdoc-include-katex-header.html"] +features = ["nightly", "simd_backend"] + +[badges] +travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master"} + +[dev-dependencies] +sha2 = { version = "0.8", default-features = false } +bincode = "1" +criterion = "0.3" +rand = "0.7" + +[[bench]] +name = "dalek_benchmarks" +harness = false + +[dependencies] +rand_core = { version = "0.5", default-features = false } +byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] } +digest = { version = "0.8", default-features = false } +subtle = { version = "^2.2.1", default-features = false } +serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } +packed_simd = { version = "0.3", features = ["into_bits"], optional = true } +zeroize = { version = "1", default-features = false } + +[features] +nightly = ["subtle/nightly"] +default = ["std", "u64_backend"] +std = ["alloc", "subtle/std", "rand_core/std"] +alloc = ["zeroize/alloc"] + +# The u32 backend uses u32s with u64 products. +u32_backend = [] +# The u64 backend uses u64s with u128 products. +u64_backend = [] +# The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA. +simd_backend = ["nightly", "u64_backend", "packed_simd"] +# DEPRECATED: this is now an alias for `simd_backend` and may be removed +# in some future release. +avx2_backend = ["simd_backend"] diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/LICENSE b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/LICENSE new file mode 100644 index 0000000..2501697 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/LICENSE @@ -0,0 +1,64 @@ +Copyright (c) 2016-2019 Isis Agora Lovecruft, Henry de Valence. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +Portions of curve25519-dalek were originally derived from Adam Langley's +Go ed25519 implementation, found at , +under the following licence: + +======================================================================== + +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/Makefile b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/Makefile new file mode 100644 index 0000000..e447175 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/Makefile @@ -0,0 +1,8 @@ +FEATURES := nightly yolocrypto avx2_backend + +doc: + cargo rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html + +doc-internal: + cargo rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html --document-private-items + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/README.md b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/README.md new file mode 100644 index 0000000..e3363f5 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/README.md @@ -0,0 +1,207 @@ + +# curve25519-dalek [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) [![](https://img.shields.io/badge/dynamic/json.svg?label=docs&uri=https%3A%2F%2Fcrates.io%2Fapi%2Fv1%2Fcrates%2Fcurve25519-dalek%2Fversions&query=%24.versions%5B0%5D.num&colorB=4F74A6)](https://doc.dalek.rs) [![](https://travis-ci.org/dalek-cryptography/curve25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/curve25519-dalek) + + + +**A pure-Rust implementation of group operations on Ristretto and Curve25519.** + +`curve25519-dalek` is a library providing group operations on the Edwards and +Montgomery forms of Curve25519, and on the prime-order Ristretto group. + +`curve25519-dalek` is not intended to provide implementations of any particular +crypto protocol. Rather, implementations of those protocols (such as +[`x25519-dalek`][x25519-dalek] and [`ed25519-dalek`][ed25519-dalek]) should use +`curve25519-dalek` as a library. + +`curve25519-dalek` is intended to provide a clean and safe _mid-level_ API for use +implementing a wide range of ECC-based crypto protocols, such as key agreement, +signatures, anonymous credentials, rangeproofs, and zero-knowledge proof +systems. + +In particular, `curve25519-dalek` implements Ristretto, which constructs a +prime-order group from a non-prime-order Edwards curve. This provides the +speed and safety benefits of Edwards curve arithmetic, without the pitfalls of +cofactor-related abstraction mismatches. + +# Documentation + +The semver-stable, public-facing `curve25519-dalek` API is documented +[here][docs-external]. In addition, the unstable internal implementation +details are documented [here][docs-internal]. + +The `curve25519-dalek` documentation requires a custom HTML header to include +KaTeX for math support. Unfortunately `cargo doc` does not currently support +this, but docs can be built using +```sh +make doc +make doc-internal +``` + +# Use + +To import `curve25519-dalek`, add the following to the dependencies section of +your project's `Cargo.toml`: +```toml +curve25519-dalek = "2" +``` + +The `2.x` series has API almost entirely unchanged from the `1.x` series, +except that: + +* an error in the data modeling for the (optional) `serde` feature was + corrected, so that when the `2.x`-series `serde` implementation is used + with `serde-bincode`, the derived serialization matches the usual X/Ed25519 + formats; + +* the `rand` version was updated. + +See `CHANGELOG.md` for more details. + +# Backends and Features + +The `nightly` feature enables features available only when using a Rust nightly +compiler. In particular, it is required for rendering documentation and for +the SIMD backends. + +Curve arithmetic is implemented using one of the following backends: + +* a `u32` backend using serial formulas and `u64` products; +* a `u64` backend using serial formulas and `u128` products; +* an `avx2` backend using [parallel formulas][parallel_doc] and `avx2` instructions (sets speed records); +* an `ifma` backend using [parallel formulas][parallel_doc] and `ifma` instructions (sets speed records); + +By default the `u64` backend is selected. To select a specific backend, use: +```sh +cargo build --no-default-features --features "std u32_backend" +cargo build --no-default-features --features "std u64_backend" +# Requires nightly, RUSTFLAGS="-C target_feature=+avx2" to use avx2 +cargo build --no-default-features --features "std simd_backend" +# Requires nightly, RUSTFLAGS="-C target_feature=+avx512ifma" to use ifma +cargo build --no-default-features --features "std simd_backend" +``` +Crates using `curve25519-dalek` can either select a backend on behalf of their +users, or expose feature flags that control the `curve25519-dalek` backend. + +The `std` feature is enabled by default, but it can be disabled for no-`std` +builds using `--no-default-features`. Note that this requires explicitly +selecting an arithmetic backend using one of the `_backend` features. +If no backend is selected, compilation will fail. + +# Safety + +The `curve25519-dalek` types are designed to make illegal states +unrepresentable. For example, any instance of an `EdwardsPoint` is +guaranteed to hold a point on the Edwards curve, and any instance of a +`RistrettoPoint` is guaranteed to hold a valid point in the Ristretto +group. + +All operations are implemented using constant-time logic (no +secret-dependent branches, no secret-dependent memory accesses), +unless specifically marked as being variable-time code. +We believe that our constant-time logic is lowered to constant-time +assembly, at least on `x86_64` targets. + +As an additional guard against possible future compiler optimizations, +the `subtle` crate places an optimization barrier before every +conditional move or assignment. More details can be found in [the +documentation for the `subtle` crate][subtle_doc]. + +Some functionality (e.g., multiscalar multiplication or batch +inversion) requires heap allocation for temporary buffers. All +heap-allocated buffers of potentially secret data are explicitly +zeroed before release. + +However, we do not attempt to zero stack data, for two reasons. +First, it's not possible to do so correctly: we don't have control +over stack allocations, so there's no way to know how much data to +wipe. Second, because `curve25519-dalek` provides a mid-level API, +the correct place to start zeroing stack data is likely not at the +entrypoints of `curve25519-dalek` functions, but at the entrypoints of +functions in other crates. + +The implementation is memory-safe, and contains no significant +`unsafe` code. The SIMD backend uses `unsafe` internally to call SIMD +intrinsics. These are marked `unsafe` only because invoking them on an +inappropriate CPU would cause `SIGILL`, but the entire backend is only +compiled with appropriate `target_feature`s, so this cannot occur. + +# Performance + +Benchmarks are run using [`criterion.rs`][criterion]: + +```sh +cargo bench --no-default-features --features "std u32_backend" +cargo bench --no-default-features --features "std u64_backend" +# Uses avx2 or ifma only if compiled for an appropriate target. +export RUSTFLAGS="-C target_cpu=native" +cargo bench --no-default-features --features "std simd_backend" +``` + +Performance is a secondary goal behind correctness, safety, and +clarity, but we aim to be competitive with other implementations. + +# FFI + +Unfortunately, we have no plans to add FFI to `curve25519-dalek` directly. The +reason is that we use Rust features to provide an API that maintains safety +invariants, which are not possible to maintain across an FFI boundary. For +instance, as described in the _Safety_ section above, invalid points are +impossible to construct, and this would not be the case if we exposed point +operations over FFI. + +However, `curve25519-dalek` is designed as a *mid-level* API, aimed at +implementing other, higher-level primitives. Instead of providing FFI at the +mid-level, our suggestion is to implement the higher-level primitive (a +signature, PAKE, ZKP, etc) in Rust, using `curve25519-dalek` as a dependency, +and have that crate provide a minimal, byte-buffer-oriented FFI specific to +that primitive. + +# Contributing + +Please see [CONTRIBUTING.md][contributing]. + +Patches and pull requests should be make against the `develop` +branch, **not** `master`. + +# About + +**SPOILER ALERT:** *The Twelfth Doctor's first encounter with the Daleks is in +his second full episode, "Into the Dalek". A beleaguered ship of the "Combined +Galactic Resistance" has discovered a broken Dalek that has turned "good", +desiring to kill all other Daleks. The Doctor, Clara and a team of soldiers +are miniaturized and enter the Dalek, which the Doctor names Rusty. They +repair the damage, but accidentally restore it to its original nature, causing +it to go on the rampage and alert the Dalek fleet to the whereabouts of the +rebel ship. However, the Doctor manages to return Rusty to its previous state +by linking his mind with the Dalek's: Rusty shares the Doctor's view of the +universe's beauty, but also his deep hatred of the Daleks. Rusty destroys the +other Daleks and departs the ship, determined to track down and bring an end +to the Dalek race.* + +`curve25519-dalek` is authored by Isis Agora Lovecruft and Henry de Valence. + +Portions of this library were originally a port of [Adam Langley's +Golang ed25519 library](https://github.com/agl/ed25519), which was in +turn a port of the reference `ref10` implementation. Most of this code, +including the 32-bit field arithmetic, has since been rewritten. + +The fast `u32` and `u64` scalar arithmetic was implemented by Andrew Moon, and +the addition chain for scalar inversion was provided by Brian Smith. The +optimised batch inversion was contributed by Sean Bowe and Daira Hopwood. + +The `no_std` and `zeroize` support was contributed by Tony Arcieri. + +Thanks also to Ashley Hauck, Lucas Salibian, and Manish Goregaokar for their +contributions. + +[ed25519-dalek]: https://github.com/dalek-cryptography/ed25519-dalek +[x25519-dalek]: https://github.com/dalek-cryptography/x25519-dalek +[contributing]: https://github.com/dalek-cryptography/curve25519-dalek/blob/master/CONTRIBUTING.md +[docs-external]: https://doc.dalek.rs/curve25519_dalek/ +[docs-internal]: https://doc-internal.dalek.rs/curve25519_dalek/ +[criterion]: https://github.com/japaric/criterion.rs +[parallel_doc]: https://doc-internal.dalek.rs/curve25519_dalek/backend/vector/avx2/index.html +[subtle_doc]: https://doc.dalek.rs/subtle/ diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/benches/dalek_benchmarks.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/benches/dalek_benchmarks.rs new file mode 100644 index 0000000..15d87a2 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/benches/dalek_benchmarks.rs @@ -0,0 +1,339 @@ +#![allow(non_snake_case)] + +extern crate rand; +use rand::rngs::OsRng; +use rand::thread_rng; + +#[macro_use] +extern crate criterion; + +use criterion::BatchSize; +use criterion::Criterion; + +extern crate curve25519_dalek; + +use curve25519_dalek::constants; +use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::field::FieldElement; + +static BATCH_SIZES: [usize; 5] = [1, 2, 4, 8, 16]; +static MULTISCALAR_SIZES: [usize; 13] = [1, 2, 4, 8, 16, 32, 64, 128, 256, 384, 512, 768, 1024]; + +mod edwards_benches { + use super::*; + + use curve25519_dalek::edwards::EdwardsPoint; + + fn compress(c: &mut Criterion) { + let B = &constants::ED25519_BASEPOINT_POINT; + c.bench_function("EdwardsPoint compression", move |b| b.iter(|| B.compress())); + } + + fn decompress(c: &mut Criterion) { + let B_comp = &constants::ED25519_BASEPOINT_COMPRESSED; + c.bench_function("EdwardsPoint decompression", move |b| { + b.iter(|| B_comp.decompress().unwrap()) + }); + } + + fn consttime_fixed_base_scalar_mul(c: &mut Criterion) { + let B = &constants::ED25519_BASEPOINT_TABLE; + let s = Scalar::from(897987897u64).invert(); + c.bench_function("Constant-time fixed-base scalar mul", move |b| { + b.iter(|| B * &s) + }); + } + + fn consttime_variable_base_scalar_mul(c: &mut Criterion) { + let B = &constants::ED25519_BASEPOINT_POINT; + let s = Scalar::from(897987897u64).invert(); + c.bench_function("Constant-time variable-base scalar mul", move |b| { + b.iter(|| B * s) + }); + } + + fn vartime_double_base_scalar_mul(c: &mut Criterion) { + c.bench_function("Variable-time aA+bB, A variable, B fixed", |bench| { + let mut rng = thread_rng(); + let A = &Scalar::random(&mut rng) * &constants::ED25519_BASEPOINT_TABLE; + bench.iter_batched( + || (Scalar::random(&mut rng), Scalar::random(&mut rng)), + |(a, b)| EdwardsPoint::vartime_double_scalar_mul_basepoint(&a, &A, &b), + BatchSize::SmallInput, + ); + }); + } + + criterion_group! { + name = edwards_benches; + config = Criterion::default(); + targets = + compress, + decompress, + consttime_fixed_base_scalar_mul, + consttime_variable_base_scalar_mul, + vartime_double_base_scalar_mul, + } +} + +mod multiscalar_benches { + use super::*; + + use curve25519_dalek::edwards::EdwardsPoint; + use curve25519_dalek::edwards::VartimeEdwardsPrecomputation; + use curve25519_dalek::traits::MultiscalarMul; + use curve25519_dalek::traits::VartimeMultiscalarMul; + use curve25519_dalek::traits::VartimePrecomputedMultiscalarMul; + + fn construct_scalars(n: usize) -> Vec { + let mut rng = thread_rng(); + (0..n).map(|_| Scalar::random(&mut rng)).collect() + } + + fn construct_points(n: usize) -> Vec { + let mut rng = thread_rng(); + (0..n) + .map(|_| &Scalar::random(&mut rng) * &constants::ED25519_BASEPOINT_TABLE) + .collect() + } + + fn construct(n: usize) -> (Vec, Vec) { + (construct_scalars(n), construct_points(n)) + } + + fn consttime_multiscalar_mul(c: &mut Criterion) { + c.bench_function_over_inputs( + "Constant-time variable-base multiscalar multiplication", + |b, &&size| { + let points = construct_points(size); + // This is supposed to be constant-time, but we might as well + // rerandomize the scalars for every call just in case. + b.iter_batched( + || construct_scalars(size), + |scalars| EdwardsPoint::multiscalar_mul(&scalars, &points), + BatchSize::SmallInput, + ); + }, + &MULTISCALAR_SIZES, + ); + } + + fn vartime_multiscalar_mul(c: &mut Criterion) { + c.bench_function_over_inputs( + "Variable-time variable-base multiscalar multiplication", + |b, &&size| { + let points = construct_points(size); + // Rerandomize the scalars for every call to prevent + // false timings from better caching (e.g., the CPU + // cache lifts exactly the right table entries for the + // benchmark into the highest cache levels). + b.iter_batched( + || construct_scalars(size), + |scalars| EdwardsPoint::vartime_multiscalar_mul(&scalars, &points), + BatchSize::SmallInput, + ); + }, + &MULTISCALAR_SIZES, + ); + } + + fn vartime_precomputed_pure_static(c: &mut Criterion) { + c.bench_function_over_inputs( + "Variable-time fixed-base multiscalar multiplication", + move |b, &&total_size| { + let static_size = total_size; + + let static_points = construct_points(static_size); + let precomp = VartimeEdwardsPrecomputation::new(&static_points); + // Rerandomize the scalars for every call to prevent + // false timings from better caching (e.g., the CPU + // cache lifts exactly the right table entries for the + // benchmark into the highest cache levels). + b.iter_batched( + || construct_scalars(static_size), + |scalars| precomp.vartime_multiscalar_mul(&scalars), + BatchSize::SmallInput, + ); + }, + &MULTISCALAR_SIZES, + ); + } + + fn vartime_precomputed_helper(c: &mut Criterion, dynamic_fraction: f64) { + let label = format!( + "Variable-time mixed-base multiscalar multiplication ({:.0}pct dyn)", + 100.0 * dynamic_fraction, + ); + c.bench_function_over_inputs( + &label, + move |b, &&total_size| { + let dynamic_size = ((total_size as f64) * dynamic_fraction) as usize; + let static_size = total_size - dynamic_size; + + let static_points = construct_points(static_size); + let dynamic_points = construct_points(dynamic_size); + let precomp = VartimeEdwardsPrecomputation::new(&static_points); + // Rerandomize the scalars for every call to prevent + // false timings from better caching (e.g., the CPU + // cache lifts exactly the right table entries for the + // benchmark into the highest cache levels). Timings + // should be independent of points so we don't + // randomize them. + b.iter_batched( + || { + ( + construct_scalars(static_size), + construct_scalars(dynamic_size), + ) + }, + |(static_scalars, dynamic_scalars)| { + precomp.vartime_mixed_multiscalar_mul( + &static_scalars, + &dynamic_scalars, + &dynamic_points, + ) + }, + BatchSize::SmallInput, + ); + }, + &MULTISCALAR_SIZES, + ); + } + + fn vartime_precomputed_00_pct_dynamic(c: &mut Criterion) { + vartime_precomputed_helper(c, 0.0); + } + + fn vartime_precomputed_20_pct_dynamic(c: &mut Criterion) { + vartime_precomputed_helper(c, 0.2); + } + + fn vartime_precomputed_50_pct_dynamic(c: &mut Criterion) { + vartime_precomputed_helper(c, 0.5); + } + + criterion_group! { + name = multiscalar_benches; + // Lower the sample size to run the benchmarks faster + config = Criterion::default().sample_size(15); + targets = + consttime_multiscalar_mul, + vartime_multiscalar_mul, + vartime_precomputed_pure_static, + vartime_precomputed_00_pct_dynamic, + vartime_precomputed_20_pct_dynamic, + vartime_precomputed_50_pct_dynamic, + } +} + +mod ristretto_benches { + use super::*; + use curve25519_dalek::ristretto::RistrettoPoint; + + fn compress(c: &mut Criterion) { + c.bench_function("RistrettoPoint compression", |b| { + let B = &constants::RISTRETTO_BASEPOINT_POINT; + b.iter(|| B.compress()) + }); + } + + fn decompress(c: &mut Criterion) { + c.bench_function("RistrettoPoint decompression", |b| { + let B_comp = &constants::RISTRETTO_BASEPOINT_COMPRESSED; + b.iter(|| B_comp.decompress().unwrap()) + }); + } + + fn elligator(c: &mut Criterion) { + let fe_bytes = [0u8; 32]; + let fe = FieldElement::from_bytes(&fe_bytes); + + c.bench_function("RistrettoPoint Elligator", |b| { + b.iter(|| RistrettoPoint::elligator_ristretto_flavor(&fe)); + }); + } + + fn double_and_compress_batch(c: &mut Criterion) { + c.bench_function_over_inputs( + "Batch Ristretto double-and-encode", + |b, &&size| { + let mut rng = OsRng; + let points: Vec = (0..size) + .map(|_| RistrettoPoint::random(&mut rng)) + .collect(); + b.iter(|| RistrettoPoint::double_and_compress_batch(&points)); + }, + &BATCH_SIZES, + ); + } + + criterion_group! { + name = ristretto_benches; + config = Criterion::default(); + targets = + compress, + decompress, + elligator, + double_and_compress_batch, + } +} + +mod montgomery_benches { + use super::*; + + fn montgomery_ladder(c: &mut Criterion) { + c.bench_function("Montgomery pseudomultiplication", |b| { + let B = constants::X25519_BASEPOINT; + let s = Scalar::from(897987897u64).invert(); + b.iter(|| B * s); + }); + } + + criterion_group! { + name = montgomery_benches; + config = Criterion::default(); + targets = montgomery_ladder, + } +} + +mod scalar_benches { + use super::*; + + fn scalar_inversion(c: &mut Criterion) { + c.bench_function("Scalar inversion", |b| { + let s = Scalar::from(897987897u64).invert(); + b.iter(|| s.invert()); + }); + } + + fn batch_scalar_inversion(c: &mut Criterion) { + c.bench_function_over_inputs( + "Batch scalar inversion", + |b, &&size| { + let mut rng = OsRng; + let scalars: Vec = (0..size).map(|_| Scalar::random(&mut rng)).collect(); + b.iter(|| { + let mut s = scalars.clone(); + Scalar::batch_invert(&mut s); + }); + }, + &BATCH_SIZES, + ); + } + + criterion_group! { + name = scalar_benches; + config = Criterion::default(); + targets = + scalar_inversion, + batch_scalar_inversion, + } +} + +criterion_main!( + scalar_benches::scalar_benches, + montgomery_benches::montgomery_benches, + ristretto_benches::ristretto_benches, + edwards_benches::edwards_benches, + multiscalar_benches::multiscalar_benches, +); diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/dalek-logo-clear.png b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/dalek-logo-clear.png new file mode 100644 index 0000000..d3170d8 Binary files /dev/null and b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/dalek-logo-clear.png differ diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/dalek-logo.png b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/dalek-logo.png new file mode 100644 index 0000000..83d6a0c Binary files /dev/null and b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/dalek-logo.png differ diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/dalek-logo.svg b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/dalek-logo.svg new file mode 100644 index 0000000..3e87a44 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/dalek-logo.svg @@ -0,0 +1 @@ +dalek \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/rustdoc-include-katex-header.html b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/rustdoc-include-katex-header.html new file mode 100644 index 0000000..bc4e3d8 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/assets/rustdoc-include-katex-header.html @@ -0,0 +1,10 @@ + + + + + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/avx2-notes.md b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/avx2-notes.md new file mode 100644 index 0000000..87992b3 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/avx2-notes.md @@ -0,0 +1,140 @@ +An AVX2 implementation of the vectorized point operation strategy. + +# Field element representation + +Our strategy is to implement 4-wide multiplication and squaring by +wordslicing, using one 64-bit AVX2 lane for each field element. Field +elements are represented in the usual way as 10 `u32` limbs in radix +\\(25.5\\) (i.e., alternating between \\(2\^{26}\\) for even limbs and +\\(2\^{25}\\) for odd limbs). This has the effect that passing between +the parallel 32-bit AVX2 representation and the serial 64-bit +representation (which uses radix \\(2^{51}\\)) amounts to regrouping +digits. + +The field element representation is oriented around the AVX2 +`vpmuluqdq` instruction, which multiplies the low 32 bits of each +64-bit lane of each operand to produce a 64-bit result. + +```text,no_run +(a1 ?? b1 ?? c1 ?? d1 ??) +(a2 ?? b2 ?? c2 ?? d2 ??) + +(a1*a2 b1*b2 c1*c2 d1*d2) +``` + +To unpack 32-bit values into 64-bit lanes for use in multiplication +it would be convenient to use the `vpunpck[lh]dq` instructions, +which unpack and interleave the low and high 32-bit lanes of two +source vectors. +However, the AVX2 versions of these instructions are designed to +operate only within 128-bit lanes of the 256-bit vectors, so that +interleaving the low lanes of `(a0 b0 c0 d0 a1 b1 c1 d1)` with zero +gives `(a0 00 b0 00 a1 00 b1 00)`. Instead, we pre-shuffle the data +layout as `(a0 b0 a1 b1 c0 d0 c1 d1)` so that we can unpack the +"low" and "high" parts as + +```text,no_run +(a0 00 b0 00 c0 00 d0 00) +(a1 00 b1 00 c1 00 d1 00) +``` + +The data layout for a vector of four field elements \\( (a,b,c,d) +\\) with limbs \\( a_0, a_1, \ldots, a_9 \\) is as `[u32x8; 5]` in +the form + +```text,no_run +(a0 b0 a1 b1 c0 d0 c1 d1) +(a2 b2 a3 b3 c2 d2 c3 d3) +(a4 b4 a5 b5 c4 d4 c5 d5) +(a6 b6 a7 b7 c6 d6 c7 d7) +(a8 b8 a9 b9 c8 d8 c9 d9) +``` + +Since this breaks cleanly into two 128-bit lanes, it may be possible +to adapt it to 128-bit vector instructions such as NEON without too +much difficulty. + +# Avoiding Overflow in Doubling + +To analyze the size of the field element coefficients during the +computations, we can parameterize the bounds on the limbs of each +field element by \\( b \in \mathbb R \\) representing the excess bits +above that limb's radix, so that each limb is bounded by either +\\(2\^{25+b} \\) or \\( 2\^{26+b} \\), as appropriate. + +The multiplication routine requires that its inputs are bounded with +\\( b < 1.75 \\), in order to fit a multiplication by \\( 19 \\) +into 32 bits. Since \\( \lg 19 < 4.25 \\), \\( 19x < 2\^{32} \\) +when \\( x < 2\^{27.75} = 2\^{26 + 1.75} \\). However, this is only +required for one of the inputs; the other can grow up to \\( b < 2.5 +\\). + +In addition, the multiplication and squaring routines do not +canonically reduce their outputs, but can leave some small uncarried +excesses, so that their reduced outputs are bounded with +\\( b < 0.007 \\). + +The non-parallel portion of the doubling formulas is +$$ +\begin{aligned} +(S\_5 &&,&& S\_6 &&,&& S\_8 &&,&& S\_9 ) +&\gets +(S\_1 + S\_2 &&,&& S\_1 - S\_2 &&,&& S\_1 + 2S\_3 - S\_2 &&,&& S\_1 + S\_2 - S\_4) +\end{aligned} +$$ + +Computing \\( (S\_5, S\_6, S\_8, S\_9 ) \\) as +$$ +\begin{matrix} + & S\_1 & S\_1 & S\_1 & S\_1 \\\\ ++& S\_2 & & & S\_2 \\\\ ++& & & S\_3 & \\\\ ++& & & S\_3 & \\\\ ++& & 2p & 2p & 2p \\\\ +-& & S\_2 & S\_2 & \\\\ +-& & & & S\_4 \\\\ +=& S\_5 & S\_6 & S\_8 & S\_9 +\end{matrix} +$$ +results in bit-excesses \\( < (1.01, 1.60, 2.33, 2.01)\\) for +\\( (S\_5, S\_6, S\_8, S\_9 ) \\). The products we want to compute +are then +$$ +\begin{aligned} +X\_3 &\gets S\_8 S\_9 \leftrightarrow (2.33, 2.01) \\\\ +Y\_3 &\gets S\_5 S\_6 \leftrightarrow (1.01, 1.60) \\\\ +Z\_3 &\gets S\_8 S\_6 \leftrightarrow (2.33, 1.60) \\\\ +T\_3 &\gets S\_5 S\_9 \leftrightarrow (1.01, 2.01) +\end{aligned} +$$ +which are too large: it's not possible to arrange the multiplicands so +that one vector has \\(b < 2.5\\) and the other has \\( b < 1.75 \\). +However, if we flip the sign of \\( S\_4 = S\_0\^2 \\) during +squaring, so that we output \\(S\_4' = -S\_4 \pmod p\\), then we can +compute +$$ +\begin{matrix} + & S\_1 & S\_1 & S\_1 & S\_1 \\\\ ++& S\_2 & & & S\_2 \\\\ ++& & & S\_3 & \\\\ ++& & & S\_3 & \\\\ ++& & & & S\_4' \\\\ ++& & 2p & 2p & \\\\ +-& & S\_2 & S\_2 & \\\\ +=& S\_5 & S\_6 & S\_8 & S\_9 +\end{matrix} +$$ +resulting in bit-excesses \\( < (1.01, 1.60, 2.33, 1.60)\\) for +\\( (S\_5, S\_6, S\_8, S\_9 ) \\). The products we want to compute +are then +$$ +\begin{aligned} +X\_3 &\gets S\_8 S\_9 \leftrightarrow (2.33, 1.60) \\\\ +Y\_3 &\gets S\_5 S\_6 \leftrightarrow (1.01, 1.60) \\\\ +Z\_3 &\gets S\_8 S\_6 \leftrightarrow (2.33, 1.60) \\\\ +T\_3 &\gets S\_5 S\_9 \leftrightarrow (1.01, 1.60) +\end{aligned} +$$ +whose right-hand sides are all bounded with \\( b < 1.75 \\) and +whose left-hand sides are all bounded with \\( b < 2.5 \\), +so that we can avoid any intermediate reductions. diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/ifma-notes.md b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/ifma-notes.md new file mode 100644 index 0000000..c6fd3b3 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/ifma-notes.md @@ -0,0 +1,580 @@ +An AVX512-IFMA implementation of the vectorized point operation +strategy. + +# IFMA instructions + +AVX512-IFMA is an extension to AVX-512 consisting of two instructions: + +* `vpmadd52luq`: packed multiply of unsigned 52-bit integers and add + the low 52 product bits to 64-bit accumulators; +* `vpmadd52huq`: packed multiply of unsigned 52-bit integers and add + the high 52 product bits to 64-bit accumulators; + +These operate on 64-bit lanes of their source vectors, taking the low +52 bits of each lane of each source vector, computing the 104-bit +products of each pair, and then adding either the high or low 52 bits +of the 104-bit products to the 64-bit lanes of the destination vector. +The multiplication is performed internally by reusing circuitry for +floating-point arithmetic. Although these instructions are part of +AVX512, the AVX512VL (vector length) extension (present whenever IFMA +is) allows using them with 512, 256, or 128-bit operands. + +This provides a major advantage to vectorized integer operations: +previously, vector operations could only use a \\(32 \times 32 +\rightarrow 64\\)-bit multiplier, while serial code could use a +\\(64\times 64 \rightarrow 128\\)-bit multiplier. + +## IFMA for big-integer multiplications + +A detailed example of the intended use of the IFMA instructions can be +found in a 2016 paper by Gueron and Krasnov, [_Accelerating Big +Integer Arithmetic Using Intel IFMA Extensions_][2016_gueron_krasnov]. +The basic idea is that multiplication of large integers (such as 1024, +2048, or more bits) can be performed as follows. + +First, convert a “packed” 64-bit representation +\\[ +\begin{aligned} +x &= x'_0 + x'_1 2^{64} + x'_2 2^{128} + \cdots \\\\ +y &= y'_0 + y'_1 2^{64} + y'_2 2^{128} + \cdots +\end{aligned} +\\] +into a “redundant” 52-bit representation +\\[ +\begin{aligned} +x &= x_0 + x_1 2^{52} + x_2 2^{104} + \cdots \\\\ +y &= y_0 + y_1 2^{52} + y_2 2^{104} + \cdots +\end{aligned} +\\] +with each \\(x_i, y_j\\) in a 64-bit lane. + +Writing the product as \\(z = z_0 + z_1 2^{52} + z_2 2^{104} + \cdots\\), +the “schoolbook” multiplication strategy gives +\\[ +\begin{aligned} +&z_0 &&=& x_0 & y_0 & & & & & & & & \\\\ +&z_1 &&=& x_1 & y_0 &+ x_0 & y_1 & & & & & & \\\\ +&z_2 &&=& x_2 & y_0 &+ x_1 & y_1 &+ x_0 & y_2 & & & & \\\\ +&z_3 &&=& x_3 & y_0 &+ x_2 & y_1 &+ x_1 & y_2 &+ x_0 & y_3 & & \\\\ +&z_4 &&=& \vdots\\;&\\;\vdots &+ x_3 & y_1 &+ x_2 & y_2 &+ x_1 & y_3 &+ \cdots& \\\\ +&z_5 &&=& & & \vdots\\;&\\;\vdots &+ x_3 & y_2 &+ x_2 & y_3 &+ \cdots& \\\\ +&z_6 &&=& & & & & \vdots\\;&\\;\vdots &+ x_3 & y_3 &+ \cdots& \\\\ +&z_7 &&=& & & & & & & \vdots\\;&\\;\vdots &+ \cdots& \\\\ +&\vdots&&=& & & & & & & & & \ddots& \\\\ +\end{aligned} +\\] +Notice that the product coefficient \\(z_k\\), representing the value +\\(z_k 2^{52k}\\), is the sum of all product terms +\\( +(x_i 2^{52 i}) (y_j 2^{52 j}) +\\) +with \\(k = i + j\\). +Write the IFMA operators \\(\mathrm{lo}(a,b)\\), denoting the low +\\(52\\) bits of \\(ab\\), and +\\(\mathrm{hi}(a,b)\\), denoting the high \\(52\\) bits of +\\(ab\\). +Now we can rewrite the product terms as +\\[ +\begin{aligned} +(x_i 2^{52 i}) (y_j 2^{52 j}) +&= +2^{52 (i+j)}( +\mathrm{lo}(x_i, y_j) + +\mathrm{hi}(x_i, y_j) 2^{52} +) +\\\\ +&= +\mathrm{lo}(x_i, y_j) 2^{52 (i+j)} + +\mathrm{hi}(x_i, y_j) 2^{52 (i+j+1)}. +\end{aligned} +\\] +This means that the low half of \\(x_i y_j\\) can be accumulated onto +the product limb \\(z_{i+j}\\) and the high half can be directly +accumulated onto the next-higher product limb \\(z_{i+j+1}\\) with no +additional operations. This allows rewriting the schoolbook +multiplication into the form +\\[ +\begin{aligned} +&z_0 &&=& \mathrm{lo}(x_0,&y_0) & & & & & & & & & & \\\\ +&z_1 &&=& \mathrm{lo}(x_1,&y_0) &+\mathrm{hi}(x_0,&y_0) &+\mathrm{lo}(x_0,&y_1) & & & & & & \\\\ +&z_2 &&=& \mathrm{lo}(x_2,&y_0) &+\mathrm{hi}(x_1,&y_0) &+\mathrm{lo}(x_1,&y_1) &+\mathrm{hi}(x_0,&y_1) &+\mathrm{lo}(x_0,&y_2) & & \\\\ +&z_3 &&=& \mathrm{lo}(x_3,&y_0) &+\mathrm{hi}(x_2,&y_0) &+\mathrm{lo}(x_2,&y_1) &+\mathrm{hi}(x_1,&y_1) &+\mathrm{lo}(x_1,&y_2) &+ \cdots& \\\\ +&z_4 &&=& \vdots\\;&\\;\vdots &+\mathrm{hi}(x_3,&y_0) &+\mathrm{lo}(x_3,&y_1) &+\mathrm{hi}(x_2,&y_1) &+\mathrm{lo}(x_2,&y_2) &+ \cdots& \\\\ +&z_5 &&=& & & \vdots\\;&\\;\vdots & \vdots\\;&\\;\vdots &+\mathrm{hi}(x_3,&y_1) &+\mathrm{lo}(x_3,&y_2) &+ \cdots& \\\\ +&z_6 &&=& & & & & & & \vdots\\;&\\;\vdots & \vdots\\;&\\;\vdots &+ \cdots& \\\\ +&\vdots&&=& & & & & & & & & & & \ddots& \\\\ +\end{aligned} +\\] +Gueron and Krasnov implement multiplication by constructing vectors +out of the columns of this diagram, so that the source operands for +the IFMA instructions are of the form \\((x_0, x_1, x_2, \ldots)\\) +and \\((y_i, y_i, y_i, \ldots)\\). +After performing the multiplication, +the product terms \\(z_i\\) are then repacked into a 64-bit representation. + +## An alternative strategy + +The strategy described above is aimed at big-integer multiplications, +such as 1024, 2048, or 4096 bits, which would be used for applications +like RSA. However, elliptic curve cryptography uses much smaller field +sizes, such as 256 or 384 bits, so a different strategy is needed. + +The parallel Edwards formulas provide parallelism at the level of the +formulas for curve operations. This means that instead of scanning +through the terms of the source operands and parallelizing *within* a +field element (as described above), we can arrange the computation in +product-scanning form and parallelize *across* field elements (as +described below). + +The parallel Edwards +formulas provide 4-way parallelism, so they can be implemented using +256-bit vectors using a single 64-bit lane for each element, or using +512-bit vectors using two 64-bit lanes. +The only available CPU supporting IFMA (the +i3-8121U) executes 512-bit IFMA instructions at half rate compared to +256-bit instructions, so for now there's no throughput advantage to +using 512-bit IFMA instructions, and this implementation uses 256-bit +vectors. + +To extend this to 512-bit vectors, it's only only necessary to achieve +2-way parallelism, and it's possible (with a small amount of overhead) +to create a hybrid strategy that operates entirely within 128-bit +lanes. This means that cross-lane operations can use the faster +`vpshufd` (1c latency) instead of a general shuffle instruction (3c +latency). + +# Choice of radix + +The inputs to IFMA instructions are 52 bits wide, so the radix \\(r\\) +used to represent a multiprecision integer must be \\( r \leq 52 \\). +The obvious choice is the "native" radix \\(r = 52\\). + +As described above, this choice +has the advantage that for \\(x_i, y_j \in [0,2^{52})\\), the product term +\\[ +\begin{aligned} +(x_i 2^{52 i}) (y_j 2^{52 j}) +&= +2^{52 (i+j)}( +\mathrm{lo}(x_i, y_j) + +\mathrm{hi}(x_i, y_j) 2^{52} +) +\\\\ +&= +\mathrm{lo}(x_i, y_j) 2^{52 (i+j)} + +\mathrm{hi}(x_i, y_j) 2^{52 (i+j+1)}, +\end{aligned} +\\] +so that the low and high halves of the product can be directly accumulated +onto the product limbs. +In contrast, when using a smaller radix \\(r = 52 - k\\), +the product term has the form +\\[ +\begin{aligned} +(x_i 2^{r i}) (y_j 2^{r j}) +&= +2^{r (i+j)}( +\mathrm{lo}(x_i, y_j) + +\mathrm{hi}(x_i, y_j) 2^{52} +) +\\\\ +&= +\mathrm{lo}(x_i, y_j) 2^{r (i+j)} + +( +\mathrm{hi}(x_i, y_j) 2^k +) +2^{r (i+j+1)}. +\end{aligned} +\\] +What's happening is that the product \\(x_i y_j\\) of size \\(2r\\) +bits is split not at \\(r\\) but at \\(52\\), so \\(k\\) product bits +are placed into the low half instead of the high half. This means +that the high half of the product cannot be directly accumulated onto +\\(z_{i+j+1}\\), but must first be multiplied by \\(2^k\\) (i.e., left +shifted by \\(k\\)). In addition, the low half of the product is +\\(52\\) bits large instead of \\(r\\) bits. + +## Handling offset product terms + +[Drucker and Gueron][2018_drucker_gueron] analyze the choice of radix +in the context of big-integer squaring, outlining three ways to handle +the offset product terms, before concluding that all of them are +suboptimal: + +1. Shift the results after accumulation; +2. Shift the input operands before multiplication; +3. Split the MAC operation, accumulating into a zeroed register, + shifting the result, and then adding. + +The first option is rejected because it could double-shift some +previously accumulated terms, the second doesn't work because the +inputs could become larger than \\(52\\) bits, and the third requires +additional instructions to handle the shifting and adding. + +Based on an analysis of total number of instructions, they suggest an +addition to the instruction set, which they call `FMSA` (fused +multiply-shift-add). This would shift the result according to an 8-bit +immediate value before accumulating it into the destination register. + +However, this change to the instruction set doesn't seem to be +necessary. Instead, the product terms can be grouped according to +their coefficients, accumulated together, then shifted once before +adding them to the final sum. This uses an extra register, shift, and +add, but only once per product term (accumulation target), not once +per source term (as in the Drucker-Gueron paper). + +Moreover, because IFMA instructions execute only on two ports +(presumably 0 and 1), while adds and shifts can execute on three ports +(0, 1, and 5), the adds and shifts can execute independently of the +IFMA operations, as long as there is not too much pressure on port 5. +This means that, although the total number of instructions increases, +the shifts and adds do not necessarily increase the execution time, as +long as throughput is limited by IFMA operations. + +Finally, because IFMA instructions have 4 cycle latency and 0.5/1 +cycle throughput (for 256/512 bit vectors), maximizing IFMA throughput +requires either 8 (for 256) or 4 (for 512) independent operations. So +accumulating groups of terms independently before adding them at the +end may be necessary anyways, in order to prevent long chains of +dependent instructions. + +## Advantages of a smaller radix + +Using a smaller radix has other advantages. Although radix \\(52\\) +is an unsaturated representation from the point of view of the +\\(64\\)-bit accumulators (because up to 4096 product terms can be +accumulated without carries), it's a saturated representation from the +point of view of the multiplier (since \\(52\\)-bit values are the +maximum input size). + +Because the inputs to a multiplication must have all of their limbs +bounded by \\(2^{52}\\), limbs in excess of \\(2^{52}\\) must be +reduced before they can be used as an input. The +[Gueron-Krasnov][2016_gueron_krasnov] paper suggests normalizing +values using a standard, sequential carry chain: for each limb, add +the carryin from reducing the previous limb, compute the carryout and +reduce the current limb, then move to the next limb. + +However, when using a smaller radix, such as \\(51\\), each limb can +store a carry bit and still be used as the input to a multiplication. +This means that the inputs do not need to be normalized, and instead +of using a sequential carry chain, we can compute all carryouts in +parallel, reduce all limbs in parallel, and then add the carryins in +parallel (possibly growing the limb values by one bit). + +Because the output of this partial reduction is an acceptable +multiplication input, we can "close the loop" using partial reductions +and never have to normalize to a canonical representation through the +entire computation, in contrast to the Gueron-Krasnov approach, which +converts back to a packed representation after every operation. (This +idea seems to trace back to at least as early as [this 1999 +paper][1999_walter]). + +Using \\(r = 51\\) is enough to keep a carry bit in each limb and +avoid normalizations. What about an even smaller radix? One reason +to choose a smaller radix would be to align the limb boundaries with +an inline reduction (for instance, choosing \\(r = 43\\) for the +Mersenne field \\(p = 2^{127} - 1\\)), but for \\(p = 2^{255 - 19}\\), +\\(r = 51 = 255/5\\) is the natural choice. + +# Multiplication + +The inputs to a multiplication are two field elements +\\[ +\begin{aligned} +x &= x_0 + x_1 2^{51} + x_2 2^{102} + x_3 2^{153} + x_4 2^{204} \\\\ +y &= y_0 + y_1 2^{51} + y_2 2^{102} + y_3 2^{153} + y_4 2^{204}, +\end{aligned} +\\] +with limbs in range \\([0,2^{52})\\). + +Writing the product terms as +\\[ +\begin{aligned} +z &= z_0 + z_1 2^{51} + z_2 2^{102} + z_3 2^{153} + z_4 2^{204} \\\\ + &+ z_5 2^{255} + z_6 2^{306} + z_7 2^{357} + z_8 2^{408} + z_9 2^{459}, +\end{aligned} +\\] +a schoolbook multiplication in product scanning form takes the form +\\[ +\begin{aligned} +z_0 &= x_0 y_0 \\\\ +z_1 &= x_1 y_0 + x_0 y_1 \\\\ +z_2 &= x_2 y_0 + x_1 y_1 + x_0 y_2 \\\\ +z_3 &= x_3 y_0 + x_2 y_1 + x_1 y_2 + x_0 y_3 \\\\ +z_4 &= x_4 y_0 + x_3 y_1 + x_2 y_2 + x_1 y_3 + x_0 y_4 \\\\ +z_5 &= x_4 y_1 + x_3 y_2 + x_2 y_3 + x_1 y_4 \\\\ +z_6 &= x_4 y_2 + x_3 y_3 + x_2 y_4 \\\\ +z_7 &= x_4 y_3 + x_3 y_4 \\\\ +z_8 &= x_4 y_4 \\\\ +z_9 &= 0 \\\\ +\end{aligned} +\\] +Each term \\(x_i y_j\\) can be written in terms of IFMA operations as +\\[ +x_i y_j = \mathrm{lo}(x_i,y_j) + 2\mathrm{hi}(x_i,y_j)2^{51}. +\\] +Substituting this equation into the schoolbook multiplication, then +moving terms to eliminate the \\(2^{51}\\) factors gives +\\[ +\begin{aligned} +z_0 &= \mathrm{lo}(x_0, y_0) \\\\ + &+ \qquad 0 \\\\ +z_1 &= \mathrm{lo}(x_1, y_0) + \mathrm{lo}(x_0, y_1) \\\\ + &+ \qquad 2( \mathrm{hi}(x_0, y_0) )\\\\ +z_2 &= \mathrm{lo}(x_2, y_0) + \mathrm{lo}(x_1, y_1) + \mathrm{lo}(x_0, y_2) \\\\ + &+ \qquad 2( \mathrm{hi}(x_1, y_0) + \mathrm{hi}(x_0, y_1) )\\\\ +z_3 &= \mathrm{lo}(x_3, y_0) + \mathrm{lo}(x_2, y_1) + \mathrm{lo}(x_1, y_2) + \mathrm{lo}(x_0, y_3) \\\\ + &+ \qquad 2( \mathrm{hi}(x_2, y_0) + \mathrm{hi}(x_1, y_1) + \mathrm{hi}(x_0, y_2) )\\\\ +z_4 &= \mathrm{lo}(x_4, y_0) + \mathrm{lo}(x_3, y_1) + \mathrm{lo}(x_2, y_2) + \mathrm{lo}(x_1, y_3) + \mathrm{lo}(x_0, y_4) \\\\ + &+ \qquad 2( \mathrm{hi}(x_3, y_0) + \mathrm{hi}(x_2, y_1) + \mathrm{hi}(x_1, y_2) + \mathrm{hi}(x_0, y_3) )\\\\ +z_5 &= \mathrm{lo}(x_4, y_1) + \mathrm{lo}(x_3, y_2) + \mathrm{lo}(x_2, y_3) + \mathrm{lo}(x_1, y_4) \\\\ + &+ \qquad 2( \mathrm{hi}(x_4, y_0) + \mathrm{hi}(x_3, y_1) + \mathrm{hi}(x_2, y_2) + \mathrm{hi}(x_1, y_3) + \mathrm{hi}(x_0, y_4) )\\\\ +z_6 &= \mathrm{lo}(x_4, y_2) + \mathrm{lo}(x_3, y_3) + \mathrm{lo}(x_2, y_4) \\\\ + &+ \qquad 2( \mathrm{hi}(x_4, y_1) + \mathrm{hi}(x_3, y_2) + \mathrm{hi}(x_2, y_3) + \mathrm{hi}(x_1, y_4) )\\\\ +z_7 &= \mathrm{lo}(x_4, y_3) + \mathrm{lo}(x_3, y_4) \\\\ + &+ \qquad 2( \mathrm{hi}(x_4, y_2) + \mathrm{hi}(x_3, y_3) + \mathrm{hi}(x_2, y_4) )\\\\ +z_8 &= \mathrm{lo}(x_4, y_4) \\\\ + &+ \qquad 2( \mathrm{hi}(x_4, y_3) + \mathrm{hi}(x_3, y_4) )\\\\ +z_9 &= 0 \\\\ + &+ \qquad 2( \mathrm{hi}(x_4, y_4) )\\\\ +\end{aligned} +\\] +As noted above, our strategy will be to multiply and accumulate the +terms with coefficient \\(2\\) separately from those with coefficient +\\(1\\), before combining them at the end. This can alternately be +thought of as accumulating product terms into a *doubly-redundant* +representation, with two limbs for each digit, before collapsing +the doubly-redundant representation by shifts and adds. + +This computation requires 25 `vpmadd52luq` and 25 `vpmadd52huq` +operations. For 256-bit vectors, IFMA operations execute on an +i3-8121U with latency 4 cycles, throughput 0.5 cycles, so executing 50 +instructions requires 25 cycles' worth of throughput. Accumulating +terms with coefficient \\(1\\) and \\(2\\) seperately means that the +longest dependency chain has length 5, so the critical path has length +20 cycles and the bottleneck is throughput. + +# Reduction modulo \\(p\\) + +The next question is how to handle the reduction modulo \\(p\\). +Because \\(p = 2^{255} - 19\\), \\(2^{255} = 19 \pmod p\\), so we can +alternately write +\\[ +\begin{aligned} +z &= z_0 + z_1 2^{51} + z_2 2^{102} + z_3 2^{153} + z_4 2^{204} \\\\ + &+ z_5 2^{255} + z_6 2^{306} + z_7 2^{357} + z_8 2^{408} + z_9 2^{459} +\end{aligned} +\\] +as +\\[ +\begin{aligned} +z &= (z_0 + 19z_5) + (z_1 + 19z_6) 2^{51} + (z_2 + 19z_7) 2^{102} + (z_3 + 19z_8) 2^{153} + (z_4 + 19z_9) 2^{204}. +\end{aligned} +\\] +When using a \\(64 \times 64 \rightarrow 128\\)-bit multiplier, this +can be handled (as in [Ed25519][ed25519_paper]) by premultiplying +source terms by \\(19\\). Since \\(\lg(19) < 4.25\\), this increases +their size by less than \\(4.25\\) bits, and the rest of the +multiplication can be shown to work out. + +Here, we have at most \\(1\\) bit of headroom. In order to allow +premultiplication, we would need to use radix \\(2^{47}\\), which +would require six limbs instead of five. Instead, we compute the high +terms \\(z_5, \ldots, z_9\\), each using two chains of IFMA +operations, then multiply by \\(19\\) and combine with the lower terms +\\(z_0, \ldots, z_4\\). There are two ways to perform the +multiplication by \\(19\\): using more IFMA operations, or using the +`vpmullq` instruction, which computes the low \\(64\\) bits of a \\(64 +\times 64\\)-bit product. However, `vpmullq` has 15c/1.5c +latency/throughput, in contrast to the 4c/0.5c latency/throughput of +IFMA operations, so it seems like a worse choice. + +The high terms \\(z_5, \ldots, z_9\\) are sums of \\(52\\)-bit terms, +so they are larger than \\(52\\) bits. Write these terms in radix \\(52\\) as +\\[ +z_{5+i} = z_{5+i}' + z_{5+i}'' 2^{52}, \qquad z_{5+i}' < 2^{52}. +\\] +Then the contribution of \\(z_{5+i}\\), taken modulo \\(p\\), is +\\[ +\begin{aligned} +z_{5+i} 2^{255} 2^{51 i} +&= +19 (z_{5+i}' + z_{5+i}'' 2^{52}) 2^{51 i} +\\\\ +&= +19 z_{5+i}' 2^{51 i} + 2 \cdot 19 z_{5+i}'' 2^{51 (i+1)} +\\\\ +\end{aligned} +\\] +The products \\(19 z_{5+i}', 19 z_{5+i}''\\) can be written in terms of IFMA operations as +\\[ +\begin{aligned} +19 z_{5+i}' &= \mathrm{lo}(19, z_{5+i}') + 2 \mathrm{hi}(19, z_{5+i}') 2^{51}, \\\\ +19 z_{5+i}'' &= \mathrm{lo}(19, z_{5+i}'') + 2 \mathrm{hi}(19, z_{5+i}'') 2^{51}. \\\\ +\end{aligned} +\\] +Because \\(z_{5+i} < 2^{64}\\), \\(z_{5+i}'' < 2^{12} \\), so \\(19 +z_{5+i}'' < 2^{17} < 2^{52} \\) and \\(\mathrm{hi}(19, z_{5+i}'') = 0\\). +Because IFMA operations ignore the high bits of their source +operands, we do not need to compute \\(z\_{5+i}'\\) explicitly: +the high bits will be ignored. +Combining these observations, we can write +\\[ +\begin{aligned} +z_{5+i} 2^{255} 2^{51 i} +&= +19 z_{5+i}' 2^{51 i} + 2 \cdot 19 z_{5+i}'' 2^{51 (i+1)} +\\\\ +&= +\mathrm{lo}(19, z_{5+i}) 2^{51 i} +\+ 2 \mathrm{hi}(19, z_{5+i}) 2^{51 (i+1)} +\+ 2 \mathrm{lo}(19, z_{5+i}/2^{52}) 2^{51 (i+1)}. +\end{aligned} +\\] + +For \\(i = 0,1,2,3\\), this allows reducing \\(z_{5+i}\\) onto +\\(z_{i}, z_{i+1}\\), and if the low terms are computed using a +doubly-redundant representation, no additional shifts are needed to +handle the \\(2\\) coefficients. For \\(i = 4\\), there's a +complication: the contribution becomes +\\[ +\begin{aligned} +z_{9} 2^{255} 2^{204} +&= +\mathrm{lo}(19, z_{9}) 2^{204} +\+ 2 \mathrm{hi}(19, z_{9}) 2^{255} +\+ 2 \mathrm{lo}(19, z_{9}/2^{52}) 2^{255} +\\\\ +&= +\mathrm{lo}(19, z_{9}) 2^{204} +\+ 2 \mathrm{hi}(19, z_{9}) 19 +\+ 2 \mathrm{lo}(19, z_{9}/2^{52}) 19 +\\\\ +&= +\mathrm{lo}(19, z_{9}) 2^{204} +\+ 2 +\mathrm{lo}(19, \mathrm{hi}(19, z_{9}) + \mathrm{lo}(19, z_{9}/2^{52})). +\\\\ +\end{aligned} +\\] + +It would be possible to cut the number of multiplications from 3 to 2 +by carrying the high part of each \\(z_i\\) onto \\(z_{i+1}\\). This +would eliminate 5 multiplications, clearing 2.5 cycles of port +pressure, at the cost of 5 additions, adding 1.66 cycles of port +pressure. But doing this would create a dependency between terms +(e.g., \\(z_{5}\\) must be computed before the reduction of +\\(z_{6}\\) can begin), whereas with the approach above, all +contributions to all terms are computed independently, to maximize ILP +and flexibility for the processor to schedule instructions. + +This strategy performs 16 IFMA operations, adding two IFMA operations +to each of the \\(2\\)-coefficient terms and one to each of the +\\(1\\)-coefficient terms. Considering the multiplication and +reduction together, we use 66 IFMA operations, requiring 33 cycles' +throughput, while the longest chain of IFMA operations is in the +reduction of \\(z_5\\) onto \\(z_1\\), of length 7 (so 28 cycles, plus +2 cycles to combine the two parts of \\(z_5\\), and the bottleneck is +again throughput. + +Once this is done, we have computed the product terms +\\[ +z = z_0 + z_1 2^{51} + z_2 2^{102} + z_3 2^{153} + z_4 2^{204}, +\\] +without reducing the \\(z_i\\) to fit in \\(52\\) bits. Because the +overall flow of operations alternates multiplications and additions or +subtractions, we would have to perform a reduction after an addition +but before the next multiplication anyways, so there's no benefit to +fully reducing the limbs at the end of a multiplication. Instead, we +leave them unreduced, and track the reduction state using the type +system to ensure that unreduced limbs are not accidentally used as an +input to a multiplication. + +# Squaring + +Squaring operates similarly to multiplication, but with the +possibility to combine identical terms. +As before, we write the input as +\\[ +\begin{aligned} +x &= x_0 + x_1 2^{51} + x_2 2^{102} + x_3 2^{153} + x_4 2^{204} +\end{aligned} +\\] +with limbs in range \\([0,2^{52})\\). +Writing the product terms as +\\[ +\begin{aligned} +z &= z_0 + z_1 2^{51} + z_2 2^{102} + z_3 2^{153} + z_4 2^{204} \\\\ + &+ z_5 2^{255} + z_6 2^{306} + z_7 2^{357} + z_8 2^{408} + z_9 2^{459}, +\end{aligned} +\\] +a schoolbook squaring in product scanning form takes the form +\\[ +\begin{aligned} +z_0 &= x_0 x_0 \\\\ +z_1 &= 2 x_1 x_0 \\\\ +z_2 &= 2 x_2 x_0 + x_1 x_1 \\\\ +z_3 &= 2 x_3 x_0 + 2 x_2 x_1 \\\\ +z_4 &= 2 x_4 x_0 + 2 x_3 x_1 + x_2 x_2 \\\\ +z_5 &= 2 x_4 x_1 + 2 x_3 x_2 \\\\ +z_6 &= 2 x_4 x_2 + x_3 x_3 \\\\ +z_7 &= 2 x_4 x_3 \\\\ +z_8 &= x_4 x_4 \\\\ +z_9 &= 0 \\\\ +\end{aligned} +\\] +As before, we write \\(x_i x_j\\) as +\\[ +x_i x_j = \mathrm{lo}(x_i,x_j) + 2\mathrm{hi}(x_i,x_j)2^{51}, +\\] +and substitute to obtain +\\[ +\begin{aligned} +z_0 &= \mathrm{lo}(x_0, x_0) + 0 \\\\ +z_1 &= 2 \mathrm{lo}(x_1, x_0) + 2 \mathrm{hi}(x_0, x_0) \\\\ +z_2 &= 2 \mathrm{lo}(x_2, x_0) + \mathrm{lo}(x_1, x_1) + 4 \mathrm{hi}(x_1, x_0) \\\\ +z_3 &= 2 \mathrm{lo}(x_3, x_0) + 2 \mathrm{lo}(x_2, x_1) + 4 \mathrm{hi}(x_2, x_0) + 2 \mathrm{hi}(x_1, x_1) \\\\ +z_4 &= 2 \mathrm{lo}(x_4, x_0) + 2 \mathrm{lo}(x_3, x_1) + \mathrm{lo}(x_2, x_2) + 4 \mathrm{hi}(x_3, x_0) + 4 \mathrm{hi}(x_2, x_1) \\\\ +z_5 &= 2 \mathrm{lo}(x_4, x_1) + 2 \mathrm{lo}(x_3, x_2) + 4 \mathrm{hi}(x_4, x_0) + 4 \mathrm{hi}(x_3, x_1) + 2 \mathrm{hi}(x_2, x_2) \\\\ +z_6 &= 2 \mathrm{lo}(x_4, x_2) + \mathrm{lo}(x_3, x_3) + 4 \mathrm{hi}(x_4, x_1) + 4 \mathrm{hi}(x_3, x_2) \\\\ +z_7 &= 2 \mathrm{lo}(x_4, x_3) + 4 \mathrm{hi}(x_4, x_2) + 2 \mathrm{hi}(x_3, x_3) \\\\ +z_8 &= \mathrm{lo}(x_4, x_4) + 4 \mathrm{hi}(x_4, x_3) \\\\ +z_9 &= 0 + 2 \mathrm{hi}(x_4, x_4) \\\\ +\end{aligned} +\\] +To implement these, we group terms by their coefficient, computing +those with coefficient \\(2\\) on set of IFMA chains, and on another +set of chains, we begin with coefficient-\\(4\\) terms, then shift +left before continuing with the coefficient-\\(1\\) terms. +The reduction strategy is the same as for multiplication. + +# Future improvements + +LLVM won't use blend operations on [256-bit vectors yet][llvm_blend], +so there's a bunch of blend instructions that could be omitted. + +Although the multiplications and squarings are much faster, there's no +speedup to the additions and subtractions, so there are diminishing +returns. In fact, the complications in the doubling formulas mean +that doubling is actually slower than readdition. This also suggests +that moving to 512-bit vectors won't be much help for a strategy aimed +at parallelism within a group operation, so to extract performance +gains from 512-bit vectors it will probably be necessary to create a +parallel-friendly multiscalar multiplication algorithm. This could +also help with reducing shuffle pressure. + +The squaring implementation could probably be optimized, but without +`perf` support on Cannonlake it's difficult to make actual +measurements. + +Another improvement would be to implement vectorized square root +computations, which would allow creating an iterator adaptor for point +decompression that bunched decompression operations and executed them +in parallel. This would accelerate batch verification. + +[2016_gueron_krasnov]: https://ieeexplore.ieee.org/document/7563269 +[2018_drucker_gueron]: https://eprint.iacr.org/2018/335 +[1999_walter]: https://pdfs.semanticscholar.org/0e6a/3e8f30b63b556679f5dff2cbfdfe9523f4fa.pdf +[ed25519_paper]: https://ed25519.cr.yp.to/ed25519-20110926.pdf +[llvm_blend]: https://bugs.llvm.org/show_bug.cgi?id=38343 diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/parallel-formulas.md b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/parallel-formulas.md new file mode 100644 index 0000000..22f59cd --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/docs/parallel-formulas.md @@ -0,0 +1,333 @@ +Vectorized implementations of field and point operations, using a +modification of the 4-way parallel formulas of Hisil, Wong, Carter, +and Dawson. + +These notes explain the parallel formulas and our strategy for using +them with SIMD operations. There are two backend implementations: one +using AVX2, and the other using AVX512-IFMA. + +# Overview + +The 2008 paper [_Twisted Edwards Curves Revisited_][hwcd08] by Hisil, +Wong, Carter, and Dawson (HWCD) introduced the “extended coordinates” +and mixed-model representations which are used by most Edwards curve +implementations. + +However, they also describe 4-way parallel formulas for point addition +and doubling: a unified addition algorithm taking an effective +\\(2\mathbf M + 1\mathbf D\\), a doubling algorithm taking an +effective \\(1\mathbf M + 1\mathbf S\\), and a dedicated (i.e., for +distinct points) addition algorithm taking an effective \\(2 \mathbf M +\\). They compare these formulas with a 2-way parallel variant of the +Montgomery ladder. + +Unlike their serial formulas, which are used widely, their parallel +formulas do not seem to have been implemented in software before. The +2-way parallel Montgomery ladder was used in 2015 by Tung Chou's +`sandy2x` implementation. Curiously, however, although the [`sandy2x` +paper][sandy2x] also implements Edwards arithmetic, and cites HWCD08, +it doesn't mention their parallel Edwards formulas. +A 2015 paper by Hernández and López describes an AVX2 implementation +of X25519. Neither the paper nor the code are publicly available, but +it apparently gives only a [slight speedup][avx2trac], suggesting that +it uses a 4-way parallel Montgomery ladder rather than parallel +Edwards formulas. + +The reason may be that HWCD08 describe their formulas as operating on +four independent processors, which would make a software +implementation impractical: all of the operations are too low-latency +to effectively synchronize. But a closer inspection reveals that the +(more expensive) multiplication and squaring steps are uniform, while +the instruction divergence occurs in the (much cheaper) addition and +subtraction steps. This means that a SIMD implementation can perform +the expensive steps uniformly, and handle divergence in the +inexpensive steps using masking. + +These notes describe modifications to the original parallel formulas +to allow a SIMD implementation, and this module contains +implementations of the modified formulas targeting either AVX2 or +AVX512-IFMA. + +# Parallel formulas in HWCD'08 + +The doubling formula is presented in the HWCD paper as follows: + +| Cost | Processor 1 | Processor 2 | Processor 3 | Processor 4 | +|------------------|--------------------------------|--------------------------------|--------------------------------|--------------------------------| +| | idle | idle | idle | \\( R\_1 \gets X\_1 + Y\_1 \\) | +| \\(1\mathbf S\\) | \\( R\_2 \gets X\_1\^2 \\) | \\( R\_3 \gets Y\_1\^2 \\) | \\( R\_4 \gets Z\_1\^2 \\) | \\( R\_5 \gets R\_1\^2 \\) | +| | \\( R\_6 \gets R\_2 + R\_3 \\) | \\( R\_7 \gets R\_2 - R\_3 \\) | \\( R\_4 \gets 2 R\_4 \\) | idle | +| | idle | \\( R\_1 \gets R\_4 + R\_7 \\) | idle | \\( R\_2 \gets R\_6 - R\_5 \\) | +| \\(1\mathbf M\\) | \\( X\_3 \gets R\_1 R\_2 \\) | \\( Y\_3 \gets R\_6 R\_7 \\) | \\( T\_3 \gets R\_2 R\_6 \\) | \\( Z\_3 \gets R\_1 R\_7 \\) | + +and the unified addition algorithm is presented as follows: + +| Cost | Processor 1 | Processor 2 | Processor 3 | Processor 4 | +|------------------|--------------------------------|--------------------------------|--------------------------------|--------------------------------| +| | \\( R\_1 \gets Y\_1 - X\_1 \\) | \\( R\_2 \gets Y\_2 - X\_2 \\) | \\( R\_3 \gets Y\_1 + X\_1 \\) | \\( R\_4 \gets Y\_2 + X\_2 \\) | +| \\(1\mathbf M\\) | \\( R\_5 \gets R\_1 R\_2 \\) | \\( R\_6 \gets R\_3 R\_4 \\) | \\( R\_7 \gets T\_1 T\_2 \\) | \\( R\_8 \gets Z\_1 Z\_2 \\) | +| \\(1\mathbf D\\) | idle | idle | \\( R\_7 \gets k R\_7 \\) | \\( R\_8 \gets 2 R\_8 \\) | +| | \\( R\_1 \gets R\_6 - R\_5 \\) | \\( R\_2 \gets R\_8 - R\_7 \\) | \\( R\_3 \gets R\_8 + R\_7 \\) | \\( R\_4 \gets R\_6 + R\_5 \\) | +| \\(1\mathbf M\\) | \\( X\_3 \gets R\_1 R\_2 \\) | \\( Y\_3 \gets R\_3 R\_4 \\) | \\( T\_3 \gets R\_1 R\_4 \\) | \\( Z\_3 \gets R\_2 R\_3 \\) | + +Here \\(\mathbf M\\) and \\(\mathbf S\\) represent the cost of +multiplication and squaring of generic field elements, \\(\mathbf D\\) +represents the cost of multiplication by a curve constant (in this +case \\( k = 2d \\)). + +Notice that the \\(1\mathbf M\\) and \\(1\mathbf S\\) steps are +uniform. The non-uniform steps are all inexpensive additions or +subtractions, with the exception of the multiplication by the curve +constant \\(k = 2d\\): +$$ +R\_7 \gets 2 d R\_7. +$$ + +HWCD suggest parallelising this step by breaking \\(k = 2d\\) into four +parts as \\(k = k_0 + 2\^n k_1 + 2\^{2n} k_2 + 2\^{3n} k_3 \\) and +computing \\(k_i R_7 \\) in parallel. This is quite awkward, but if +the curve constant is a ratio \\( d = d\_1/d\_2 \\), then projective +coordinates allow us to instead compute +$$ +(R\_5, R\_6, R\_7, R\_8) \gets (d\_2 R\_5, d\_2 R\_6, 2d\_1 R\_7, d\_2 R\_8). +$$ +This can be performed as a uniform multiplication by a vector of +constants, and if \\(d\_1, d\_2\\) are small, it is relatively +inexpensive. (This trick was suggested by Mike Hamburg). +In the Curve25519 case, we have +$$ +d = \frac{d\_1}{d\_2} = \frac{-121665}{121666}; +$$ +Since \\(2 \cdot 121666 < 2\^{18}\\), all the constants above fit (up +to sign) in 32 bits, so this can be done in parallel as four +multiplications by small constants \\( (121666, 121666, 2\cdot 121665, +2\cdot 121666) \\), followed by a negation to compute \\( - 2\cdot 121665\\). + +# Modified parallel formulas + +Using the modifications sketched above, we can write SIMD-friendly +versions of the parallel formulas as follows. To avoid confusion with +the original formulas, temporary variables are named \\(S\\) instead +of \\(R\\) and are in static single-assignment form. + +## Addition + +To add points +\\(P_1 = (X_1 : Y_1 : Z_1 : T_1) \\) +and +\\(P_2 = (X_2 : Y_2 : Z_2 : T_2 ) \\), +we compute +$$ +\begin{aligned} +(S\_0 &&,&& S\_1 &&,&& S\_2 &&,&& S\_3 ) +&\gets +(Y\_1 - X\_1&&,&& Y\_1 + X\_1&&,&& Y\_2 - X\_2&&,&& Y\_2 + X\_2) +\\\\ +(S\_4 &&,&& S\_5 &&,&& S\_6 &&,&& S\_7 ) +&\gets +(S\_0 \cdot S\_2&&,&& S\_1 \cdot S\_3&&,&& Z\_1 \cdot Z\_2&&,&& T\_1 \cdot T\_2) +\\\\ +(S\_8 &&,&& S\_9 &&,&& S\_{10} &&,&& S\_{11} ) +&\gets +(d\_2 \cdot S\_4 &&,&& d\_2 \cdot S\_5 &&,&& 2 d\_2 \cdot S\_6 &&,&& 2 d\_1 \cdot S\_7 ) +\\\\ +(S\_{12} &&,&& S\_{13} &&,&& S\_{14} &&,&& S\_{15}) +&\gets +(S\_9 - S\_8&&,&& S\_9 + S\_8&&,&& S\_{10} - S\_{11}&&,&& S\_{10} + S\_{11}) +\\\\ +(X\_3&&,&& Y\_3&&,&& Z\_3&&,&& T\_3) +&\gets +(S\_{12} \cdot S\_{14}&&,&& S\_{15} \cdot S\_{13}&&,&& S\_{15} \cdot S\_{14}&&,&& S\_{12} \cdot S\_{13}) +\end{aligned} +$$ +to obtain \\( P\_3 = (X\_3 : Y\_3 : Z\_3 : T\_3) = P\_1 + P\_2 \\). +This costs \\( 2\mathbf M + 1 \mathbf D\\). + +## Readdition + +If the point \\( P_2 = (X\_2 : Y\_2 : Z\_2 : T\_2) \\) is fixed, we +can cache the multiplication of the curve constants by computing +$$ +\begin{aligned} +(S\_2' &&,&& S\_3' &&,&& Z\_2' &&,&& T\_2' ) +&\gets +(d\_2 \cdot (Y\_2 - X\_2)&&,&& d\_2 \cdot (Y\_1 + X\_1)&&,&& 2d\_2 \cdot Z\_2 &&,&& 2d\_1 \cdot T\_2). +\end{aligned} +$$ +This costs \\( 1\mathbf D\\); with \\( (S\_2', S\_3', Z\_2', T\_2')\\) +in hand, the addition formulas above become +$$ +\begin{aligned} +(S\_0 &&,&& S\_1 &&,&& Z\_1 &&,&& T\_1 ) +&\gets +(Y\_1 - X\_1&&,&& Y\_1 + X\_1&&,&& Z\_1 &&,&& T\_1) +\\\\ +(S\_8 &&,&& S\_9 &&,&& S\_{10} &&,&& S\_{11} ) +&\gets +(S\_0 \cdot S\_2' &&,&& S\_1 \cdot S\_3'&&,&& Z\_1 \cdot Z\_2' &&,&& T\_1 \cdot T\_2') +\\\\ +(S\_{12} &&,&& S\_{13} &&,&& S\_{14} &&,&& S\_{15}) +&\gets +(S\_9 - S\_8&&,&& S\_9 + S\_8&&,&& S\_{10} - S\_{11}&&,&& S\_{10} + S\_{11}) +\\\\ +(X\_3&&,&& Y\_3&&,&& Z\_3&&,&& T\_3) +&\gets +(S\_{12} \cdot S\_{14}&&,&& S\_{15} \cdot S\_{13}&&,&& S\_{15} \cdot S\_{14}&&,&& S\_{12} \cdot S\_{13}) +\end{aligned} +$$ +which costs only \\( 2\mathbf M \\). This precomputation is +essentially similar to the precomputation that HWCD suggest for their +serial formulas. Because the cost of precomputation and then +readdition is the same as addition, it's sufficient to only +implement caching and readdition. + +## Doubling + +The non-uniform portions of the (re)addition formulas have a fairly +regular structure. Unfortunately, this is not the case for the +doubling formulas, which are much less nice. + +To double a point \\( P = (X\_1 : Y\_1 : Z\_1 : T\_1) \\), we compute +$$ +\begin{aligned} +(X\_1 &&,&& Y\_1 &&,&& Z\_1 &&,&& S\_0) +&\gets +(X\_1 &&,&& Y\_1 &&,&& Z\_1 &&,&& X\_1 + Y\_1) +\\\\ +(S\_1 &&,&& S\_2 &&,&& S\_3 &&,&& S\_4 ) +&\gets +(X\_1\^2 &&,&& Y\_1\^2&&,&& Z\_1\^2 &&,&& S\_0\^2) +\\\\ +(S\_5 &&,&& S\_6 &&,&& S\_8 &&,&& S\_9 ) +&\gets +(S\_1 + S\_2 &&,&& S\_1 - S\_2 &&,&& S\_1 + 2S\_3 - S\_2 &&,&& S\_1 + S\_2 - S\_4) +\\\\ +(X\_3 &&,&& Y\_3 &&,&& Z\_3 &&,&& T\_3 ) +&\gets +(S\_8 \cdot S\_9 &&,&& S\_5 \cdot S\_6 &&,&& S\_8 \cdot S\_6 &&,&& S\_5 \cdot S\_9) +\end{aligned} +$$ +to obtain \\( P\_3 = (X\_3 : Y\_3 : Z\_3 : T\_3) = [2]P\_1 \\). + +The intermediate step between the squaring and multiplication requires +a long chain of additions. For the IFMA-based implementation, this is not a problem; for the AVX2-based implementation, it is, but with some care and finesse, it's possible to arrange the computation without requiring an intermediate reduction. + +# Implementation + +These formulas aren't specific to a particular representation of field +element vectors, whose optimum choice is determined by the details of +the instruction set. However, it's not possible to perfectly separate +the implementation of the field element vectors from the +implementation of the point operations. Instead, the [`avx2`] and +[`ifma`] backends provide `ExtendedPoint` and `CachedPoint` types, and +the [`scalar_mul`] code uses one of the backend types by a type alias. + +# Comparison to non-vectorized formulas + +In theory, the parallel Edwards formulas seem to allow a \\(4\\)-way +speedup from parallelism. However, an actual vectorized +implementation has several slowdowns that cut into this speedup. + +First, the parallel formulas can only use the available vector +multiplier. For AVX2, this is a \\( 32 \times 32 \rightarrow 64 +\\)-bit integer multiplier, so the speedup from vectorization must +overcome the disadvantage of losing the \\( 64 \times 64 \rightarrow +128\\)-bit (serial) integer multiplier. The effect of this slowdown +is microarchitecture-dependent, since it requires accounting for the +total number of multiplications and additions and their relative +costs. IFMA allows using a \\( 52 \times 52 \rightarrow 104 \\)-bit +multiplier, but the high and low halves need to be computed +separately, and the reduction requires extra work because it's not +possible to pre-multiply by \\(19\\). + +Second, the parallel doubling formulas incur both a theoretical and +practical slowdown. The parallel formulas described above work on the +\\( \mathbb P\^3 \\) “extended” coordinates. The \\( \mathbb P\^2 \\) +model introduced earlier by [Bernstein, Birkner, Joye, Lange, and +Peters][bbjlp08] allows slightly faster doublings, so HWCD suggest +mixing coordinate systems while performing scalar multiplication +(attributing the idea to [a 1998 paper][cmo98] by Cohen, Miyagi, and +Ono). The \\( T \\) coordinate is not required for doublings, so when +doublings are followed by doublings, its computation can be skipped. +More details on this approach and the different coordinate systems can +be found in the [`curve_models` module documentation][curve_models]. + +Unfortunately, this optimization is not compatible with the parallel +formulas, which cannot save time by skipping a single variable, so the +parallel doubling formulas do slightly more work when counting the +total number of field multiplications and squarings. + +In addition, the parallel doubling formulas have a less regular +pattern of additions and subtractions than the parallel addition +formulas, so the vectorization overhead is proportionately greater. +Both the parallel addition and parallel doubling formulas also require +some shuffling to rearrange data within the vectors, which places more +pressure on the shuffle unit than is desirable. + +This means that the speedup from using a vectorized implementation of +parallel Edwards formulas is likely to be greatest in applications +that do fewer doublings and more additions (like a large multiscalar +multiplication) rather than applications that do fewer additions and +more doublings (like a double-base scalar multiplication). + +Third, Amdahl's law says that the speedup is limited to the portion +which can be parallelized. Normally, the field multiplications +dominate the cost of point operations, but with the IFMA backend, the +multiplications are so fast that the non-parallel additions end up as +a significant portion of the total time. + +Fourth, current Intel CPUs perform thermal throttling when using wide +vector instructions. A detailed description can be found in §15.26 of +[the Intel Optimization Manual][intel], but using wide vector +instructions prevents the core from operating at higher frequencies. +The core can return to the higher-frequency state after 2 +milliseconds, but this timer is reset every time high-power +instructions are used. + +Any speedup from vectorization therefore has to be weighed against a +slowdown for the next few million instructions. For a mixed workload, +where point operations are interspersed with other tasks, this can +reduce overall performance. This implementation is therefore probably +not suitable for basic applications, like signatures, but is +worthwhile for complex applications, like zero-knowledge proofs, which +do sustained work. + +# Future work + +There are several directions for future improvement: + +* Using the vectorized field arithmetic code to parallelize across + point operations rather than within a single point operation. This + is less flexible, but would give a speedup both from allowing use of + the faster mixed-model arithmetic and from reducing shuffle + pressure. One approach in this direction would be to implement + batched scalar-point operations using vectors of points (AoSoA + layout). This less generally useful but would give a speedup for + Bulletproofs. + +* Extending the IFMA implementation to use the full width of AVX512, + either handling the extra parallelism internally to a single point + operation (by using a 2-way parallel implementation of field + arithmetic instead of a wordsliced one), or externally, + parallelizing across point operations. Internal parallelism would + be preferable but might require too much shuffle pressure. For now, + the only available CPU which runs IFMA operations executes them at + 256-bits wide anyways, so this isn't yet important. + +* Generalizing the implementation to NEON instructions. The current + point arithmetic code is written in terms of field element vectors, + which are in turn implemented using platform SIMD vectors. It + should be possible to write an alternate implementation of the + `FieldElement2625x4` using NEON without changing the point + arithmetic. NEON has 128-bit vectors rather than 256-bit vectors, + but this may still be worthwhile compared to a serial + implementation. + + +[sandy2x]: https://eprint.iacr.org/2015/943.pdf +[avx2trac]: https://trac.torproject.org/projects/tor/ticket/8897#comment:28 +[hwcd08]: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf +[curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/curve_models/index.html +[bbjlp08]: https://eprint.iacr.org/2008/013 +[cmo98]: https://link.springer.com/content/pdf/10.1007%2F3-540-49649-1_6.pdf +[intel]: https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/mod.rs new file mode 100644 index 0000000..f761eaa --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/mod.rs @@ -0,0 +1,62 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Pluggable implementations for different architectures. +//! +//! The backend code is split into two parts: a serial backend, +//! and a vector backend. +//! +//! The [`serial`] backend contains 32- and 64-bit implementations of +//! field arithmetic and scalar arithmetic, as well as implementations +//! of point operations using the mixed-model strategy (passing +//! between different curve models depending on the operation). +//! +//! The [`vector`] backend contains implementations of vectorized +//! field arithmetic, used to implement point operations using a novel +//! implementation strategy derived from parallel formulas of Hisil, +//! Wong, Carter, and Dawson. +//! +//! Because the two strategies give rise to different curve models, +//! it's not possible to reuse exactly the same scalar multiplication +//! code (or to write it generically), so both serial and vector +//! backends contain matching implementations of scalar multiplication +//! algorithms. These are intended to be selected by a `#[cfg]`-based +//! type alias. +//! +//! The [`vector`] backend is selected by the `simd_backend` cargo +//! feature; it uses the [`serial`] backend for non-vectorized operations. + +#[cfg(not(any( + feature = "u32_backend", + feature = "u64_backend", + feature = "simd_backend", +)))] +compile_error!( + "no curve25519-dalek backend cargo feature enabled! \ + please enable one of: u32_backend, u64_backend, simd_backend" +); + +pub mod serial; + +#[cfg(any( + all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") + ), + all(feature = "nightly", rustdoc) +))] +#[cfg_attr( + feature = "nightly", + doc(cfg(any(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") + )))) +)] +pub mod vector; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/curve_models/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/curve_models/mod.rs new file mode 100644 index 0000000..5d5850f --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/curve_models/mod.rs @@ -0,0 +1,550 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Internal curve representations which are not part of the public API. +//! +//! # Curve representations +//! +//! Internally, we use several different models for the curve. Here +//! is a sketch of the relationship between the models, following [a +//! post][smith-moderncrypto] +//! by Ben Smith on the `moderncrypto` mailing list. This is also briefly +//! discussed in section 2.5 of [_Montgomery curves and their +//! arithmetic_][costello-smith-2017] by Costello and Smith. +//! +//! Begin with the affine equation for the curve, +//! $$ +//! -x\^2 + y\^2 = 1 + dx\^2y\^2. +//! $$ +//! Next, pass to the projective closure \\(\mathbb P\^1 \times \mathbb +//! P\^1 \\) by setting \\(x=X/Z\\), \\(y=Y/T.\\) Clearing denominators +//! gives the model +//! $$ +//! -X\^2T\^2 + Y\^2Z\^2 = Z\^2T\^2 + dX\^2Y\^2. +//! $$ +//! In `curve25519-dalek`, this is represented as the `CompletedPoint` +//! struct. +//! To map from \\(\mathbb P\^1 \times \mathbb P\^1 \\), a product of +//! two lines, to \\(\mathbb P\^3\\), we use the [Segre +//! embedding](https://en.wikipedia.org/wiki/Segre_embedding) +//! $$ +//! \sigma : ((X:Z),(Y:T)) \mapsto (XY:XT:ZY:ZT). +//! $$ +//! Using coordinates \\( (W_0:W_1:W_2:W_3) \\) for \\(\mathbb P\^3\\), +//! the image \\(\sigma (\mathbb P\^1 \times \mathbb P\^1) \\) is the +//! surface defined by \\( W_0 W_3 = W_1 W_2 \\), and under \\( +//! \sigma\\), the equation above becomes +//! $$ +//! -W\_1\^2 + W\_2\^2 = W\_3\^2 + dW\_0\^2, +//! $$ +//! so that the curve is given by the pair of equations +//! $$ +//! \begin{aligned} +//! -W\_1\^2 + W\_2\^2 &= W\_3\^2 + dW\_0\^2, \\\\ W_0 W_3 &= W_1 W_2. +//! \end{aligned} +//! $$ +//! Up to variable naming, this is exactly the "extended" curve model +//! introduced in [_Twisted Edwards Curves +//! Revisited_][hisil-wong-carter-dawson-2008] by Hisil, Wong, Carter, +//! and Dawson. In `curve25519-dalek`, it is represented as the +//! `EdwardsPoint` struct. We can map from \\(\mathbb P\^3 \\) to +//! \\(\mathbb P\^2 \\) by sending \\( (W\_0:W\_1:W\_2:W\_3) \\) to \\( +//! (W\_1:W\_2:W\_3) \\). Notice that +//! $$ +//! \frac {W\_1} {W\_3} = \frac {XT} {ZT} = \frac X Z = x, +//! $$ +//! and +//! $$ +//! \frac {W\_2} {W\_3} = \frac {YZ} {ZT} = \frac Y T = y, +//! $$ +//! so this is the same as if we had started with the affine model +//! and passed to \\( \mathbb P\^2 \\) by setting \\( x = W\_1 / W\_3 +//! \\), \\(y = W\_2 / W\_3 \\). +//! Up to variable naming, this is the projective representation +//! introduced in in [_Twisted Edwards +//! Curves_][bernstein-birkner-joye-lange-peters-2008] by Bernstein, +//! Birkner, Joye, Lange, and Peters. In `curve25519-dalek`, it is +//! represented by the `ProjectivePoint` struct. +//! +//! # Passing between curve models +//! +//! Although the \\( \mathbb P\^3 \\) model provides faster addition +//! formulas, the \\( \mathbb P\^2 \\) model provides faster doubling +//! formulas. Hisil, Wong, Carter, and Dawson therefore suggest mixing +//! coordinate systems for scalar multiplication, attributing the idea +//! to [a 1998 paper][cohen-miyaji-ono-1998] of Cohen, Miyagi, and Ono. +//! +//! Their suggestion is to vary the formulas used by context, using a +//! \\( \mathbb P\^2 \rightarrow \mathbb P\^2 \\) doubling formula when +//! a doubling is followed +//! by another doubling, a \\( \mathbb P\^2 \rightarrow \mathbb P\^3 \\) +//! doubling formula when a doubling is followed by an addition, and +//! computing point additions using a \\( \mathbb P\^3 \times \mathbb P\^3 +//! \rightarrow \mathbb P\^2 \\) formula. +//! +//! The `ref10` reference implementation of [Ed25519][ed25519], by +//! Bernstein, Duif, Lange, Schwabe, and Yang, tweaks +//! this strategy, factoring the addition formulas through the +//! completion \\( \mathbb P\^1 \times \mathbb P\^1 \\), so that the +//! output of an addition or doubling always lies in \\( \mathbb P\^1 \times +//! \mathbb P\^1\\), and the choice of which formula to use is replaced +//! by a choice of whether to convert the result to \\( \mathbb P\^2 \\) +//! or \\(\mathbb P\^3 \\). However, this tweak is not described in +//! their paper, only in their software. +//! +//! Our naming for the `CompletedPoint` (\\(\mathbb P\^1 \times \mathbb +//! P\^1 \\)), `ProjectivePoint` (\\(\mathbb P\^2 \\)), and +//! `EdwardsPoint` (\\(\mathbb P\^3 \\)) structs follows the naming in +//! Adam Langley's [Golang ed25519][agl-ed25519] implementation, which +//! `curve25519-dalek` was originally derived from. +//! +//! Finally, to accelerate readditions, we use two cached point formats +//! in "Niels coordinates", named for Niels Duif, +//! one for the affine model and one for the \\( \mathbb P\^3 \\) model: +//! +//! * `AffineNielsPoint`: \\( (y+x, y-x, 2dxy) \\) +//! * `ProjectiveNielsPoint`: \\( (Y+X, Y-X, Z, 2dXY) \\) +//! +//! [smith-moderncrypto]: https://moderncrypto.org/mail-archive/curves/2016/000807.html +//! [costello-smith-2017]: https://eprint.iacr.org/2017/212 +//! [hisil-wong-carter-dawson-2008]: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf +//! [bernstein-birkner-joye-lange-peters-2008]: https://eprint.iacr.org/2008/013 +//! [cohen-miyaji-ono-1998]: https://link.springer.com/content/pdf/10.1007%2F3-540-49649-1_6.pdf +//! [ed25519]: https://eprint.iacr.org/2011/368 +//! [agl-ed25519]: https://github.com/agl/ed25519 + +#![allow(non_snake_case)] + +use core::fmt::Debug; +use core::ops::{Add, Neg, Sub}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use zeroize::Zeroize; + +use constants; + +use edwards::EdwardsPoint; +use field::FieldElement; +use traits::ValidityCheck; + +// ------------------------------------------------------------------------ +// Internal point representations +// ------------------------------------------------------------------------ + +/// A `ProjectivePoint` is a point \\((X:Y:Z)\\) on the \\(\mathbb +/// P\^2\\) model of the curve. +/// A point \\((x,y)\\) in the affine model corresponds to +/// \\((x:y:1)\\). +/// +/// More details on the relationships between the different curve models +/// can be found in the module-level documentation. +#[derive(Copy, Clone)] +pub struct ProjectivePoint { + pub X: FieldElement, + pub Y: FieldElement, + pub Z: FieldElement, +} + +/// A `CompletedPoint` is a point \\(((X:Z), (Y:T))\\) on the \\(\mathbb +/// P\^1 \times \mathbb P\^1 \\) model of the curve. +/// A point (x,y) in the affine model corresponds to \\( ((x:1),(y:1)) +/// \\). +/// +/// More details on the relationships between the different curve models +/// can be found in the module-level documentation. +#[derive(Copy, Clone)] +#[allow(missing_docs)] +pub struct CompletedPoint { + pub X: FieldElement, + pub Y: FieldElement, + pub Z: FieldElement, + pub T: FieldElement, +} + +/// A pre-computed point in the affine model for the curve, represented as +/// \\((y+x, y-x, 2dxy)\\) in "Niels coordinates". +/// +/// More details on the relationships between the different curve models +/// can be found in the module-level documentation. +// Safe to derive Eq because affine coordinates. +#[derive(Copy, Clone, Eq, PartialEq)] +#[allow(missing_docs)] +pub struct AffineNielsPoint { + pub y_plus_x: FieldElement, + pub y_minus_x: FieldElement, + pub xy2d: FieldElement, +} + +impl Zeroize for AffineNielsPoint { + fn zeroize(&mut self) { + self.y_plus_x.zeroize(); + self.y_minus_x.zeroize(); + self.xy2d.zeroize(); + } +} + +/// A pre-computed point on the \\( \mathbb P\^3 \\) model for the +/// curve, represented as \\((Y+X, Y-X, Z, 2dXY)\\) in "Niels coordinates". +/// +/// More details on the relationships between the different curve models +/// can be found in the module-level documentation. +#[derive(Copy, Clone)] +pub struct ProjectiveNielsPoint { + pub Y_plus_X: FieldElement, + pub Y_minus_X: FieldElement, + pub Z: FieldElement, + pub T2d: FieldElement, +} + +impl Zeroize for ProjectiveNielsPoint { + fn zeroize(&mut self) { + self.Y_plus_X.zeroize(); + self.Y_minus_X.zeroize(); + self.Z.zeroize(); + self.T2d.zeroize(); + } +} + +// ------------------------------------------------------------------------ +// Constructors +// ------------------------------------------------------------------------ + +use traits::Identity; + +impl Identity for ProjectivePoint { + fn identity() -> ProjectivePoint { + ProjectivePoint { + X: FieldElement::zero(), + Y: FieldElement::one(), + Z: FieldElement::one(), + } + } +} + +impl Identity for ProjectiveNielsPoint { + fn identity() -> ProjectiveNielsPoint { + ProjectiveNielsPoint{ + Y_plus_X: FieldElement::one(), + Y_minus_X: FieldElement::one(), + Z: FieldElement::one(), + T2d: FieldElement::zero(), + } + } +} + +impl Default for ProjectiveNielsPoint { + fn default() -> ProjectiveNielsPoint { + ProjectiveNielsPoint::identity() + } +} + +impl Identity for AffineNielsPoint { + fn identity() -> AffineNielsPoint { + AffineNielsPoint{ + y_plus_x: FieldElement::one(), + y_minus_x: FieldElement::one(), + xy2d: FieldElement::zero(), + } + } +} + +impl Default for AffineNielsPoint { + fn default() -> AffineNielsPoint { + AffineNielsPoint::identity() + } +} + +// ------------------------------------------------------------------------ +// Validity checks (for debugging, not CT) +// ------------------------------------------------------------------------ + +impl ValidityCheck for ProjectivePoint { + fn is_valid(&self) -> bool { + // Curve equation is -x^2 + y^2 = 1 + d*x^2*y^2, + // homogenized as (-X^2 + Y^2)*Z^2 = Z^4 + d*X^2*Y^2 + let XX = self.X.square(); + let YY = self.Y.square(); + let ZZ = self.Z.square(); + let ZZZZ = ZZ.square(); + let lhs = &(&YY - &XX) * &ZZ; + let rhs = &ZZZZ + &(&constants::EDWARDS_D * &(&XX * &YY)); + + lhs == rhs + } +} + +// ------------------------------------------------------------------------ +// Constant-time assignment +// ------------------------------------------------------------------------ + +impl ConditionallySelectable for ProjectiveNielsPoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + ProjectiveNielsPoint { + Y_plus_X: FieldElement::conditional_select(&a.Y_plus_X, &b.Y_plus_X, choice), + Y_minus_X: FieldElement::conditional_select(&a.Y_minus_X, &b.Y_minus_X, choice), + Z: FieldElement::conditional_select(&a.Z, &b.Z, choice), + T2d: FieldElement::conditional_select(&a.T2d, &b.T2d, choice), + } + } + + fn conditional_assign(&mut self, other: &Self, choice: Choice) { + self.Y_plus_X.conditional_assign(&other.Y_plus_X, choice); + self.Y_minus_X.conditional_assign(&other.Y_minus_X, choice); + self.Z.conditional_assign(&other.Z, choice); + self.T2d.conditional_assign(&other.T2d, choice); + } +} + +impl ConditionallySelectable for AffineNielsPoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + AffineNielsPoint { + y_plus_x: FieldElement::conditional_select(&a.y_plus_x, &b.y_plus_x, choice), + y_minus_x: FieldElement::conditional_select(&a.y_minus_x, &b.y_minus_x, choice), + xy2d: FieldElement::conditional_select(&a.xy2d, &b.xy2d, choice), + } + } + + fn conditional_assign(&mut self, other: &Self, choice: Choice) { + self.y_plus_x.conditional_assign(&other.y_plus_x, choice); + self.y_minus_x.conditional_assign(&other.y_minus_x, choice); + self.xy2d.conditional_assign(&other.xy2d, choice); + } +} + +// ------------------------------------------------------------------------ +// Point conversions +// ------------------------------------------------------------------------ + +impl ProjectivePoint { + /// Convert this point from the \\( \mathbb P\^2 \\) model to the + /// \\( \mathbb P\^3 \\) model. + /// + /// This costs \\(3 \mathrm M + 1 \mathrm S\\). + pub fn to_extended(&self) -> EdwardsPoint { + EdwardsPoint { + X: &self.X * &self.Z, + Y: &self.Y * &self.Z, + Z: self.Z.square(), + T: &self.X * &self.Y, + } + } +} + +impl CompletedPoint { + /// Convert this point from the \\( \mathbb P\^1 \times \mathbb P\^1 + /// \\) model to the \\( \mathbb P\^2 \\) model. + /// + /// This costs \\(3 \mathrm M \\). + pub fn to_projective(&self) -> ProjectivePoint { + ProjectivePoint { + X: &self.X * &self.T, + Y: &self.Y * &self.Z, + Z: &self.Z * &self.T, + } + } + + /// Convert this point from the \\( \mathbb P\^1 \times \mathbb P\^1 + /// \\) model to the \\( \mathbb P\^3 \\) model. + /// + /// This costs \\(4 \mathrm M \\). + pub fn to_extended(&self) -> EdwardsPoint { + EdwardsPoint { + X: &self.X * &self.T, + Y: &self.Y * &self.Z, + Z: &self.Z * &self.T, + T: &self.X * &self.Y, + } + } +} + +// ------------------------------------------------------------------------ +// Doubling +// ------------------------------------------------------------------------ + +impl ProjectivePoint { + /// Double this point: return self + self + pub fn double(&self) -> CompletedPoint { // Double() + let XX = self.X.square(); + let YY = self.Y.square(); + let ZZ2 = self.Z.square2(); + let X_plus_Y = &self.X + &self.Y; + let X_plus_Y_sq = X_plus_Y.square(); + let YY_plus_XX = &YY + &XX; + let YY_minus_XX = &YY - &XX; + + CompletedPoint{ + X: &X_plus_Y_sq - &YY_plus_XX, + Y: YY_plus_XX, + Z: YY_minus_XX, + T: &ZZ2 - &YY_minus_XX + } + } +} + +// ------------------------------------------------------------------------ +// Addition and Subtraction +// ------------------------------------------------------------------------ + +// XXX(hdevalence) These were doc(hidden) so they don't appear in the +// public API docs. +// However, that prevents them being used with --document-private-items, +// so comment out the doc(hidden) for now until this is resolved +// +// upstream rust issue: https://github.com/rust-lang/rust/issues/46380 +//#[doc(hidden)] +impl<'a, 'b> Add<&'b ProjectiveNielsPoint> for &'a EdwardsPoint { + type Output = CompletedPoint; + + fn add(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint { + let Y_plus_X = &self.Y + &self.X; + let Y_minus_X = &self.Y - &self.X; + let PP = &Y_plus_X * &other.Y_plus_X; + let MM = &Y_minus_X * &other.Y_minus_X; + let TT2d = &self.T * &other.T2d; + let ZZ = &self.Z * &other.Z; + let ZZ2 = &ZZ + &ZZ; + + CompletedPoint{ + X: &PP - &MM, + Y: &PP + &MM, + Z: &ZZ2 + &TT2d, + T: &ZZ2 - &TT2d + } + } +} + +//#[doc(hidden)] +impl<'a, 'b> Sub<&'b ProjectiveNielsPoint> for &'a EdwardsPoint { + type Output = CompletedPoint; + + fn sub(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint { + let Y_plus_X = &self.Y + &self.X; + let Y_minus_X = &self.Y - &self.X; + let PM = &Y_plus_X * &other.Y_minus_X; + let MP = &Y_minus_X * &other.Y_plus_X; + let TT2d = &self.T * &other.T2d; + let ZZ = &self.Z * &other.Z; + let ZZ2 = &ZZ + &ZZ; + + CompletedPoint{ + X: &PM - &MP, + Y: &PM + &MP, + Z: &ZZ2 - &TT2d, + T: &ZZ2 + &TT2d + } + } +} + +//#[doc(hidden)] +impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a EdwardsPoint { + type Output = CompletedPoint; + + fn add(self, other: &'b AffineNielsPoint) -> CompletedPoint { + let Y_plus_X = &self.Y + &self.X; + let Y_minus_X = &self.Y - &self.X; + let PP = &Y_plus_X * &other.y_plus_x; + let MM = &Y_minus_X * &other.y_minus_x; + let Txy2d = &self.T * &other.xy2d; + let Z2 = &self.Z + &self.Z; + + CompletedPoint{ + X: &PP - &MM, + Y: &PP + &MM, + Z: &Z2 + &Txy2d, + T: &Z2 - &Txy2d + } + } +} + +//#[doc(hidden)] +impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a EdwardsPoint { + type Output = CompletedPoint; + + fn sub(self, other: &'b AffineNielsPoint) -> CompletedPoint { + let Y_plus_X = &self.Y + &self.X; + let Y_minus_X = &self.Y - &self.X; + let PM = &Y_plus_X * &other.y_minus_x; + let MP = &Y_minus_X * &other.y_plus_x; + let Txy2d = &self.T * &other.xy2d; + let Z2 = &self.Z + &self.Z; + + CompletedPoint{ + X: &PM - &MP, + Y: &PM + &MP, + Z: &Z2 - &Txy2d, + T: &Z2 + &Txy2d + } + } +} + +// ------------------------------------------------------------------------ +// Negation +// ------------------------------------------------------------------------ + +impl<'a> Neg for &'a ProjectiveNielsPoint { + type Output = ProjectiveNielsPoint; + + fn neg(self) -> ProjectiveNielsPoint { + ProjectiveNielsPoint{ + Y_plus_X: self.Y_minus_X, + Y_minus_X: self.Y_plus_X, + Z: self.Z, + T2d: -(&self.T2d), + } + } +} + +impl<'a> Neg for &'a AffineNielsPoint { + type Output = AffineNielsPoint; + + fn neg(self) -> AffineNielsPoint { + AffineNielsPoint{ + y_plus_x: self.y_minus_x, + y_minus_x: self.y_plus_x, + xy2d: -(&self.xy2d) + } + } +} + +// ------------------------------------------------------------------------ +// Debug traits +// ------------------------------------------------------------------------ + +impl Debug for ProjectivePoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "ProjectivePoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?}\n}}", + &self.X, &self.Y, &self.Z) + } +} + +impl Debug for CompletedPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "CompletedPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", + &self.X, &self.Y, &self.Z, &self.T) + } +} + +impl Debug for AffineNielsPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "AffineNielsPoint{{\n\ty_plus_x: {:?},\n\ty_minus_x: {:?},\n\txy2d: {:?}\n}}", + &self.y_plus_x, &self.y_minus_x, &self.xy2d) + } +} + +impl Debug for ProjectiveNielsPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "ProjectiveNielsPoint{{\n\tY_plus_X: {:?},\n\tY_minus_X: {:?},\n\tZ: {:?},\n\tT2d: {:?}\n}}", + &self.Y_plus_X, &self.Y_minus_X, &self.Z, &self.T2d) + } +} + + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/mod.rs new file mode 100644 index 0000000..fc6b320 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/mod.rs @@ -0,0 +1,43 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Serial implementations of field, scalar, point arithmetic. +//! +//! When the vector backend is disabled, the crate uses the +//! mixed-model strategy for implementing point operations and scalar +//! multiplication; see the [`curve_models`](self::curve_models) and +//! [`scalar_mul`](self::scalar_mul) documentation for more +//! information. +//! +//! When the vector backend is enabled, the field and scalar +//! implementations are still used for non-vectorized operations. +//! +//! Note: at this time the `u32` and `u64` backends cannot be built +//! together. + +#[cfg(not(any(feature = "u32_backend", feature = "u64_backend")))] +compile_error!( + "no curve25519-dalek backend cargo feature enabled! \ + please enable one of: u32_backend, u64_backend" +); + +#[cfg(feature = "u32_backend")] +pub mod u32; + +#[cfg(feature = "u64_backend")] +pub mod u64; + +pub mod curve_models; + +#[cfg(not(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +)))] +pub mod scalar_mul; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/mod.rs new file mode 100644 index 0000000..544725a --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/mod.rs @@ -0,0 +1,30 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Implementations of various scalar multiplication algorithms. +//! +//! Note that all of these implementations use serial code for field +//! arithmetic with the multi-model strategy described in the +//! `curve_models` module. The vectorized AVX2 backend has its own +//! scalar multiplication implementations, since it only uses one +//! curve model. + +pub mod variable_base; + +pub mod vartime_double_base; + +#[cfg(feature = "alloc")] +pub mod straus; + +#[cfg(feature = "alloc")] +pub mod precomputed_straus; + +#[cfg(feature = "alloc")] +pub mod pippenger; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/pippenger.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/pippenger.rs new file mode 100644 index 0000000..bffe140 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/pippenger.rs @@ -0,0 +1,202 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Oleg Andreev +// See LICENSE for licensing information. +// +// Authors: +// - Oleg Andreev + +//! Implementation of a variant of Pippenger's algorithm. + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::VartimeMultiscalarMul; + +#[allow(unused_imports)] +use prelude::*; + +/// Implements a version of Pippenger's algorithm. +/// +/// The algorithm works as follows: +/// +/// Let `n` be a number of point-scalar pairs. +/// Let `w` be a window of bits (6..8, chosen based on `n`, see cost factor). +/// +/// 1. Prepare `2^(w-1) - 1` buckets with indices `[1..2^(w-1))` initialized with identity points. +/// Bucket 0 is not needed as it would contain points multiplied by 0. +/// 2. Convert scalars to a radix-`2^w` representation with signed digits in `[-2^w/2, 2^w/2]`. +/// Note: only the last digit may equal `2^w/2`. +/// 3. Starting with the last window, for each point `i=[0..n)` add it to a a bucket indexed by +/// the point's scalar's value in the window. +/// 4. Once all points in a window are sorted into buckets, add buckets by multiplying each +/// by their index. Efficient way of doing it is to start with the last bucket and compute two sums: +/// intermediate sum from the last to the first, and the full sum made of all intermediate sums. +/// 5. Shift the resulting sum of buckets by `w` bits by using `w` doublings. +/// 6. Add to the return value. +/// 7. Repeat the loop. +/// +/// Approximate cost w/o wNAF optimizations (A = addition, D = doubling): +/// +/// ```ascii +/// cost = (n*A + 2*(2^w/2)*A + w*D + A)*256/w +/// | | | | | +/// | | | | looping over 256/w windows +/// | | | adding to the result +/// sorting points | shifting the sum by w bits (to the next window, starting from last window) +/// one by one | +/// into buckets adding/subtracting all buckets +/// multiplied by their indexes +/// using a sum of intermediate sums +/// ``` +/// +/// For large `n`, dominant factor is (n*256/w) additions. +/// However, if `w` is too big and `n` is not too big, then `(2^w/2)*A` could dominate. +/// Therefore, the optimal choice of `w` grows slowly as `n` grows. +/// +/// This algorithm is adapted from section 4 of https://eprint.iacr.org/2012/549.pdf. +pub struct Pippenger; + +#[cfg(any(feature = "alloc", feature = "std"))] +impl VartimeMultiscalarMul for Pippenger { + type Point = EdwardsPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + use traits::Identity; + + let mut scalars = scalars.into_iter(); + let size = scalars.by_ref().size_hint().0; + + // Digit width in bits. As digit width grows, + // number of point additions goes down, but amount of + // buckets and bucket additions grows exponentially. + let w = if size < 500 { + 6 + } else if size < 800 { + 7 + } else { + 8 + }; + + let max_digit: usize = 1 << w; + let digits_count: usize = Scalar::to_radix_2w_size_hint(w); + let buckets_count: usize = max_digit / 2; // digits are signed+centered hence 2^w/2, excluding 0-th bucket + + // Collect optimized scalars and points in buffers for repeated access + // (scanning the whole set per digit position). + let scalars = scalars + .map(|s| s.borrow().to_radix_2w(w)); + + let points = points + .into_iter() + .map(|p| p.map(|P| P.to_projective_niels())); + + let scalars_points = scalars + .zip(points) + .map(|(s, maybe_p)| maybe_p.map(|p| (s, p))) + .collect::>>()?; + + // Prepare 2^w/2 buckets. + // buckets[i] corresponds to a multiplication factor (i+1). + let mut buckets: Vec<_> = (0..buckets_count) + .map(|_| EdwardsPoint::identity()) + .collect(); + + let mut columns = (0..digits_count).rev().map(|digit_index| { + // Clear the buckets when processing another digit. + for i in 0..buckets_count { + buckets[i] = EdwardsPoint::identity(); + } + + // Iterate over pairs of (point, scalar) + // and add/sub the point to the corresponding bucket. + // Note: if we add support for precomputed lookup tables, + // we'll be adding/subtracting point premultiplied by `digits[i]` to buckets[0]. + for (digits, pt) in scalars_points.iter() { + // Widen digit so that we don't run into edge cases when w=8. + let digit = digits[digit_index] as i16; + if digit > 0 { + let b = (digit - 1) as usize; + buckets[b] = (&buckets[b] + pt).to_extended(); + } else if digit < 0 { + let b = (-digit - 1) as usize; + buckets[b] = (&buckets[b] - pt).to_extended(); + } + } + + // Add the buckets applying the multiplication factor to each bucket. + // The most efficient way to do that is to have a single sum with two running sums: + // an intermediate sum from last bucket to the first, and a sum of intermediate sums. + // + // For example, to add buckets 1*A, 2*B, 3*C we need to add these points: + // C + // C B + // C B A Sum = C + (C+B) + (C+B+A) + let mut buckets_intermediate_sum = buckets[buckets_count - 1]; + let mut buckets_sum = buckets[buckets_count - 1]; + for i in (0..(buckets_count - 1)).rev() { + buckets_intermediate_sum += buckets[i]; + buckets_sum += buckets_intermediate_sum; + } + + buckets_sum + }); + + // Take the high column as an initial value to avoid wasting time doubling the identity element in `fold()`. + // `unwrap()` always succeeds because we know we have more than zero digits. + let hi_column = columns.next().unwrap(); + + Some( + columns + .fold(hi_column, |total, p| total.mul_by_pow_2(w as u32) + p), + ) + } +} + +#[cfg(test)] +mod test { + use super::*; + use constants; + use scalar::Scalar; + + #[test] + fn test_vartime_pippenger() { + // Reuse points across different tests + let mut n = 512; + let x = Scalar::from(2128506u64).invert(); + let y = Scalar::from(4443282u64).invert(); + let points: Vec<_> = (0..n) + .map(|i| constants::ED25519_BASEPOINT_POINT * Scalar::from(1 + i as u64)) + .collect(); + let scalars: Vec<_> = (0..n) + .map(|i| x + (Scalar::from(i as u64) * y)) // fast way to make ~random but deterministic scalars + .collect(); + + let premultiplied: Vec = scalars + .iter() + .zip(points.iter()) + .map(|(sc, pt)| sc * pt) + .collect(); + + while n > 0 { + let scalars = &scalars[0..n].to_vec(); + let points = &points[0..n].to_vec(); + let control: EdwardsPoint = premultiplied[0..n].iter().sum(); + + let subject = Pippenger::vartime_multiscalar_mul(scalars.clone(), points.clone()); + + assert_eq!(subject.compress(), control.compress()); + + n = n / 2; + } + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/precomputed_straus.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/precomputed_straus.rs new file mode 100644 index 0000000..97f5e86 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/precomputed_straus.rs @@ -0,0 +1,110 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Henry de Valence. +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +//! Precomputation for Straus's method. + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use backend::serial::curve_models::{ + AffineNielsPoint, CompletedPoint, ProjectiveNielsPoint, ProjectivePoint, +}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::Identity; +use traits::VartimePrecomputedMultiscalarMul; +use window::{NafLookupTable5, NafLookupTable8}; + +#[allow(unused_imports)] +use prelude::*; + +pub struct VartimePrecomputedStraus { + static_lookup_tables: Vec>, +} + +impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { + type Point = EdwardsPoint; + + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + Self { + static_lookup_tables: static_points + .into_iter() + .map(|P| NafLookupTable8::::from(P.borrow())) + .collect(), + } + } + + fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator>, + { + let static_nafs = static_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + let dynamic_nafs: Vec<_> = dynamic_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + + let dynamic_lookup_tables = dynamic_points + .into_iter() + .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) + .collect::>>()?; + + let sp = self.static_lookup_tables.len(); + let dp = dynamic_lookup_tables.len(); + assert_eq!(sp, static_nafs.len()); + assert_eq!(dp, dynamic_nafs.len()); + + // We could save some doublings by looking for the highest + // nonzero NAF coefficient, but since we might have a lot of + // them to search, it's not clear it's worthwhile to check. + let mut S = ProjectivePoint::identity(); + for j in (0..256).rev() { + let mut R: CompletedPoint = S.double(); + + for i in 0..dp { + let t_ij = dynamic_nafs[i][j]; + if t_ij > 0 { + R = &R.to_extended() + &dynamic_lookup_tables[i].select(t_ij as usize); + } else if t_ij < 0 { + R = &R.to_extended() - &dynamic_lookup_tables[i].select(-t_ij as usize); + } + } + + for i in 0..sp { + let t_ij = static_nafs[i][j]; + if t_ij > 0 { + R = &R.to_extended() + &self.static_lookup_tables[i].select(t_ij as usize); + } else if t_ij < 0 { + R = &R.to_extended() - &self.static_lookup_tables[i].select(-t_ij as usize); + } + } + + S = R.to_projective(); + } + + Some(S.to_extended()) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/straus.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/straus.rs new file mode 100644 index 0000000..b63e162 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/straus.rs @@ -0,0 +1,195 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Implementation of the interleaved window method, also known as Straus' method. + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::MultiscalarMul; +use traits::VartimeMultiscalarMul; + +#[allow(unused_imports)] +use prelude::*; + +/// Perform multiscalar multiplication by the interleaved window +/// method, also known as Straus' method (since it was apparently +/// [first published][solution] by Straus in 1964, as a solution to [a +/// problem][problem] posted in the American Mathematical Monthly in +/// 1963). +/// +/// It is easy enough to reinvent, and has been repeatedly. The basic +/// idea is that when computing +/// \\[ +/// Q = s_1 P_1 + \cdots + s_n P_n +/// \\] +/// by means of additions and doublings, the doublings can be shared +/// across the \\( P_i \\\). +/// +/// We implement two versions, a constant-time algorithm using fixed +/// windows and a variable-time algorithm using sliding windows. They +/// are slight variations on the same idea, and are described in more +/// detail in the respective implementations. +/// +/// [solution]: https://www.jstor.org/stable/2310929 +/// [problem]: https://www.jstor.org/stable/2312273 +pub struct Straus {} + +impl MultiscalarMul for Straus { + type Point = EdwardsPoint; + + /// Constant-time Straus using a fixed window of size \\(4\\). + /// + /// Our goal is to compute + /// \\[ + /// Q = s_1 P_1 + \cdots + s_n P_n. + /// \\] + /// + /// For each point \\( P_i \\), precompute a lookup table of + /// \\[ + /// P_i, 2P_i, 3P_i, 4P_i, 5P_i, 6P_i, 7P_i, 8P_i. + /// \\] + /// + /// For each scalar \\( s_i \\), compute its radix-\\(2^4\\) + /// signed digits \\( s_{i,j} \\), i.e., + /// \\[ + /// s_i = s_{i,0} + s_{i,1} 16^1 + ... + s_{i,63} 16^{63}, + /// \\] + /// with \\( -8 \leq s_{i,j} < 8 \\). Since \\( 0 \leq |s_{i,j}| + /// \leq 8 \\), we can retrieve \\( s_{i,j} P_i \\) from the + /// lookup table with a conditional negation: using signed + /// digits halves the required table size. + /// + /// Then as in the single-base fixed window case, we have + /// \\[ + /// \begin{aligned} + /// s_i P_i &= P_i (s_{i,0} + s_{i,1} 16^1 + \cdots + s_{i,63} 16^{63}) \\\\ + /// s_i P_i &= P_i s_{i,0} + P_i s_{i,1} 16^1 + \cdots + P_i s_{i,63} 16^{63} \\\\ + /// s_i P_i &= P_i s_{i,0} + 16(P_i s_{i,1} + 16( \cdots +16P_i s_{i,63})\cdots ) + /// \end{aligned} + /// \\] + /// so each \\( s_i P_i \\) can be computed by alternately adding + /// a precomputed multiple \\( P_i s_{i,j} \\) of \\( P_i \\) and + /// repeatedly doubling. + /// + /// Now consider the two-dimensional sum + /// \\[ + /// \begin{aligned} + /// s\_1 P\_1 &=& P\_1 s\_{1,0} &+& 16 (P\_1 s\_{1,1} &+& 16 ( \cdots &+& 16 P\_1 s\_{1,63}&) \cdots ) \\\\ + /// + & & + & & + & & & & + & \\\\ + /// s\_2 P\_2 &=& P\_2 s\_{2,0} &+& 16 (P\_2 s\_{2,1} &+& 16 ( \cdots &+& 16 P\_2 s\_{2,63}&) \cdots ) \\\\ + /// + & & + & & + & & & & + & \\\\ + /// \vdots & & \vdots & & \vdots & & & & \vdots & \\\\ + /// + & & + & & + & & & & + & \\\\ + /// s\_n P\_n &=& P\_n s\_{n,0} &+& 16 (P\_n s\_{n,1} &+& 16 ( \cdots &+& 16 P\_n s\_{n,63}&) \cdots ) + /// \end{aligned} + /// \\] + /// The sum of the left-hand column is the result \\( Q \\); by + /// computing the two-dimensional sum on the right column-wise, + /// top-to-bottom, then right-to-left, we need to multiply by \\( + /// 16\\) only once per column, sharing the doublings across all + /// of the input points. + fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + { + use zeroize::Zeroizing; + + use backend::serial::curve_models::ProjectiveNielsPoint; + use window::LookupTable; + use traits::Identity; + + let lookup_tables: Vec<_> = points + .into_iter() + .map(|point| LookupTable::::from(point.borrow())) + .collect(); + + // This puts the scalar digits into a heap-allocated Vec. + // To ensure that these are erased, pass ownership of the Vec into a + // Zeroizing wrapper. + let scalar_digits_vec: Vec<_> = scalars + .into_iter() + .map(|s| s.borrow().to_radix_16()) + .collect(); + let scalar_digits = Zeroizing::new(scalar_digits_vec); + + let mut Q = EdwardsPoint::identity(); + for j in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + let it = scalar_digits.iter().zip(lookup_tables.iter()); + for (s_i, lookup_table_i) in it { + // R_i = s_{i,j} * P_i + let R_i = lookup_table_i.select(s_i[j]); + // Q = Q + R_i + Q = (&Q + &R_i).to_extended(); + } + } + + Q + } +} + +impl VartimeMultiscalarMul for Straus { + type Point = EdwardsPoint; + + /// Variable-time Straus using a non-adjacent form of width \\(5\\). + /// + /// This is completely similar to the constant-time code, but we + /// use a non-adjacent form for the scalar, and do not do table + /// lookups in constant time. + /// + /// The non-adjacent form has signed, odd digits. Using only odd + /// digits halves the table size (since we only need odd + /// multiples), or gives fewer additions for the same table size. + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + use backend::serial::curve_models::{CompletedPoint, ProjectiveNielsPoint, ProjectivePoint}; + use window::NafLookupTable5; + use traits::Identity; + + let nafs: Vec<_> = scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect(); + + let lookup_tables = points + .into_iter() + .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) + .collect::>>()?; + + let mut r = ProjectivePoint::identity(); + + for i in (0..256).rev() { + let mut t: CompletedPoint = r.double(); + + for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) { + if naf[i] > 0 { + t = &t.to_extended() + &lookup_table.select(naf[i] as usize); + } else if naf[i] < 0 { + t = &t.to_extended() - &lookup_table.select(-naf[i] as usize); + } + } + + r = t.to_projective(); + } + + Some(r.to_extended()) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/variable_base.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/variable_base.rs new file mode 100644 index 0000000..c69e48c --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/variable_base.rs @@ -0,0 +1,46 @@ +#![allow(non_snake_case)] + +use traits::Identity; +use scalar::Scalar; +use edwards::EdwardsPoint; +use backend::serial::curve_models::{ProjectiveNielsPoint, ProjectivePoint}; +use window::LookupTable; + +/// Perform constant-time, variable-base scalar multiplication. +pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + let lookup_table = LookupTable::::from(point); + // Setting s = scalar, compute + // + // s = s_0 + s_1*16^1 + ... + s_63*16^63, + // + // with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`. + let scalar_digits = scalar.to_radix_16(); + // Compute s*P as + // + // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) + // s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63 + // s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...)) + // + // We sum right-to-left. + + // Unwrap first loop iteration to save computing 16*identity + let mut tmp2; + let mut tmp3 = EdwardsPoint::identity(); + let mut tmp1 = &tmp3 + &lookup_table.select(scalar_digits[63]); + // Now tmp1 = s_63*P in P1xP1 coords + for i in (0..63).rev() { + tmp2 = tmp1.to_projective(); // tmp2 = (prev) in P2 coords + tmp1 = tmp2.double(); // tmp1 = 2*(prev) in P1xP1 coords + tmp2 = tmp1.to_projective(); // tmp2 = 2*(prev) in P2 coords + tmp1 = tmp2.double(); // tmp1 = 4*(prev) in P1xP1 coords + tmp2 = tmp1.to_projective(); // tmp2 = 4*(prev) in P2 coords + tmp1 = tmp2.double(); // tmp1 = 8*(prev) in P1xP1 coords + tmp2 = tmp1.to_projective(); // tmp2 = 8*(prev) in P2 coords + tmp1 = tmp2.double(); // tmp1 = 16*(prev) in P1xP1 coords + tmp3 = tmp1.to_extended(); // tmp3 = 16*(prev) in P3 coords + tmp1 = &tmp3 + &lookup_table.select(scalar_digits[i]); + // Now tmp1 = s_i*P + 16*(prev) in P1xP1 coords + } + tmp1.to_extended() +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/vartime_double_base.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/vartime_double_base.rs new file mode 100644 index 0000000..ef8c0ca --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/scalar_mul/vartime_double_base.rs @@ -0,0 +1,61 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence +#![allow(non_snake_case)] + +use constants; +use traits::Identity; +use scalar::Scalar; +use edwards::EdwardsPoint; +use backend::serial::curve_models::{ProjectiveNielsPoint, ProjectivePoint}; +use window::NafLookupTable5; + +/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. +pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { + let a_naf = a.non_adjacent_form(5); + let b_naf = b.non_adjacent_form(8); + + // Find starting index + let mut i: usize = 255; + for j in (0..256).rev() { + i = j; + if a_naf[i] != 0 || b_naf[i] != 0 { + break; + } + } + + let table_A = NafLookupTable5::::from(A); + let table_B = &constants::AFFINE_ODD_MULTIPLES_OF_BASEPOINT; + + let mut r = ProjectivePoint::identity(); + loop { + let mut t = r.double(); + + if a_naf[i] > 0 { + t = &t.to_extended() + &table_A.select(a_naf[i] as usize); + } else if a_naf[i] < 0 { + t = &t.to_extended() - &table_A.select(-a_naf[i] as usize); + } + + if b_naf[i] > 0 { + t = &t.to_extended() + &table_B.select(b_naf[i] as usize); + } else if b_naf[i] < 0 { + t = &t.to_extended() - &table_B.select(-b_naf[i] as usize); + } + + r = t.to_projective(); + + if i == 0 { + break; + } + i -= 1; + } + + r.to_extended() +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/constants.rs new file mode 100644 index 0000000..73f353f --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/constants.rs @@ -0,0 +1,4776 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! This module contains various constants (such as curve parameters +//! and useful field elements like `sqrt(-1)`), as well as +//! lookup tables of pre-computed points. + +use backend::serial::curve_models::AffineNielsPoint; +use backend::serial::u32::field::FieldElement2625; +use backend::serial::u32::scalar::Scalar29; +use edwards::{EdwardsBasepointTable, EdwardsPoint}; +use window::{LookupTable, NafLookupTable8}; + +/// The value of minus one, equal to `-&FieldElement::one()` +pub(crate) const MINUS_ONE: FieldElement2625 = FieldElement2625([ + 67108844, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431 +]); + +/// Edwards `d` value, equal to `-121665/121666 mod p`. +pub(crate) const EDWARDS_D: FieldElement2625 = FieldElement2625([ + 56195235, 13857412, 51736253, 6949390, 114729, 24766616, 60832955, 30306712, 48412415, 21499315, +]); + +/// Edwards `2*d` value, equal to `2*(-121665/121666) mod p`. +pub(crate) const EDWARDS_D2: FieldElement2625 = FieldElement2625([ + 45281625, 27714825, 36363642, 13898781, 229458, 15978800, 54557047, 27058993, 29715967, 9444199, +]); + +/// One minus edwards `d` value squared, equal to `(1 - (-121665/121666) mod p) pow 2` +pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement2625 = FieldElement2625([ + 6275446, 16937061, 44170319, 29780721, 11667076, 7397348, 39186143, 1766194, 42675006, 672202 +]); + +/// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2` +pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement2625 = FieldElement2625([ + 15551776, 22456977, 53683765, 23429360, 55212328, 10178283, 40474537, 4729243, 61826754, 23438029 +]); + +/// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const SQRT_AD_MINUS_ONE: FieldElement2625 = FieldElement2625([ + 24849947, 33400850, 43495378, 6347714, 46036536, 32887293, 41837720, 18186727, 66238516, + 14525638, +]); + +/// `= 1/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const INVSQRT_A_MINUS_D: FieldElement2625 = FieldElement2625([ + 6111466, 4156064, 39310137, 12243467, 41204824, 120896, 20826367, 26493656, 6093567, 31568420, +]); + +/// Precomputed value of one of the square roots of -1 (mod p) +pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625([ + 34513072, 25610706, 9377949, 3500415, 12389472, 33281959, 41962654, 31548777, 326685, 11406482, +]); + +/// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) +pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 = + FieldElement2625([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + +/// `L` is the order of base point, i.e. 2^252 + +/// 27742317777372353535851937790883648493 +pub(crate) const L: Scalar29 = Scalar29([ + 0x1cf5d3ed, 0x009318d2, 0x1de73596, 0x1df3bd45, 0x0000014d, 0x00000000, 0x00000000, 0x00000000, + 0x00100000, +]); + +/// `L` * `LFACTOR` = -1 (mod 2^29) +pub(crate) const LFACTOR: u32 = 0x12547e1b; + +/// `R` = R % L where R = 2^261 +pub(crate) const R: Scalar29 = Scalar29([ + 0x114df9ed, 0x1a617303, 0x0f7c098c, 0x16793167, 0x1ffd656e, 0x1fffffff, 0x1fffffff, 0x1fffffff, + 0x000fffff, +]); + +/// `RR` = (R^2) % L where R = 2^261 +pub(crate) const RR: Scalar29 = Scalar29([ + 0x0b5f9d12, 0x1e141b17, 0x158d7f3d, 0x143f3757, 0x1972d781, 0x042feb7c, 0x1ceec73d, 0x1e184d1e, + 0x0005046d, +]); + +/// The Ed25519 basepoint, as an `EdwardsPoint`. +/// +/// This is called `_POINT` to distinguish it from +/// `ED25519_BASEPOINT_TABLE`, which should be used for scalar +/// multiplication (it's much faster). +pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { + X: FieldElement2625([ + 52811034, 25909283, 16144682, 17082669, 27570973, 30858332, 40966398, 8378388, 20764389, + 8758491, + ]), + Y: FieldElement2625([ + 40265304, 26843545, 13421772, 20132659, 26843545, 6710886, 53687091, 13421772, 40265318, + 26843545, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([ + 28827043, 27438313, 39759291, 244362, 8635006, 11264893, 19351346, 13413597, 16611511, + 27139452, + ]), +}; + +/// The 8-torsion subgroup \\(\mathcal E [8]\\). +/// +/// In the case of Curve25519, it is cyclic; the \\(i\\)-th element of +/// the array is \\([i]P\\), where \\(P\\) is a point of order \\(8\\) +/// generating \\(\mathcal E[8]\\). +/// +/// Thus \\(\mathcal E[4]\\) is the points indexed by `0,2,4,6`, and +/// \\(\mathcal E[2]\\) is the points indexed by `0,4`. +/// The Ed25519 basepoint has y = 4/5. This is called `_POINT` to +/// distinguish it from `_TABLE`, which should be used for scalar +/// multiplication (it's much faster). +pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN; + +/// Inner item used to hide limb constants from cargo doc output. +#[doc(hidden)] +pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ + EdwardsPoint { + X: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Y: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625([ + 21352778, 5345713, 4660180, 25206575, 24143089, 14568123, 30185756, 21306662, 33579924, + 8345318, + ]), + Y: FieldElement2625([ + 6952903, 1265500, 60246523, 7057497, 4037696, 5447722, 35427965, 15325401, 19365852, + 31985330, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([ + 41846657, 21581751, 11716001, 27684820, 48915701, 16297738, 20670665, 24995334, + 3541542, 28543251, + ]), + }, + EdwardsPoint { + X: FieldElement2625([ + 32595773, 7943725, 57730914, 30054016, 54719391, 272472, 25146209, 2005654, 66782178, + 22147949, + ]), + Y: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625([ + 21352778, 5345713, 4660180, 25206575, 24143089, 14568123, 30185756, 21306662, 33579924, + 8345318, + ]), + Y: FieldElement2625([ + 60155942, 32288931, 6862340, 26496934, 63071167, 28106709, 31680898, 18229030, + 47743011, 1569101, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([ + 25262188, 11972680, 55392862, 5869611, 18193162, 17256693, 46438198, 8559097, 63567321, + 5011180, + ]), + }, + EdwardsPoint { + X: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Y: FieldElement2625([ + 67108844, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, + 67108863, 33554431, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625([ + 45756067, 28208718, 62448683, 8347856, 42965774, 18986308, 36923107, 12247769, + 33528939, 25209113, + ]), + Y: FieldElement2625([ + 60155942, 32288931, 6862340, 26496934, 63071167, 28106709, 31680898, 18229030, + 47743011, 1569101, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([ + 41846657, 21581751, 11716001, 27684820, 48915701, 16297738, 20670665, 24995334, + 3541542, 28543251, + ]), + }, + EdwardsPoint { + X: FieldElement2625([ + 34513072, 25610706, 9377949, 3500415, 12389472, 33281959, 41962654, 31548777, 326685, + 11406482, + ]), + Y: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625([ + 45756067, 28208718, 62448683, 8347856, 42965774, 18986308, 36923107, 12247769, + 33528939, 25209113, + ]), + Y: FieldElement2625([ + 6952903, 1265500, 60246523, 7057497, 4037696, 5447722, 35427965, 15325401, 19365852, + 31985330, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([ + 25262188, 11972680, 55392862, 5869611, 18193162, 17256693, 46438198, 8559097, 63567321, + 5011180, + ]), + }, +]; + +/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). +pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; + +/// Inner constant, used to avoid filling the docs with precomputed points. +#[doc(hidden)] +pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = + EdwardsBasepointTable([ + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 93076338, 52752828, 29566454, 37215328, 54414518, 37569218, 94653489, 21800160, + 61029707, 35602036, + ]), + y_minus_x: FieldElement2625([ + 54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692, 5043384, + 19500929, 18085054, + ]), + xy2d: FieldElement2625([ + 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918, 11864899, + 42594502, 29115885, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54292951, 54132516, 45527619, 11784319, 41753206, 30803714, 55390960, 29739860, + 66750418, 23343128, + ]), + y_minus_x: FieldElement2625([ + 45405608, 6903824, 27185491, 6451973, 37531140, 24000426, 51492312, 11189267, + 40279186, 28235350, + ]), + xy2d: FieldElement2625([ + 26966623, 11152617, 32442495, 15396054, 14353839, 20802097, 63980037, 24013313, + 51636816, 29387734, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82745136, 23865874, 24204772, 25642034, 67725840, 16869169, 94896463, 52336674, + 28944398, 32004408, + ]), + y_minus_x: FieldElement2625([ + 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576, 21778470, + 7689661, 11199574, + ]), + xy2d: FieldElement2625([ + 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774, 10017326, + 49359771, 23634074, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50071967, 13921891, 78054670, 27521000, 27105051, 17470053, 105291517, + 15006021, 70393432, 27277891, + ]), + y_minus_x: FieldElement2625([ + 23599295, 25248385, 55915199, 25867015, 13236773, 10506355, 7464579, 9656445, + 13059162, 10374397, + ]), + xy2d: FieldElement2625([ + 7798537, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, 29715387, + 66467155, 33453106, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77970208, 11473153, 27284546, 35535607, 37044514, 46132292, 99976748, 48069538, + 118779423, 44373810, + ]), + y_minus_x: FieldElement2625([ + 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196, 12483687, + 54440373, 5581305, + ]), + xy2d: FieldElement2625([ + 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349, 13850243, + 43430843, 17738489, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 51736881, 20691677, 32573249, 4720197, 107781206, 39429941, 115029100, + 18329611, 124398787, 21468653, + ]), + y_minus_x: FieldElement2625([ + 58559652, 109982, 15149363, 2178705, 22900618, 4543417, 3044240, 17864545, + 1762327, 14866737, + ]), + xy2d: FieldElement2625([ + 48909169, 17603008, 56635573, 1707277, 49922944, 3916100, 38872452, 3959420, + 27914454, 4383652, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 72262591, 43463716, 68832610, 30776557, 97632468, 39071304, 86589715, 38784565, + 43156424, 18378665, + ]), + y_minus_x: FieldElement2625([ + 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025, 16520125, + 30598449, 7715701, + ]), + xy2d: FieldElement2625([ + 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204, 1370707, + 29794553, 32145132, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 14499452, 64379265, 33917749, 62854211, 95603724, 14271266, 97399599, 10876453, + 33954766, 35936157, + ]), + y_minus_x: FieldElement2625([ + 59913433, 30899068, 52378708, 462250, 39384538, 3941371, 60872247, 3696004, + 34808032, 15351954, + ]), + xy2d: FieldElement2625([ + 27431194, 8222322, 16448760, 29646437, 48401861, 11938354, 34147463, 30583916, + 29551812, 10109425, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 53451805, 20399000, 102933977, 45331528, 88556249, 40073815, 64730579, + 31926875, 77201646, 28790260, + ]), + y_minus_x: FieldElement2625([ + 27939166, 14210322, 4677035, 16277044, 44144402, 21156292, 34600109, 12005537, + 49298737, 12803509, + ]), + xy2d: FieldElement2625([ + 17228999, 17892808, 65875336, 300139, 65883994, 21839654, 30364212, 24516238, + 18016356, 4397660, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 56150002, 25864224, 4776340, 18600194, 27850027, 17952220, 40489757, 14544524, + 49631360, 34537070, + ]), + y_minus_x: FieldElement2625([ + 29253598, 15796703, 64244882, 23645547, 10057022, 3163536, 7332899, 29434304, + 46061167, 9934962, + ]), + xy2d: FieldElement2625([ + 5793284, 16271923, 42977250, 23438027, 29188559, 1206517, 52360934, 4559894, + 36984942, 22656481, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 39464893, 55615857, 83391519, 22517938, 28414020, 52096600, 24191032, 38096129, + 53770554, 39054999, + ]), + y_minus_x: FieldElement2625([ + 12650548, 32057319, 9052870, 11355358, 49428827, 25154267, 49678271, 12264342, + 10874051, 13524335, + ]), + xy2d: FieldElement2625([ + 25556948, 30508442, 714650, 2510400, 23394682, 23139102, 33119037, 5080568, + 44580805, 5376627, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 108129445, 29543378, 50095164, 30016803, 60382070, 35475328, 44787558, + 57661420, 71644630, 35123438, + ]), + y_minus_x: FieldElement2625([ + 64853442, 14606629, 45416424, 25514613, 28430648, 8775819, 36614302, 3044289, + 31848280, 12543772, + ]), + xy2d: FieldElement2625([ + 45080285, 2943892, 35251351, 6777305, 13784462, 29262229, 39731668, 31491700, + 7718481, 14474653, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69494160, 36008644, 44477543, 33601034, 62670928, 51428448, 67765827, 26317766, + 91425031, 28300864, + ]), + y_minus_x: FieldElement2625([ + 13741529, 10911568, 33875447, 24950694, 46931033, 32521134, 33040650, 20129900, + 46379407, 8321685, + ]), + xy2d: FieldElement2625([ + 21060490, 31341688, 15712756, 29218333, 1639039, 10656336, 23845965, 21679594, + 57124405, 608371, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 53436113, 18466845, 56219170, 25997372, 61071954, 11305546, 68232832, 60328286, + 94338261, 33578318, + ]), + y_minus_x: FieldElement2625([ + 43864724, 33260226, 55364135, 14712570, 37643165, 31524814, 12797023, 27114124, + 65475458, 16678953, + ]), + xy2d: FieldElement2625([ + 37608244, 4770661, 51054477, 14001337, 7830047, 9564805, 65600720, 28759386, + 49939598, 4904952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 91168402, 48171434, 86146020, 18514523, 86874956, 18648002, 72278074, 16191879, + 69237100, 29227598, + ]), + y_minus_x: FieldElement2625([ + 50127693, 4124965, 58568254, 22900634, 30336521, 19449185, 37302527, 916032, + 60226322, 30567899, + ]), + xy2d: FieldElement2625([ + 44477957, 12419371, 59974635, 26081060, 50629959, 16739174, 285431, 2763829, + 15736322, 4143876, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69488197, 11839344, 62998462, 27565766, 78383161, 34349388, 67321664, 18959768, + 23527083, 17096164, + ]), + y_minus_x: FieldElement2625([ + 33431108, 22423954, 49269897, 17927531, 8909498, 8376530, 34483524, 4087880, + 51919953, 19138217, + ]), + xy2d: FieldElement2625([ + 1767664, 7197987, 53903638, 31531796, 54017513, 448825, 5799055, 4357868, + 62334673, 17231393, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 6721947, 47388255, 43585475, 32003117, 93463156, 21691110, 90474010, 29604699, + 74499753, 36314231, + ]), + y_minus_x: FieldElement2625([ + 4409022, 2052381, 23373853, 10530217, 7676779, 20668478, 21302352, 29290375, + 1244379, 20634787, + ]), + xy2d: FieldElement2625([ + 62687625, 7169618, 4982368, 30596842, 30256824, 30776892, 14086412, 9208236, + 15886429, 16489664, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69104920, 43930080, 81455230, 46865633, 60234728, 17116020, 120524529, + 33952799, 36502408, 32841498, + ]), + y_minus_x: FieldElement2625([ + 41801399, 9795879, 64331450, 14878808, 33577029, 14780362, 13348553, 12076947, + 36272402, 5113181, + ]), + xy2d: FieldElement2625([ + 49338080, 11797795, 31950843, 13929123, 41220562, 12288343, 36767763, 26218045, + 13847710, 5387222, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 48526682, 30138214, 84933706, 64767897, 89853205, 56666252, 75871923, 37172217, + 47508201, 43925422, + ]), + y_minus_x: FieldElement2625([ + 20246567, 19185054, 22358228, 33010720, 18507282, 23140436, 14554436, 24808340, + 32232923, 16763880, + ]), + xy2d: FieldElement2625([ + 9648486, 10094563, 26416693, 14745928, 36734546, 27081810, 11094160, 15689506, + 3140038, 17044340, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50948773, 39027126, 31895587, 38299426, 75932378, 43920116, 39884063, 43003044, + 38334409, 33920726, + ]), + y_minus_x: FieldElement2625([ + 19153450, 11523972, 56012374, 27051289, 42461232, 5420646, 28344573, 8041113, + 719605, 11671788, + ]), + xy2d: FieldElement2625([ + 8678006, 2694440, 60300850, 2517371, 4964326, 11152271, 51675948, 18287915, + 27000812, 23358879, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 119059805, 40688742, 75748150, 30739554, 59873175, 43976173, 67672928, + 38890528, 73859840, 19033405, + ]), + y_minus_x: FieldElement2625([ + 11836410, 29574944, 26297893, 16080799, 23455045, 15735944, 1695823, 24735310, + 8169719, 16220347, + ]), + xy2d: FieldElement2625([ + 48993007, 8653646, 17578566, 27461813, 59083086, 17541668, 55964556, 30926767, + 61118155, 19388398, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 43800347, 22586119, 82322091, 23473217, 36255258, 22504427, 27884328, 36401716, + 69764724, 35292826, + ]), + y_minus_x: FieldElement2625([ + 39571412, 19301410, 41772562, 25551651, 57738101, 8129820, 21651608, 30315096, + 48021414, 22549153, + ]), + xy2d: FieldElement2625([ + 1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, + 10478196, 8544890, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 32173083, 50979553, 24896205, 37475929, 22579055, 63698010, 19270447, 45771905, + 84897880, 63712868, + ]), + y_minus_x: FieldElement2625([ + 36555903, 31326030, 51530034, 23407230, 13243888, 517024, 15479401, 29701199, + 30460519, 1052596, + ]), + xy2d: FieldElement2625([ + 55493970, 13323617, 32618793, 8175907, 51878691, 12596686, 27491595, 28942073, + 3179267, 24075541, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 99055914, 52742212, 62468279, 18214510, 51982886, 27514722, 52352086, 17142691, + 19072639, 24043372, + ]), + y_minus_x: FieldElement2625([ + 11685058, 11822410, 3158003, 19601838, 33402193, 29389366, 5977895, 28339415, + 473098, 5040608, + ]), + xy2d: FieldElement2625([ + 46817982, 8198641, 39698732, 11602122, 1290375, 30754672, 28326861, 1721092, + 47550222, 30422825, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 74990396, 10687936, 74687587, 7738377, 48157852, 31000479, 88929649, 8076148, + 39240368, 11538388, + ]), + y_minus_x: FieldElement2625([ + 47173198, 3899860, 18283497, 26752864, 51380203, 22305220, 8754524, 7446702, + 61432810, 5797015, + ]), + xy2d: FieldElement2625([ + 55813245, 29760862, 51326753, 25589858, 12708868, 25098233, 2014098, 24503858, + 64739691, 27677090, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 111745333, 55540121, 106535706, 34700805, 86065554, 50194990, 68301593, + 29840232, 82232482, 44365936, + ]), + y_minus_x: FieldElement2625([ + 14352079, 30134717, 48166819, 10822654, 32750596, 4699007, 67038501, 15776355, + 38222085, 21579878, + ]), + xy2d: FieldElement2625([ + 38867681, 25481956, 62129901, 28239114, 29416930, 1847569, 46454691, 17069576, + 4714546, 23953777, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 15200313, 41923004, 86787964, 15970073, 35236190, 35513882, 24611598, 29010600, + 55362987, 45894651, + ]), + y_minus_x: FieldElement2625([ + 12876937, 23074376, 33134380, 6590940, 60801088, 14872439, 9613953, 8241152, + 15370987, 9608631, + ]), + xy2d: FieldElement2625([ + 62965568, 21540023, 8446280, 33162829, 4407737, 13629032, 59383996, 15866073, + 38898243, 24740332, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 26660609, 51431209, 75502596, 33912478, 59707572, 34547419, 43204630, 34413128, + 87680086, 41974987, + ]), + y_minus_x: FieldElement2625([ + 14620696, 13067227, 51661590, 8264466, 14106269, 15080814, 33531827, 12516406, + 45534429, 21077682, + ]), + xy2d: FieldElement2625([ + 236881, 10476226, 57258, 18877408, 6472997, 2466984, 17258519, 7256740, + 8791136, 15069930, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 68385255, 24182513, 90058498, 17231624, 43615824, 61406677, 81820737, 38428660, + 36445723, 31223040, + ]), + y_minus_x: FieldElement2625([ + 5855666, 4990204, 53397016, 7294283, 59304582, 1924646, 65685689, 25642053, + 34039526, 9234252, + ]), + xy2d: FieldElement2625([ + 20590503, 24535444, 31529743, 26201766, 64402029, 10650547, 31559055, 21944845, + 18979185, 13396066, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 24474268, 38522535, 22267081, 37961786, 91172745, 25229251, 48291976, 13594781, + 33514650, 40576390, + ]), + y_minus_x: FieldElement2625([ + 55541958, 26988926, 45743778, 15928891, 40950559, 4315420, 41160136, 29637754, + 45628383, 12868081, + ]), + xy2d: FieldElement2625([ + 38473832, 13504660, 19988037, 31421671, 21078224, 6443208, 45662757, 2244499, + 54653067, 25465048, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 36513317, 13793478, 61256044, 33873567, 41385691, 60844964, 100195408, 8957936, + 51875216, 39094952, + ]), + y_minus_x: FieldElement2625([ + 55478669, 22050529, 58989363, 25911358, 2620055, 1022908, 43398120, 31985447, + 50980335, 18591624, + ]), + xy2d: FieldElement2625([ + 23152952, 775386, 27395463, 14006635, 57407746, 4649511, 1689819, 892185, + 55595587, 18348483, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76878974, 43141169, 93604957, 37878551, 68665374, 30004407, 94562682, 38317558, + 47929249, 39421565, + ]), + y_minus_x: FieldElement2625([ + 34343820, 1927589, 31726409, 28801137, 23962433, 17534932, 27846558, 5931263, + 37359161, 17445976, + ]), + xy2d: FieldElement2625([ + 27461885, 30576896, 22380809, 1815854, 44075111, 30522493, 7283489, 18406359, + 47582163, 7734628, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 59098581, 57518046, 55988459, 39750469, 29344157, 20123547, 74694158, 30377805, + 85658360, 48856500, + ]), + y_minus_x: FieldElement2625([ + 34450527, 27383209, 59436070, 22502750, 6258877, 13504381, 10458790, 27135971, + 58236621, 8424745, + ]), + xy2d: FieldElement2625([ + 24687186, 8613276, 36441818, 30320886, 1863891, 31723888, 19206233, 7134917, + 55824382, 32725512, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 11334880, 24336410, 75134156, 46261950, 84632755, 23078360, 77352601, 18868970, + 62042829, 50053268, + ]), + y_minus_x: FieldElement2625([ + 8911542, 6887158, 57524604, 26595841, 11145640, 24010752, 17303924, 19430194, + 6536640, 10543906, + ]), + xy2d: FieldElement2625([ + 38162480, 15479762, 49642029, 568875, 65611181, 11223453, 64439674, 16928857, + 39873154, 8876770, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41365946, 54541999, 118567760, 32707823, 101191041, 32758142, 33627041, + 15824473, 66504438, 24514614, + ]), + y_minus_x: FieldElement2625([ + 10330056, 70051, 7957388, 24551765, 9764901, 15609756, 27698697, 28664395, + 1657393, 3084098, + ]), + xy2d: FieldElement2625([ + 10477963, 26084172, 12119565, 20303627, 29016246, 28188843, 31280318, 14396151, + 36875289, 15272408, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54820536, 36723894, 28813182, 16658753, 92225296, 27923965, 109043770, + 54472724, 42094105, 35504935, + ]), + y_minus_x: FieldElement2625([ + 40928506, 9489186, 11053416, 18808271, 36055143, 5825629, 58724558, 24786899, + 15341278, 8373727, + ]), + xy2d: FieldElement2625([ + 28685821, 7759505, 52730348, 21551571, 35137043, 4079241, 298136, 23321830, + 64230656, 15190419, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 34175950, 47360767, 52771378, 51314432, 110213106, 10940926, 75778582, + 36296824, 108184414, 60233859, + ]), + y_minus_x: FieldElement2625([ + 65528476, 21825014, 41129205, 22109408, 49696989, 22641577, 9291593, 17306653, + 54954121, 6048604, + ]), + xy2d: FieldElement2625([ + 36803549, 14843443, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, + 11213262, 9168384, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 40828313, 44562278, 19408959, 32613674, 115624762, 29225850, 62020803, + 22449281, 20470156, 50710163, + ]), + y_minus_x: FieldElement2625([ + 43972811, 9282191, 14855179, 18164354, 59746048, 19145871, 44324911, 14461607, + 14042978, 5230683, + ]), + xy2d: FieldElement2625([ + 29969548, 30812838, 50396996, 25001989, 9175485, 31085458, 21556950, 3506042, + 61174973, 21104723, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 63964099, 42299092, 19704002, 38135710, 46678177, 6830682, 45824694, 42525944, + 38569674, 48880994, + ]), + y_minus_x: FieldElement2625([ + 47644235, 10110287, 49846336, 30050539, 43608476, 1355668, 51585814, 15300987, + 46594746, 9168259, + ]), + xy2d: FieldElement2625([ + 61755510, 4488612, 43305616, 16314346, 7780487, 17915493, 38160505, 9601604, + 33087103, 24543045, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 47665675, 18041531, 46311396, 21109108, 104393280, 43783891, 39664534, + 52108332, 61111992, 49219103, + ]), + y_minus_x: FieldElement2625([ + 23294591, 16921819, 44458082, 25083453, 27844203, 11461195, 13099750, 31094076, + 18151675, 13417686, + ]), + xy2d: FieldElement2625([ + 42385932, 29377914, 35958184, 5988918, 40250079, 6685064, 1661597, 21002991, + 15271675, 18101767, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 78541887, 20325766, 75348494, 28274914, 65123427, 32828713, 48410099, 35721975, + 60187562, 20114249, + ]), + y_minus_x: FieldElement2625([ + 35672693, 15575145, 30436815, 12192228, 44645511, 9395378, 57191156, 24915434, + 12215109, 12028277, + ]), + xy2d: FieldElement2625([ + 14098381, 6555944, 23007258, 5757252, 51681032, 20603929, 30123439, 4617780, + 50208775, 32898803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 63082644, 51868028, 79002030, 47273095, 52299401, 35401816, 51288864, 43708440, + 91082124, 20869957, + ]), + y_minus_x: FieldElement2625([ + 40577025, 29858441, 65199965, 2534300, 35238307, 17004076, 18341389, 22134481, + 32013173, 23450893, + ]), + xy2d: FieldElement2625([ + 41629544, 10876442, 55337778, 18929291, 54739296, 1838103, 21911214, 6354752, + 4425632, 32716610, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 56675456, 18941465, 89338721, 30463384, 53917697, 34331160, 116802352, + 55088400, 71833867, 47599401, + ]), + y_minus_x: FieldElement2625([ + 19268631, 26250011, 1555348, 8692754, 45634805, 23643767, 6347389, 32142648, + 47586572, 17444675, + ]), + xy2d: FieldElement2625([ + 42244775, 12986007, 56209986, 27995847, 55796492, 33405905, 19541417, 8180106, + 9282262, 10282508, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 108012627, 37982977, 58447667, 20360168, 71207265, 52943606, 15522533, 8372215, + 72651459, 22851748, + ]), + y_minus_x: FieldElement2625([ + 56546323, 14895632, 26814552, 16880582, 49628109, 31065071, 64326972, 6993760, + 49014979, 10114654, + ]), + xy2d: FieldElement2625([ + 47001790, 32625013, 31422703, 10427861, 59998115, 6150668, 38017109, 22025285, + 25953724, 33448274, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62874448, 59069571, 57989737, 36600431, 69210472, 54501569, 86498882, 39648727, + 63793584, 46385556, + ]), + y_minus_x: FieldElement2625([ + 51110167, 7578151, 5310217, 14408357, 33560244, 33329692, 31575953, 6326196, + 7381791, 31132593, + ]), + xy2d: FieldElement2625([ + 46206085, 3296810, 24736065, 17226043, 18374253, 7318640, 6295303, 8082724, + 51746375, 12339663, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 27724736, 35845589, 73197064, 19369633, 68901590, 39412065, 80957277, 15768921, + 92200031, 14856293, + ]), + y_minus_x: FieldElement2625([ + 48242193, 8331042, 24373479, 8541013, 66406866, 24284974, 12927299, 20858939, + 44926390, 24541532, + ]), + xy2d: FieldElement2625([ + 55685435, 28132841, 11632844, 3405020, 30536730, 21880393, 39848098, 13866389, + 30146206, 9142070, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 71032974, 18246915, 120400605, 23499470, 79400683, 32886065, 39406089, 9326383, + 58871006, 37725725, + ]), + y_minus_x: FieldElement2625([ + 51186905, 16037936, 6713787, 16606682, 45496729, 2790943, 26396185, 3731949, + 345228, 28091483, + ]), + xy2d: FieldElement2625([ + 45781307, 13448258, 25284571, 1143661, 20614966, 24705045, 2031538, 21163201, + 50855680, 19972348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 98125037, 16832002, 93480255, 52657630, 62081513, 14854136, 17477601, 37397089, + 28012649, 50703444, + ]), + y_minus_x: FieldElement2625([ + 62033029, 9368965, 58546785, 28953529, 51858910, 6970559, 57918991, 16292056, + 58241707, 3507939, + ]), + xy2d: FieldElement2625([ + 29439664, 3537914, 23333589, 6997794, 49553303, 22536363, 51899661, 18503164, + 57943934, 6580395, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54922984, 59429075, 83547131, 10826159, 58412047, 27318820, 84969307, 24280585, + 65013061, 42858998, + ]), + y_minus_x: FieldElement2625([ + 20714545, 29217521, 29088194, 7406487, 11426967, 28458727, 14792666, 18945815, + 5289420, 33077305, + ]), + xy2d: FieldElement2625([ + 50443312, 22903641, 60948518, 20248671, 9192019, 31751970, 17271489, 12349094, + 26939669, 29802138, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54218947, 9373457, 98704712, 16374214, 21471720, 13221525, 39825369, 54760304, + 63410056, 33672318, + ]), + y_minus_x: FieldElement2625([ + 22263325, 26994382, 3984569, 22379786, 51994855, 32987646, 28311252, 5358056, + 43789084, 541963, + ]), + xy2d: FieldElement2625([ + 16259200, 3261970, 2309254, 18019958, 50223152, 28972515, 24134069, 16848603, + 53771797, 20002236, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76487005, 20414245, 111371745, 20809166, 95307144, 59864765, 64709178, + 32837080, 67799289, 48430675, + ]), + y_minus_x: FieldElement2625([ + 24977353, 33240048, 58884894, 20089345, 28432342, 32378079, 54040059, 21257083, + 44727879, 6618998, + ]), + xy2d: FieldElement2625([ + 65570671, 11685645, 12944378, 13682314, 42719353, 19141238, 8044828, 19737104, + 32239828, 27901670, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 48505798, 38317421, 66182613, 42439735, 105805247, 30367115, 76890510, + 23204372, 32779358, 5095274, + ]), + y_minus_x: FieldElement2625([ + 34100715, 28339925, 34843976, 29869215, 9460460, 24227009, 42507207, 14506723, + 21639561, 30924196, + ]), + xy2d: FieldElement2625([ + 50707921, 20442216, 25239337, 15531969, 3987758, 29055114, 65819361, 26690896, + 17874573, 558605, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 53508716, 10240080, 76280747, 16131052, 46239610, 43154131, 100608350, + 38634582, 69194755, 38674192, + ]), + y_minus_x: FieldElement2625([ + 44903700, 31034903, 50727262, 414690, 42089314, 2170429, 30634760, 25190818, + 35108870, 27794547, + ]), + xy2d: FieldElement2625([ + 60263160, 15791201, 8550074, 32241778, 29928808, 21462176, 27534429, 26362287, + 44757485, 12961481, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 42616785, 57538092, 10368192, 11582341, 110820435, 31309143, 83642793, 8206995, + 104023076, 28394792, + ]), + y_minus_x: FieldElement2625([ + 55987368, 30172197, 2307365, 6362031, 66973409, 8868176, 50273234, 7031274, + 7589640, 8945490, + ]), + xy2d: FieldElement2625([ + 34956097, 8917966, 6661220, 21876816, 65916803, 17761038, 7251488, 22372252, + 24099108, 19098262, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 72128384, 25646961, 71352990, 18840075, 107284455, 40007595, 47990681, + 20265406, 127985831, 56828126, + ]), + y_minus_x: FieldElement2625([ + 10853575, 10721687, 26480089, 5861829, 44113045, 1972174, 65242217, 22996533, + 63745412, 27113307, + ]), + xy2d: FieldElement2625([ + 50106456, 5906789, 221599, 26991285, 7828207, 20305514, 24362660, 31546264, + 53242455, 7421391, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 75248772, 27007934, 99366509, 27663885, 97484582, 1886180, 113042620, 48995682, + 95935221, 29431402, + ]), + y_minus_x: FieldElement2625([ + 6267067, 9695052, 7709135, 16950835, 34239795, 31668296, 14795159, 25714308, + 13746020, 31812384, + ]), + xy2d: FieldElement2625([ + 28584883, 7787108, 60375922, 18503702, 22846040, 25983196, 63926927, 33190907, + 4771361, 25134474, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 92058101, 6376278, 39642383, 25379823, 48462709, 23623825, 100652432, 54967168, + 70678489, 44897024, + ]), + y_minus_x: FieldElement2625([ + 26514970, 4740088, 27912651, 3697550, 19331575, 22082093, 6809885, 4608608, + 7325975, 18753361, + ]), + xy2d: FieldElement2625([ + 55490446, 19000001, 42787651, 7655127, 65739590, 5214311, 39708324, 10258389, + 49462170, 25367739, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 11431185, 49377439, 93679108, 47883555, 85138853, 38350513, 35662684, 49135095, + 76389221, 29580744, + ]), + y_minus_x: FieldElement2625([ + 66948081, 23228174, 44253547, 29249434, 46247496, 19933429, 34297962, 22372809, + 51563772, 4387440, + ]), + xy2d: FieldElement2625([ + 46309467, 12194511, 3937617, 27748540, 39954043, 9340369, 42594872, 8548136, + 20617071, 26072431, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 66170039, 29623845, 58394552, 49679149, 91711988, 27329038, 53333511, 55233041, + 91454545, 10325459, + ]), + y_minus_x: FieldElement2625([ + 47253587, 31985546, 44906155, 8714033, 14007766, 6928528, 16318175, 32543743, + 4766742, 3552007, + ]), + xy2d: FieldElement2625([ + 45357481, 16823515, 1351762, 32751011, 63099193, 3950934, 3217514, 14481909, + 10988822, 29559670, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 15564288, 19242862, 70210106, 39238579, 97555643, 25503075, 79785990, 27049088, + 58813011, 46850436, + ]), + y_minus_x: FieldElement2625([ + 57666574, 6624295, 36809900, 21640754, 62437882, 31497052, 31521203, 9614054, + 37108040, 12074673, + ]), + xy2d: FieldElement2625([ + 4771172, 33419193, 14290748, 20464580, 27992297, 14998318, 65694928, 31997715, + 29832612, 17163397, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 7064865, 59567690, 115055764, 62041325, 48217593, 30641695, 92934105, 38847728, + 39986203, 46656021, + ]), + y_minus_x: FieldElement2625([ + 64810282, 2439669, 59642254, 1719964, 39841323, 17225986, 32512468, 28236839, + 36752793, 29363474, + ]), + xy2d: FieldElement2625([ + 37102324, 10162315, 33928688, 3981722, 50626726, 20484387, 14413973, 9515896, + 19568978, 9628812, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 33053784, 33753789, 83003454, 35137490, 94489106, 28973996, 49269969, 61002024, + 60817076, 36992171, + ]), + y_minus_x: FieldElement2625([ + 48129987, 3884492, 19469877, 12726490, 15913552, 13614290, 44147131, 70103, + 7463304, 4176122, + ]), + xy2d: FieldElement2625([ + 39984863, 10659916, 11482427, 17484051, 12771466, 26919315, 34389459, 28231680, + 24216881, 5944158, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76002989, 41005405, 64444714, 57343111, 106137209, 21165315, 19345745, + 48235228, 78741856, 5847884, + ]), + y_minus_x: FieldElement2625([ + 26942781, 31239115, 9129563, 28647825, 26024104, 11769399, 55590027, 6367193, + 57381634, 4782139, + ]), + xy2d: FieldElement2625([ + 19916442, 28726022, 44198159, 22140040, 25606323, 27581991, 33253852, 8220911, + 6358847, 31680575, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 67910273, 31472729, 16569427, 44619599, 29875703, 33651059, 75017251, 29073951, + 53570360, 34941586, + ]), + y_minus_x: FieldElement2625([ + 19646058, 5720633, 55692158, 12814208, 11607948, 12749789, 14147075, 15156355, + 45242033, 11835259, + ]), + xy2d: FieldElement2625([ + 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, + 40548314, 5052482, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64091413, 43612637, 69089700, 37518674, 22160965, 12322533, 60677741, 20936246, + 12228556, 26550755, + ]), + y_minus_x: FieldElement2625([ + 32944382, 14922211, 44263970, 5188527, 21913450, 24834489, 4001464, 13238564, + 60994061, 8653814, + ]), + xy2d: FieldElement2625([ + 22865569, 28901697, 27603667, 21009037, 14348957, 8234005, 24808405, 5719875, + 28483275, 2841751, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 117796741, 32441125, 66781144, 21446575, 21886281, 51556090, 65220896, + 33238773, 87040921, 20815228, + ]), + y_minus_x: FieldElement2625([ + 55452759, 10087520, 58243976, 28018288, 47830290, 30498519, 3999227, 13239134, + 62331395, 19644223, + ]), + xy2d: FieldElement2625([ + 1382174, 21859713, 17266789, 9194690, 53784508, 9720080, 20403944, 11284705, + 53095046, 3093229, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 83759766, 56070931, 66044684, 35125060, 58779117, 40907184, 66806439, 16271224, + 43059443, 26862581, + ]), + y_minus_x: FieldElement2625([ + 45197768, 27626490, 62497547, 27994275, 35364760, 22769138, 24123613, 15193618, + 45456747, 16815042, + ]), + xy2d: FieldElement2625([ + 57172930, 29264984, 41829040, 4372841, 2087473, 10399484, 31870908, 14690798, + 17361620, 11864968, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 55801216, 39764803, 80315437, 39360751, 105200035, 19587230, 54777658, + 26067830, 41530403, 50868174, + ]), + y_minus_x: FieldElement2625([ + 14668443, 21284197, 26039038, 15305210, 25515617, 4542480, 10453892, 6577524, + 9145645, 27110552, + ]), + xy2d: FieldElement2625([ + 5974855, 3053895, 57675815, 23169240, 35243739, 3225008, 59136222, 3936127, + 61456591, 30504127, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97734231, 28825031, 41552902, 20761565, 46624288, 41249530, 17097187, 50805368, + 106217947, 35358062, + ]), + y_minus_x: FieldElement2625([ + 63555773, 9865098, 61880298, 4272700, 61435032, 16864731, 14911343, 12196514, + 45703375, 7047411, + ]), + xy2d: FieldElement2625([ + 20093258, 9920966, 55970670, 28210574, 13161586, 12044805, 34252013, 4124600, + 34765036, 23296865, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 46320021, 14084653, 53577151, 41396578, 19119037, 19731827, 71861240, 24839791, + 45429205, 35842469, + ]), + y_minus_x: FieldElement2625([ + 40289628, 30270716, 29965058, 3039786, 52635099, 2540456, 29457502, 14625692, + 42289247, 12570231, + ]), + xy2d: FieldElement2625([ + 66045306, 22002608, 16920317, 12494842, 1278292, 27685323, 45948920, 30055751, + 55134159, 4724942, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 85069815, 21778897, 62967895, 23851901, 58232301, 32143814, 54201480, 24894499, + 104641427, 35458286, + ]), + y_minus_x: FieldElement2625([ + 23134274, 19275300, 56426866, 31942495, 20684484, 15770816, 54119114, 3190295, + 26955097, 14109738, + ]), + xy2d: FieldElement2625([ + 15308788, 5320727, 36995055, 19235554, 22902007, 7767164, 29425325, 22276870, + 31960941, 11934971, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 39713134, 41990227, 71218507, 12222638, 109589860, 14818667, 87747037, + 38429459, 77600255, 34934149, + ]), + y_minus_x: FieldElement2625([ + 53949449, 9197840, 3875503, 24618324, 65725151, 27674630, 33518458, 16176658, + 21432314, 12180697, + ]), + xy2d: FieldElement2625([ + 55321537, 11500837, 13787581, 19721842, 44678184, 10140204, 1465425, 12689540, + 56807545, 19681548, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 72522936, 18168390, 46101199, 43198001, 79943833, 34740580, 64485947, 32212200, + 26128230, 39587344, + ]), + y_minus_x: FieldElement2625([ + 40771450, 19788269, 32496024, 19900513, 17847800, 20885276, 3604024, 8316894, + 41233830, 23117073, + ]), + xy2d: FieldElement2625([ + 3296484, 6223048, 24680646, 21307972, 44056843, 5903204, 58246567, 28915267, + 12376616, 3188849, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29190450, 18895386, 27549112, 32370916, 70628929, 22857130, 32049514, 26245319, + 50999629, 57256556, + ]), + y_minus_x: FieldElement2625([ + 52364359, 24245275, 735817, 32955454, 46701176, 28496527, 25246077, 17758763, + 18640740, 32593455, + ]), + xy2d: FieldElement2625([ + 60180029, 17123636, 10361373, 5642961, 4910474, 12345252, 35470478, 33060001, + 10530746, 1053335, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 104951742, 52922057, 120679510, 54991489, 47651803, 56453479, 102755357, + 30605445, 24018830, 48581076, + ]), + y_minus_x: FieldElement2625([ + 44516310, 30409154, 64819587, 5953842, 53668675, 9425630, 25310643, 13003497, + 64794073, 18408815, + ]), + xy2d: FieldElement2625([ + 39688860, 32951110, 59064879, 31885314, 41016598, 13987818, 39811242, 187898, + 43942445, 31022696, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 45364447, 19743956, 68953703, 38575859, 123783328, 17642957, 76825530, + 49821353, 62038646, 34280530, + ]), + y_minus_x: FieldElement2625([ + 29370903, 27500434, 7334070, 18212173, 9385286, 2247707, 53446902, 28714970, + 30007387, 17731091, + ]), + xy2d: FieldElement2625([ + 66172485, 16086690, 23751945, 33011114, 65941325, 28365395, 9137108, 730663, + 9835848, 4555336, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 43732410, 34964877, 44855110, 54209249, 97976497, 49381408, 17693929, 34099128, + 55123565, 45977077, + ]), + y_minus_x: FieldElement2625([ + 31117226, 21338698, 53606025, 6561946, 57231997, 20796761, 61990178, 29457725, + 29120152, 13924425, + ]), + xy2d: FieldElement2625([ + 49707966, 19321222, 19675798, 30819676, 56101901, 27695611, 57724924, 22236731, + 7240930, 33317044, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 35747087, 22207651, 119210280, 27698212, 111764387, 54956091, 68331198, + 37943914, 70402500, 51557120, + ]), + y_minus_x: FieldElement2625([ + 50424044, 19110186, 11038543, 11054958, 53307689, 30215898, 42789283, 7733546, + 12796905, 27218610, + ]), + xy2d: FieldElement2625([ + 58349431, 22736595, 41689999, 10783768, 36493307, 23807620, 38855524, 3647835, + 3222231, 22393970, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 85714958, 35247531, 108769341, 51938590, 71221215, 43599452, 23603892, + 31506198, 59558087, 36039416, + ]), + y_minus_x: FieldElement2625([ + 9255298, 30423235, 54952701, 32550175, 13098012, 24339566, 16377219, 31451620, + 47306788, 30519729, + ]), + xy2d: FieldElement2625([ + 44379556, 7496159, 61366665, 11329248, 19991973, 30206930, 35390715, 9936965, + 37011176, 22935634, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 88987435, 28553134, 71447199, 47198328, 64071998, 13160959, 86817760, 5415496, + 59748361, 29445138, + ]), + y_minus_x: FieldElement2625([ + 27736842, 10103576, 12500508, 8502413, 63695848, 23920873, 10436917, 32004156, + 43449720, 25422331, + ]), + xy2d: FieldElement2625([ + 19492550, 21450067, 37426887, 32701801, 63900692, 12403436, 30066266, 8367329, + 13243957, 8709688, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 79123950, 36355692, 95306994, 10151020, 91926984, 28811298, 55914672, 27908697, + 72259831, 40828617, + ]), + y_minus_x: FieldElement2625([ + 2831347, 21062286, 1478974, 6122054, 23825128, 20820846, 31097298, 6083058, + 31021603, 23760822, + ]), + xy2d: FieldElement2625([ + 64578913, 31324785, 445612, 10720828, 53259337, 22048494, 43601132, 16354464, + 15067285, 19406725, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 74949787, 47592304, 100852864, 49488446, 66380650, 29911725, 88512851, + 34612017, 47729401, 21151211, + ]), + y_minus_x: FieldElement2625([ + 915865, 17085158, 15608284, 24765302, 42751837, 6060029, 49737545, 8410996, + 59888403, 16527024, + ]), + xy2d: FieldElement2625([ + 32922597, 32997445, 20336073, 17369864, 10903704, 28169945, 16957573, 52992, + 23834301, 6588044, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 32752011, 44787382, 70490858, 24839565, 22652987, 22810329, 17159698, 50243539, + 46794283, 32248439, + ]), + y_minus_x: FieldElement2625([ + 62419196, 9166775, 41398568, 22707125, 11576751, 12733943, 7924251, 30802151, + 1976122, 26305405, + ]), + xy2d: FieldElement2625([ + 21251203, 16309901, 64125849, 26771309, 30810596, 12967303, 156041, 30183180, + 12331344, 25317235, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 75760459, 29077399, 118132091, 28557436, 80111370, 36505236, 96163290, + 28447461, 77116999, 28886530, + ]), + y_minus_x: FieldElement2625([ + 31486061, 15114593, 52847614, 12951353, 14369431, 26166587, 16347320, 19892343, + 8684154, 23021480, + ]), + xy2d: FieldElement2625([ + 19443825, 11385320, 24468943, 23895364, 43189605, 2187568, 40845657, 27467510, + 31316347, 14219878, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 38514355, 1193784, 99354083, 11392484, 31092169, 49277233, 94254877, 40546840, + 29126554, 42761822, + ]), + y_minus_x: FieldElement2625([ + 32382916, 1110093, 18477781, 11028262, 39697101, 26006320, 62128346, 10843781, + 59151264, 19118701, + ]), + xy2d: FieldElement2625([ + 2814918, 7836403, 27519878, 25686276, 46214848, 22000742, 45614304, 8550129, + 28346258, 1994730, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 47530546, 41639976, 53108344, 29605809, 69894701, 17323124, 47591912, 40729325, + 22628101, 41669612, + ]), + y_minus_x: FieldElement2625([ + 36703732, 955510, 55975026, 18476362, 34661776, 20276352, 41457285, 3317159, + 57165847, 930271, + ]), + xy2d: FieldElement2625([ + 51805164, 26720662, 28856489, 1357446, 23421993, 1057177, 24091212, 32165462, + 44343487, 22903716, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 44357614, 28250434, 54201256, 54339997, 51297351, 25757378, 52269845, 50554643, + 65241844, 41953401, + ]), + y_minus_x: FieldElement2625([ + 35139535, 2106402, 62372504, 1362500, 12813763, 16200670, 22981545, 27263159, + 18009407, 17781660, + ]), + xy2d: FieldElement2625([ + 49887941, 24009210, 39324209, 14166834, 29815394, 7444469, 29551787, 29827013, + 19288548, 1325865, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82209002, 51273111, 110293748, 32549332, 107767535, 49063838, 79485593, + 30075285, 100274970, 25511681, + ]), + y_minus_x: FieldElement2625([ + 20909212, 13023121, 57899112, 16251777, 61330449, 25459517, 12412150, 10018715, + 2213263, 19676059, + ]), + xy2d: FieldElement2625([ + 32529814, 22479743, 30361438, 16864679, 57972923, 1513225, 22922121, 6382134, + 61341936, 8371347, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77032307, 44825931, 79725657, 37099153, 104219359, 31832804, 12891686, + 25361300, 40665920, 44040575, + ]), + y_minus_x: FieldElement2625([ + 44511638, 26541766, 8587002, 25296571, 4084308, 20584370, 361725, 2610596, + 43187334, 22099236, + ]), + xy2d: FieldElement2625([ + 5408392, 32417741, 62139741, 10561667, 24145918, 14240566, 31319731, 29318891, + 19985174, 30118346, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 53114388, 50171252, 81658109, 36895530, 99264821, 13648975, 49531796, 8849296, + 67173894, 41925115, + ]), + y_minus_x: FieldElement2625([ + 58787919, 21504805, 31204562, 5839400, 46481576, 32497154, 47665921, 6922163, + 12743482, 23753914, + ]), + xy2d: FieldElement2625([ + 64747493, 12678784, 28815050, 4759974, 43215817, 4884716, 23783145, 11038569, + 18800704, 255233, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 61839168, 31780545, 13957885, 41545147, 23132994, 34283205, 80502710, 42621388, + 86367551, 52355070, + ]), + y_minus_x: FieldElement2625([ + 64172210, 22726896, 56676774, 14516792, 63468078, 4372540, 35173943, 2209389, + 65584811, 2055793, + ]), + xy2d: FieldElement2625([ + 580882, 16705327, 5468415, 30871414, 36182444, 18858431, 59905517, 24560042, + 37087844, 7394434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 90947654, 35377159, 118479284, 48797157, 75426955, 29821327, 45436683, + 30062226, 62287122, 48354352, + ]), + y_minus_x: FieldElement2625([ + 13345610, 9759151, 3371034, 17416641, 16353038, 8577942, 31129804, 13496856, + 58052846, 7402517, + ]), + xy2d: FieldElement2625([ + 2286874, 29118501, 47066405, 31546095, 53412636, 5038121, 11006906, 17794080, + 8205060, 1607563, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 81522931, 25552299, 70440693, 63900646, 89358013, 27960243, 85473524, 30647473, + 30019586, 24525154, + ]), + y_minus_x: FieldElement2625([ + 39420813, 1585952, 56333811, 931068, 37988643, 22552112, 52698034, 12029092, + 9944378, 8024, + ]), + xy2d: FieldElement2625([ + 4368715, 29844802, 29874199, 18531449, 46878477, 22143727, 50994269, 32555346, + 58966475, 5640029, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77408455, 13746482, 11661824, 16234854, 74739102, 5998373, 76918751, 16859867, + 82328661, 19226648, + ]), + y_minus_x: FieldElement2625([ + 27425505, 27835351, 3055005, 10660664, 23458024, 595578, 51710259, 32381236, + 48766680, 9742716, + ]), + xy2d: FieldElement2625([ + 6744077, 2427284, 26042789, 2720740, 66260958, 1118973, 32324614, 7406442, + 12420155, 1994844, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 81121366, 62084143, 115833273, 23975961, 107732385, 29617991, 121184249, + 22644627, 91428792, 27108098, + ]), + y_minus_x: FieldElement2625([ + 16412671, 29047065, 10772640, 15929391, 50040076, 28895810, 10555944, 23070383, + 37006495, 28815383, + ]), + xy2d: FieldElement2625([ + 22397363, 25786748, 57815702, 20761563, 17166286, 23799296, 39775798, 6199365, + 21880021, 21303672, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62825538, 5368522, 35991846, 41717820, 103894664, 36763558, 83666014, 42445160, + 75949308, 38512191, + ]), + y_minus_x: FieldElement2625([ + 51661137, 709326, 60189418, 22684253, 37330941, 6522331, 45388683, 12130071, + 52312361, 5005756, + ]), + xy2d: FieldElement2625([ + 64994094, 19246303, 23019041, 15765735, 41839181, 6002751, 10183197, 20315106, + 50713577, 31378319, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 115191953, 35186435, 80575154, 59113763, 110577275, 16573535, 35094956, + 30497327, 22208661, 35554900, + ]), + y_minus_x: FieldElement2625([ + 3065054, 32141671, 41510189, 33192999, 49425798, 27851016, 58944651, 11248526, + 63417650, 26140247, + ]), + xy2d: FieldElement2625([ + 10379208, 27508878, 8877318, 1473647, 37817580, 21046851, 16690914, 2553332, + 63976176, 16400288, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82825513, 34808697, 115745037, 41000704, 58659945, 6344163, 45011593, 26268851, + 26894936, 42686498, + ]), + y_minus_x: FieldElement2625([ + 24158868, 12938817, 11085297, 25376834, 39045385, 29097348, 36532400, 64451, + 60291780, 30861549, + ]), + xy2d: FieldElement2625([ + 13488534, 7794716, 22236231, 5989356, 25426474, 20976224, 2350709, 30135921, + 62420857, 2364225, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 83443897, 9132433, 92749446, 40233319, 68834491, 42072368, 55301839, 21856974, + 15445874, 25756331, + ]), + y_minus_x: FieldElement2625([ + 29004188, 25687351, 28661401, 32914020, 54314860, 25611345, 31863254, 29418892, + 66830813, 17795152, + ]), + xy2d: FieldElement2625([ + 60986784, 18687766, 38493958, 14569918, 56250865, 29962602, 10343411, 26578142, + 37280576, 22738620, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 94190495, 37018415, 14099041, 29036828, 68725166, 27348827, 96651499, 15372178, + 84402661, 34515140, + ]), + y_minus_x: FieldElement2625([ + 20263915, 11434237, 61343429, 11236809, 13505955, 22697330, 50997518, 6493121, + 47724353, 7639713, + ]), + xy2d: FieldElement2625([ + 64278047, 18715199, 25403037, 25339236, 58791851, 17380732, 18006286, 17510682, + 29994676, 17746311, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76878673, 38757082, 110060329, 19923038, 106166724, 21992806, 42495722, + 53248081, 35924287, 34263895, + ]), + y_minus_x: FieldElement2625([ + 12286395, 13076066, 45333675, 32377809, 42105665, 4057651, 35090736, 24663557, + 16102006, 13205847, + ]), + xy2d: FieldElement2625([ + 13733362, 5599946, 10557076, 3195751, 61550873, 8536969, 41568694, 8525971, + 10151379, 10394400, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 71133505, 17416880, 89545125, 12276533, 58009849, 64422764, 86807091, 11743038, + 100915394, 42488844, + ]), + y_minus_x: FieldElement2625([ + 51229064, 29029191, 58528116, 30620370, 14634844, 32856154, 57659786, 3137093, + 55571978, 11721157, + ]), + xy2d: FieldElement2625([ + 17555920, 28540494, 8268605, 2331751, 44370049, 9761012, 9319229, 8835153, + 57903375, 32274386, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 66647436, 25724417, 87722981, 16688287, 59594098, 28747312, 89409167, 34059860, + 73217325, 27371016, + ]), + y_minus_x: FieldElement2625([ + 62038564, 12367916, 36445330, 3234472, 32617080, 25131790, 29880582, 20071101, + 40210373, 25686972, + ]), + xy2d: FieldElement2625([ + 35133562, 5726538, 26934134, 10237677, 63935147, 32949378, 24199303, 3795095, + 7592688, 18562353, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 21594413, 18590204, 84575271, 63031641, 32537082, 36294330, 73516586, 12018832, + 38852812, 37852843, + ]), + y_minus_x: FieldElement2625([ + 46458361, 21592935, 39872588, 570497, 3767144, 31836892, 13891941, 31985238, + 13717173, 10805743, + ]), + xy2d: FieldElement2625([ + 52432215, 17910135, 15287173, 11927123, 24177847, 25378864, 66312432, 14860608, + 40169934, 27690595, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 80071405, 38866230, 57048095, 45212711, 85964149, 25600230, 80395126, 54300159, + 62727806, 9882021, + ]), + y_minus_x: FieldElement2625([ + 18512060, 11319350, 46985740, 15090308, 18818594, 5271736, 44380960, 3666878, + 43141434, 30255002, + ]), + xy2d: FieldElement2625([ + 60319844, 30408388, 16192428, 13241070, 15898607, 19348318, 57023983, 26893321, + 64705764, 5276064, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97278672, 28236783, 93415069, 55358004, 94923826, 40623698, 74261714, 37239413, + 68558087, 13082860, + ]), + y_minus_x: FieldElement2625([ + 10342807, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, + 46092426, 25352431, + ]), + xy2d: FieldElement2625([ + 33958735, 3261607, 22745853, 7948688, 19370557, 18376767, 40936887, 6482813, + 56808784, 22494330, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 32869439, 61700319, 25609741, 49233102, 56421094, 51637792, 26112419, 36075440, + 44444575, 40459246, + ]), + y_minus_x: FieldElement2625([ + 29506904, 4457497, 3377935, 23757988, 36598817, 12935079, 1561737, 3841096, + 38105225, 26896789, + ]), + xy2d: FieldElement2625([ + 10340844, 26924055, 48452231, 31276001, 12621150, 20215377, 30878496, 21730062, + 41524312, 5181965, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 25940096, 20896407, 17324187, 56801490, 58437394, 15029093, 91505116, 17103509, + 64786011, 21165857, + ]), + y_minus_x: FieldElement2625([ + 45343161, 9916822, 65808455, 4079497, 66080518, 11909558, 1782390, 12641087, + 20603771, 26992690, + ]), + xy2d: FieldElement2625([ + 48226577, 21881051, 24849421, 11501709, 13161720, 28785558, 1925522, 11914390, + 4662781, 7820689, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 79349895, 33128449, 75241554, 42948365, 32846759, 31954812, 29749455, 45727356, + 83245615, 48818451, + ]), + y_minus_x: FieldElement2625([ + 56758909, 18873868, 58896884, 2330219, 49446315, 19008651, 10658212, 6671822, + 19012087, 3772772, + ]), + xy2d: FieldElement2625([ + 3753511, 30133366, 10617073, 2028709, 14841030, 26832768, 28718731, 17791548, + 20527770, 12988982, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 52286341, 27757162, 63400876, 12689772, 66209881, 22639565, 110034681, + 56543919, 70408527, 54683910, + ]), + y_minus_x: FieldElement2625([ + 50331161, 18301130, 57466446, 4978982, 3308785, 8755439, 6943197, 6461331, + 41525717, 8991217, + ]), + xy2d: FieldElement2625([ + 49882601, 1816361, 65435576, 27467992, 31783887, 25378441, 34160718, 7417949, + 36866577, 1507264, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29692644, 40384323, 56610063, 37889327, 88054838, 21647935, 38221255, 41763822, + 14606361, 22907359, + ]), + y_minus_x: FieldElement2625([ + 63627275, 8707080, 32188102, 5672294, 22096700, 1711240, 34088169, 9761486, + 4170404, 31469107, + ]), + xy2d: FieldElement2625([ + 55521375, 14855944, 62981086, 32022574, 40459774, 15084045, 22186522, 16002000, + 52832027, 25153633, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62297389, 47315460, 35404986, 31070512, 63796392, 41423478, 59995291, 23934339, + 80349708, 44520301, + ]), + y_minus_x: FieldElement2625([ + 59366301, 25297669, 52340529, 19898171, 43876480, 12387165, 4498947, 14147411, + 29514390, 4302863, + ]), + xy2d: FieldElement2625([ + 53695440, 21146572, 20757301, 19752600, 14785142, 8976368, 62047588, 31410058, + 17846987, 19582505, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64864393, 32799703, 62511833, 32488122, 60861691, 35009730, 112569999, + 24339641, 61886162, 46204698, + ]), + y_minus_x: FieldElement2625([ + 57202067, 17484121, 21134159, 12198166, 40044289, 708125, 387813, 13770293, + 47974538, 10958662, + ]), + xy2d: FieldElement2625([ + 22470984, 12369526, 23446014, 28113323, 45588061, 23855708, 55336367, 21979976, + 42025033, 4271861, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 109048144, 57055220, 47199530, 48916026, 61124505, 35713623, 67184238, + 62830334, 101691505, 42024103, + ]), + y_minus_x: FieldElement2625([ + 15854951, 4148314, 58214974, 7259001, 11666551, 13824734, 36577666, 2697371, + 24154791, 24093489, + ]), + xy2d: FieldElement2625([ + 15446137, 17747788, 29759746, 14019369, 30811221, 23944241, 35526855, 12840103, + 24913809, 9815020, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62399559, 27940162, 35267365, 21265538, 52665326, 44353845, 125114051, + 46993199, 85843991, 43020669, + ]), + y_minus_x: FieldElement2625([ + 11933045, 9281483, 5081055, 28370608, 64480701, 28648802, 59381042, 22658328, + 44380208, 16199063, + ]), + xy2d: FieldElement2625([ + 14576810, 379472, 40322331, 25237195, 37682355, 22741457, 67006097, 1876698, + 30801119, 2164795, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 15995067, 36754305, 13672554, 13712240, 47730029, 62461217, 121136116, + 51612593, 53616055, 34822483, + ]), + y_minus_x: FieldElement2625([ + 56818250, 29895392, 63822271, 10948817, 23037027, 3794475, 63638526, 20954210, + 50053494, 3565903, + ]), + xy2d: FieldElement2625([ + 29210069, 24135095, 61189071, 28601646, 10834810, 20226706, 50596761, 22733718, + 39946641, 19523900, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 121055819, 49063018, 83772567, 25398281, 38758921, 42573554, 37925442, + 29785008, 69352974, 19552452, + ]), + y_minus_x: FieldElement2625([ + 61955989, 29753495, 57802388, 27482848, 16243068, 14684434, 41435776, 17373631, + 13491505, 4641841, + ]), + xy2d: FieldElement2625([ + 10813398, 643330, 47920349, 32825515, 30292061, 16954354, 27548446, 25833190, + 14476988, 20787001, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77400943, 9984944, 73590300, 41834336, 59857349, 40587174, 27282936, 31910173, + 106304917, 12651322, + ]), + y_minus_x: FieldElement2625([ + 35923332, 32741048, 22271203, 11835308, 10201545, 15351028, 17099662, 3988035, + 21721536, 30405492, + ]), + xy2d: FieldElement2625([ + 10202177, 27008593, 35735631, 23979793, 34958221, 25434748, 54202543, 3852693, + 13216206, 14842320, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 51293205, 22953365, 60569911, 26295436, 60124204, 26972653, 35608016, 47320255, + 106783330, 43454614, + ]), + y_minus_x: FieldElement2625([ + 14465486, 19721101, 34974879, 18815558, 39665676, 12990491, 33046193, 15796406, + 60056998, 25514317, + ]), + xy2d: FieldElement2625([ + 30924398, 25274812, 6359015, 20738097, 16508376, 9071735, 41620263, 15413634, + 9524356, 26535554, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 12274182, 20378885, 99736504, 65323537, 73845487, 13267304, 72346523, 28444948, + 82772379, 37590215, + ]), + y_minus_x: FieldElement2625([ + 64157555, 8903984, 17349946, 601635, 50676049, 28941875, 53376124, 17665097, + 44850385, 4659090, + ]), + xy2d: FieldElement2625([ + 50192582, 28601458, 36715152, 18395610, 20774811, 15897498, 5736189, 15026997, + 64930608, 20098846, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 58249865, 31335375, 28571665, 56953346, 66634395, 23448733, 63307367, 33832526, + 23440561, 33264224, + ]), + y_minus_x: FieldElement2625([ + 10226222, 27625730, 15139955, 120818, 52241171, 5218602, 32937275, 11551483, + 50536904, 26111567, + ]), + xy2d: FieldElement2625([ + 17932739, 21117156, 43069306, 10749059, 11316803, 7535897, 22503767, 5561594, + 63462240, 3898660, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 74858752, 32584864, 50769132, 33537967, 42090752, 15122142, 65535333, 40706961, + 88940025, 34799664, + ]), + y_minus_x: FieldElement2625([ + 26958440, 18896406, 4314585, 8346991, 61431100, 11960071, 34519569, 32934396, + 36706772, 16838219, + ]), + xy2d: FieldElement2625([ + 54942968, 9166946, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, + 44770839, 13987524, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 109867800, 7778773, 88224864, 49127028, 62275597, 28196653, 62807965, 28429792, + 59639082, 30696363, + ]), + y_minus_x: FieldElement2625([ + 9681908, 26817309, 35157219, 13591837, 60225043, 386949, 31622781, 6439245, + 52527852, 4091396, + ]), + xy2d: FieldElement2625([ + 58682418, 1470726, 38999185, 31957441, 3978626, 28430809, 47486180, 12092162, + 29077877, 18812444, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 72378032, 26694705, 120987516, 25533715, 25932562, 35317984, 61502753, + 28048550, 47091016, 2357888, + ]), + y_minus_x: FieldElement2625([ + 32264008, 18146780, 61721128, 32394338, 65017541, 29607531, 23104803, 20684524, + 5727337, 189038, + ]), + xy2d: FieldElement2625([ + 14609104, 24599962, 61108297, 16931650, 52531476, 25810533, 40363694, 10942114, + 41219933, 18669734, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 87622345, 39112362, 51504250, 41383962, 93522806, 31535027, 45729895, 41026212, + 13913676, 28416557, + ]), + y_minus_x: FieldElement2625([ + 41534488, 11967825, 29233242, 12948236, 60354399, 4713226, 58167894, 14059179, + 12878652, 8511905, + ]), + xy2d: FieldElement2625([ + 41452044, 3393630, 64153449, 26478905, 64858154, 9366907, 36885446, 6812973, + 5568676, 30426776, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 78738868, 12144453, 69225203, 47160468, 94487748, 49231348, 49700110, 20050058, + 119822531, 8070816, + ]), + y_minus_x: FieldElement2625([ + 27117677, 23547054, 35826092, 27984343, 1127281, 12772488, 37262958, 10483305, + 55556115, 32525717, + ]), + xy2d: FieldElement2625([ + 10637467, 27866368, 5674780, 1072708, 40765276, 26572129, 65424888, 9177852, + 39615702, 15431202, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 87633990, 44446997, 121475255, 12779441, 104724694, 16150073, 105977209, + 14943140, 52052074, 25618500, + ]), + y_minus_x: FieldElement2625([ + 37084402, 5626925, 66557297, 23573344, 753597, 11981191, 25244767, 30314666, + 63752313, 9594023, + ]), + xy2d: FieldElement2625([ + 43356201, 2636869, 61944954, 23450613, 585133, 7877383, 11345683, 27062142, + 13352334, 22577348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 65177046, 28146973, 70413512, 54223994, 84124668, 62231772, 104433876, + 25801948, 53893326, 33235227, + ]), + y_minus_x: FieldElement2625([ + 20239939, 6607058, 6203985, 3483793, 48721888, 32775202, 46385121, 15077869, + 44358105, 14523816, + ]), + xy2d: FieldElement2625([ + 27406023, 27512775, 27423595, 29057038, 4996213, 10002360, 38266833, 29008937, + 36936121, 28748764, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 78483087, 12660714, 17861383, 21013599, 78044431, 34653658, 53222787, 24462691, + 106490683, 44912934, + ]), + y_minus_x: FieldElement2625([ + 54378055, 10311866, 1510375, 10778093, 64989409, 24408729, 32676002, 11149336, + 40985213, 4985767, + ]), + xy2d: FieldElement2625([ + 48012542, 341146, 60911379, 33315398, 15756972, 24757770, 66125820, 13794113, + 47694557, 17933176, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 73598907, 45494717, 25495922, 59382504, 75777235, 24803115, 70476466, 40524436, + 65417798, 58104073, + ]), + y_minus_x: FieldElement2625([ + 1656478, 13457317, 15370807, 6364910, 13605745, 8362338, 47934242, 28078708, + 50312267, 28522993, + ]), + xy2d: FieldElement2625([ + 44835530, 20030007, 67044178, 29220208, 48503227, 22632463, 46537798, 26546453, + 67009010, 23317098, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 84856310, 43593691, 86477162, 29503840, 46478228, 51067577, 99101545, 17696455, + 104957364, 28042459, + ]), + y_minus_x: FieldElement2625([ + 31932008, 28568291, 47496481, 16366579, 22023614, 88450, 11371999, 29810185, + 4882241, 22927527, + ]), + xy2d: FieldElement2625([ + 29796488, 37186, 19818052, 10115756, 55279832, 3352735, 18551198, 3272828, + 61917932, 29392022, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 12501267, 4044383, 58495907, 53716478, 101787674, 38691029, 47878485, 30024734, + 330069, 29895023, + ]), + y_minus_x: FieldElement2625([ + 6384877, 2899513, 17807477, 7663917, 64749976, 12363164, 25366522, 24980540, + 66837568, 12071498, + ]), + xy2d: FieldElement2625([ + 58743349, 29511910, 25133447, 29037077, 60897836, 2265926, 34339246, 1936674, + 61949167, 3829362, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 28425947, 27718999, 66531773, 28857233, 120000172, 40425360, 75030413, + 26986644, 26333139, 47822096, + ]), + y_minus_x: FieldElement2625([ + 56041645, 11871230, 27385719, 22994888, 62522949, 22365119, 10004785, 24844944, + 45347639, 8930323, + ]), + xy2d: FieldElement2625([ + 45911060, 17158396, 25654215, 31829035, 12282011, 11008919, 1541940, 4757911, + 40617363, 17145491, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 80646107, 25794941, 113612887, 44516357, 61186043, 20336366, 53952279, + 39771685, 118274028, 47369420, + ]), + y_minus_x: FieldElement2625([ + 49686272, 15157789, 18705543, 29619, 24409717, 33293956, 27361680, 9257833, + 65152338, 31777517, + ]), + xy2d: FieldElement2625([ + 42063564, 23362465, 15366584, 15166509, 54003778, 8423555, 37937324, 12361134, + 48422886, 4578289, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 91688613, 3711569, 68451186, 22374305, 107212592, 47679386, 44564334, 14074918, + 21964432, 41789689, + ]), + y_minus_x: FieldElement2625([ + 60580251, 31142934, 9442965, 27628844, 12025639, 32067012, 64127349, 31885225, + 13006805, 2355433, + ]), + xy2d: FieldElement2625([ + 50803946, 19949172, 60476436, 28412082, 16974358, 22643349, 27202043, 1719366, + 1141648, 20758196, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54244901, 53888877, 58790596, 56090772, 60298717, 28710537, 13475065, 30420460, + 32674894, 47269477, + ]), + y_minus_x: FieldElement2625([ + 11423316, 28086373, 32344215, 8962751, 24989809, 9241752, 53843611, 16086211, + 38367983, 17912338, + ]), + xy2d: FieldElement2625([ + 65699196, 12530727, 60740138, 10847386, 19531186, 19422272, 55399715, 7791793, + 39862921, 4383346, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 38137947, 38825878, 65842854, 23817442, 121762491, 50287029, 62246456, + 62202414, 27193555, 39799623, + ]), + y_minus_x: FieldElement2625([ + 51914908, 5362277, 65324971, 2695833, 4960227, 12840725, 23061898, 3260492, + 22510453, 8577507, + ]), + xy2d: FieldElement2625([ + 54476394, 11257345, 34415870, 13548176, 66387860, 10879010, 31168030, 13952092, + 37537372, 29918525, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 70986166, 23981692, 99525555, 38959755, 56104456, 19897796, 70868632, 45489751, + 72720723, 41718449, + ]), + y_minus_x: FieldElement2625([ + 50833043, 14667796, 15906460, 12155291, 44997715, 24514713, 32003001, 24722143, + 5773084, 25132323, + ]), + xy2d: FieldElement2625([ + 43320746, 25300131, 1950874, 8937633, 18686727, 16459170, 66203139, 12376319, + 31632953, 190926, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 109624102, 17415545, 58684872, 13378745, 81271271, 6901327, 58820115, 38062995, + 41767308, 29926903, + ]), + y_minus_x: FieldElement2625([ + 8884438, 27670423, 6023973, 10104341, 60227295, 28612898, 18722940, 18768427, + 65436375, 827624, + ]), + xy2d: FieldElement2625([ + 34388281, 17265135, 34605316, 7101209, 13354605, 2659080, 65308289, 19446395, + 42230385, 1541285, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 70010192, 32436744, 70989239, 57049475, 116596786, 29941649, 45306746, + 29986950, 87565708, 31669398, + ]), + y_minus_x: FieldElement2625([ + 27019610, 12299467, 53450576, 31951197, 54247203, 28692960, 47568713, 28538373, + 29439640, 15138866, + ]), + xy2d: FieldElement2625([ + 21536104, 26928012, 34661045, 22864223, 44700786, 5175813, 61688824, 17193268, + 7779327, 109896, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97388589, 48203181, 59063992, 39979989, 80748484, 32810922, 28698389, 45734550, + 23177718, 33000357, + ]), + y_minus_x: FieldElement2625([ + 26572828, 3405927, 35407164, 12890904, 47843196, 5335865, 60615096, 2378491, + 4439158, 20275085, + ]), + xy2d: FieldElement2625([ + 44392139, 3489069, 57883598, 33221678, 18875721, 32414337, 14819433, 20822905, + 49391106, 28092994, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62052362, 50120982, 83062524, 37322183, 56672364, 49181491, 66287909, 35731656, + 75658945, 18440266, + ]), + y_minus_x: FieldElement2625([ + 48635543, 16596774, 66727204, 15663610, 22860960, 15585581, 39264755, 29971692, + 43848403, 25125843, + ]), + xy2d: FieldElement2625([ + 34628313, 15707274, 58902952, 27902350, 29464557, 2713815, 44383727, 15860481, + 45206294, 1494192, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 47546754, 53021470, 41524990, 24254879, 80236705, 34314140, 21923481, 16529112, + 75851568, 46521448, + ]), + y_minus_x: FieldElement2625([ + 38643965, 1553204, 32536856, 23080703, 42417258, 33148257, 58194238, 30620535, + 37205105, 15553882, + ]), + xy2d: FieldElement2625([ + 21877890, 3230008, 9881174, 10539357, 62311749, 2841331, 11543572, 14513274, + 19375923, 20906471, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 75941133, 52613378, 80362373, 38692006, 72146734, 37633208, 24880817, 60886148, + 69971515, 9455042, + ]), + y_minus_x: FieldElement2625([ + 29306751, 5123106, 20245049, 19404543, 9592565, 8447059, 65031740, 30564351, + 15511448, 4789663, + ]), + xy2d: FieldElement2625([ + 46429108, 7004546, 8824831, 24119455, 63063159, 29803695, 61354101, 108892, + 23513200, 16652362, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 100961536, 37699212, 62632834, 26975308, 77878902, 26398889, 60458447, + 54172563, 115898528, 43767290, + ]), + y_minus_x: FieldElement2625([ + 2756062, 8598110, 7383731, 26694540, 22312758, 32449420, 21179800, 2600940, + 57120566, 21047965, + ]), + xy2d: FieldElement2625([ + 42463153, 13317461, 36659605, 17900503, 21365573, 22684775, 11344423, 864440, + 64609187, 16844368, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 107784906, 6148327, 49924452, 19080277, 85891792, 33278434, 44547329, 33765731, + 69828620, 38495428, + ]), + y_minus_x: FieldElement2625([ + 65784982, 3911312, 60160120, 14759764, 37081714, 7851206, 21690126, 8518463, + 26699843, 5276295, + ]), + xy2d: FieldElement2625([ + 53958991, 27125364, 9396248, 365013, 24703301, 23065493, 1321585, 149635, + 51656090, 7159368, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77096625, 30149672, 84616825, 43059961, 76840398, 31388917, 89464872, 41866607, + 89586081, 25151046, + ]), + y_minus_x: FieldElement2625([ + 18155857, 17049442, 19744715, 9006923, 15154154, 23015456, 24256459, 28689437, + 44560690, 9334108, + ]), + xy2d: FieldElement2625([ + 2986088, 28642539, 10776627, 30080588, 10620589, 26471229, 45695018, 14253544, + 44521715, 536905, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 71486582, 41670267, 91675941, 15495313, 78733938, 46619030, 74499414, 44144056, + 77946923, 51688439, + ]), + y_minus_x: FieldElement2625([ + 47766460, 867879, 9277171, 30335973, 52677291, 31567988, 19295825, 17757482, + 6378259, 699185, + ]), + xy2d: FieldElement2625([ + 7895007, 4057113, 60027092, 20476675, 49222032, 33231305, 66392824, 15693154, + 62063800, 20180469, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 59371282, 27685029, 119651408, 26147511, 78494517, 46756047, 31730677, + 22591592, 63190227, 23885106, + ]), + y_minus_x: FieldElement2625([ + 10188286, 17783598, 59772502, 13427542, 22223443, 14896287, 30743455, 7116568, + 45322357, 5427592, + ]), + xy2d: FieldElement2625([ + 696102, 13206899, 27047647, 22922350, 15285304, 23701253, 10798489, 28975712, + 19236242, 12477404, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 55879406, 44798227, 50054593, 25513566, 66320635, 58940896, 63211193, 44734935, + 43939347, 41288075, + ]), + y_minus_x: FieldElement2625([ + 17800790, 19518253, 40108434, 21787760, 23887826, 3149671, 23466177, 23016261, + 10322026, 15313801, + ]), + xy2d: FieldElement2625([ + 26246234, 11968874, 32263343, 28085704, 6830754, 20231401, 51314159, 33452449, + 42659621, 10890803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 35743198, 43825794, 54448238, 27287163, 83799070, 54046319, 119235514, + 50039361, 92289660, 28219547, + ]), + y_minus_x: FieldElement2625([ + 66522290, 10376443, 34522450, 22268075, 19801892, 10997610, 2276632, 9482883, + 316878, 13820577, + ]), + xy2d: FieldElement2625([ + 57226037, 29044064, 64993357, 16457135, 56008783, 11674995, 30756178, 26039378, + 30696929, 29841583, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 100097781, 23951019, 12499365, 41465219, 56491606, 21622917, 59766047, + 57123466, 34759345, 7392472, + ]), + y_minus_x: FieldElement2625([ + 58253184, 15927860, 9866406, 29905021, 64711949, 16898650, 36699387, 24419436, + 25112946, 30627788, + ]), + xy2d: FieldElement2625([ + 64604801, 33117465, 25621773, 27875660, 15085041, 28074555, 42223985, 20028237, + 5537437, 19640113, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 55883261, 2320284, 57524584, 10149186, 100773065, 5808646, 119341477, 31824763, + 98343453, 39645030, + ]), + y_minus_x: FieldElement2625([ + 57475529, 116425, 26083934, 2897444, 60744427, 30866345, 609720, 15878753, + 60138459, 24519663, + ]), + xy2d: FieldElement2625([ + 39351007, 247743, 51914090, 24551880, 23288160, 23542496, 43239268, 6503645, + 20650474, 1804084, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 106627923, 49010854, 76081380, 42024039, 82749485, 37994278, 70230858, + 56779150, 94951478, 33352103, + ]), + y_minus_x: FieldElement2625([ + 51801891, 2839643, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, + 55733782, 12714368, + ]), + xy2d: FieldElement2625([ + 20807691, 26283607, 29286140, 11421711, 39232341, 19686201, 45881388, 1035545, + 47375635, 12796919, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 79185725, 52807577, 58323861, 21705509, 42096072, 49955115, 49517368, 20654993, + 70589528, 51926048, + ]), + y_minus_x: FieldElement2625([ + 34747315, 5457596, 28548107, 7833186, 7303070, 21600887, 42745799, 17632556, + 33734809, 2771024, + ]), + xy2d: FieldElement2625([ + 45719598, 421931, 26597266, 6860826, 22486084, 26817260, 49971378, 29344205, + 42556581, 15673396, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 46924223, 35892647, 19788684, 57487908, 63107597, 24813538, 46837679, 38287685, + 70836007, 20619983, + ]), + y_minus_x: FieldElement2625([ + 6120100, 814863, 55314462, 32931715, 6812204, 17806661, 2019593, 7975683, + 31123697, 22595451, + ]), + xy2d: FieldElement2625([ + 30069250, 22119100, 30434653, 2958439, 18399564, 32578143, 12296868, 9204260, + 50676426, 9648164, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 32705413, 32003455, 97814521, 41005496, 55303257, 43186244, 70414129, 38803035, + 108209395, 22176929, + ]), + y_minus_x: FieldElement2625([ + 17219846, 2375039, 35537917, 27978816, 47649184, 9219902, 294711, 15298639, + 2662509, 17257359, + ]), + xy2d: FieldElement2625([ + 65935918, 25995736, 62742093, 29266687, 45762450, 25120105, 32087528, 32331655, + 32247247, 19164571, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 14312609, 34775988, 17395389, 58408721, 62163121, 58424228, 106019982, + 23916613, 51081240, 20175586, + ]), + y_minus_x: FieldElement2625([ + 65680039, 23875441, 57873182, 6549686, 59725795, 33085767, 23046501, 9803137, + 17597934, 2346211, + ]), + xy2d: FieldElement2625([ + 18510781, 15337574, 26171504, 981392, 44867312, 7827555, 43617730, 22231079, + 3059832, 21771562, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77250443, 39637338, 84938156, 31606788, 76938955, 13613135, 41552228, 28009845, + 33606651, 37146527, + ]), + y_minus_x: FieldElement2625([ + 33114149, 17665080, 40583177, 20211034, 33076704, 8716171, 1151462, 1521897, + 66126199, 26716628, + ]), + xy2d: FieldElement2625([ + 34169699, 29298616, 23947180, 33230254, 34035889, 21248794, 50471177, 3891703, + 26353178, 693168, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97483084, 35150011, 117333688, 46741361, 71709207, 33961335, 76694157, + 33153763, 31375463, 47924397, + ]), + y_minus_x: FieldElement2625([ + 52738210, 25781902, 1510300, 6434173, 48324075, 27291703, 32732229, 20445593, + 17901440, 16011505, + ]), + xy2d: FieldElement2625([ + 18171223, 21619806, 54608461, 15197121, 56070717, 18324396, 47936623, 17508055, + 8764034, 12309598, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 73084753, 28311243, 47649501, 23872684, 55567586, 14015781, 110551971, + 34782749, 17544095, 22960650, + ]), + y_minus_x: FieldElement2625([ + 5811932, 31839139, 3442886, 31285122, 48741515, 25194890, 49064820, 18144304, + 61543482, 12348899, + ]), + xy2d: FieldElement2625([ + 35709185, 11407554, 25755363, 6891399, 63851926, 14872273, 42259511, 8141294, + 56476330, 32968952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 121542424, 34248456, 62032718, 46854775, 81124121, 19103037, 124519055, + 22225380, 30944592, 1130208, + ]), + y_minus_x: FieldElement2625([ + 8247747, 26843490, 40546482, 25845122, 52706924, 18905521, 4652151, 2488540, + 23550156, 33283200, + ]), + xy2d: FieldElement2625([ + 17294297, 29765994, 7026747, 15626851, 22990044, 113481, 2267737, 27646286, + 66700045, 33416712, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 83199930, 17300505, 85708115, 40895109, 69246500, 32332774, 63744702, 48105367, + 70369388, 26388160, + ]), + y_minus_x: FieldElement2625([ + 62198760, 20221544, 18550886, 10864893, 50649539, 26262835, 44079994, 20349526, + 54360141, 2701325, + ]), + xy2d: FieldElement2625([ + 58534169, 16099414, 4629974, 17213908, 46322650, 27548999, 57090500, 9276970, + 11329923, 1862132, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 14763057, 17650824, 103299457, 3689865, 70620756, 43867957, 45157775, 45773662, + 58070900, 32614131, + ]), + y_minus_x: FieldElement2625([ + 8894987, 30108338, 6150752, 3013931, 301220, 15693451, 35127648, 30644714, + 51670695, 11595569, + ]), + xy2d: FieldElement2625([ + 15214943, 3537601, 40870142, 19495559, 4418656, 18323671, 13947275, 10730794, + 53619402, 29190761, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64570539, 41237224, 99867876, 33817540, 104232996, 25598978, 111885603, + 23365795, 68085971, 34254425, + ]), + y_minus_x: FieldElement2625([ + 54642373, 4195083, 57897332, 550903, 51543527, 12917919, 19118110, 33114591, + 36574330, 19216518, + ]), + xy2d: FieldElement2625([ + 31788442, 19046775, 4799988, 7372237, 8808585, 18806489, 9408236, 23502657, + 12493931, 28145115, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41428258, 5260743, 47873055, 27269961, 63412921, 16566086, 94327144, 36161552, + 29375954, 6024730, + ]), + y_minus_x: FieldElement2625([ + 842132, 30759739, 62345482, 24831616, 26332017, 21148791, 11831879, 6985184, + 57168503, 2854095, + ]), + xy2d: FieldElement2625([ + 62261602, 25585100, 2516241, 27706719, 9695690, 26333246, 16512644, 960770, + 12121869, 16648078, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 51890193, 48221527, 53772634, 35568148, 97707150, 33090294, 35603941, 25672367, + 20237805, 36392843, + ]), + y_minus_x: FieldElement2625([ + 47820798, 4453151, 15298546, 17376044, 22115042, 17581828, 12544293, 20083975, + 1068880, 21054527, + ]), + xy2d: FieldElement2625([ + 57549981, 17035596, 33238497, 13506958, 30505848, 32439836, 58621956, 30924378, + 12521377, 4845654, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 106019188, 44298538, 64150483, 43754095, 74868174, 54020263, 70518210, + 32681031, 127735421, 20668560, + ]), + y_minus_x: FieldElement2625([ + 43547042, 6230155, 46726851, 10655313, 43068279, 21933259, 10477733, 32314216, + 63995636, 13974497, + ]), + xy2d: FieldElement2625([ + 12966261, 15550616, 35069916, 31939085, 21025979, 32924988, 5642324, 7188737, + 18895762, 12629579, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 14741860, 18607545, 89286071, 21833194, 68388604, 41613031, 11758139, 34343875, + 32195180, 37450109, + ]), + y_minus_x: FieldElement2625([ + 10758205, 15755439, 62598914, 9243697, 62229442, 6879878, 64904289, 29988312, + 58126794, 4429646, + ]), + xy2d: FieldElement2625([ + 64654951, 15725972, 46672522, 23143759, 61304955, 22514211, 59972993, 21911536, + 18047435, 18272689, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41935825, 55801698, 29759954, 45331216, 111955344, 51288407, 78101976, + 54258026, 49488161, 57700395, + ]), + y_minus_x: FieldElement2625([ + 21987233, 700364, 42603816, 14972007, 59334599, 27836036, 32155025, 2581431, + 37149879, 8773374, + ]), + xy2d: FieldElement2625([ + 41540495, 454462, 53896929, 16126714, 25240068, 8594567, 20656846, 12017935, + 59234475, 19634276, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 73137027, 39817509, 103205921, 55807152, 66289943, 36016203, 102376553, + 61640820, 65387074, 30777706, + ]), + y_minus_x: FieldElement2625([ + 54829870, 16624276, 987579, 27631834, 32908202, 1248608, 7719845, 29387734, + 28408819, 6816612, + ]), + xy2d: FieldElement2625([ + 56750770, 25316602, 19549650, 21385210, 22082622, 16147817, 20613181, 13982702, + 56769294, 5067942, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 36602859, 29732664, 79183544, 13582411, 47230892, 35998382, 47389577, 12746131, + 72440074, 57002919, + ]), + y_minus_x: FieldElement2625([ + 30528792, 3601899, 65151774, 4619784, 39747042, 18118043, 24180792, 20984038, + 27679907, 31905504, + ]), + xy2d: FieldElement2625([ + 9402385, 19597367, 32834042, 10838634, 40528714, 20317236, 26653273, 24868867, + 22611443, 20839026, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 89299435, 34672460, 22736440, 48684895, 103757035, 27563109, 86298488, + 62459921, 71963721, 40176570, + ]), + y_minus_x: FieldElement2625([ + 58798126, 30600981, 58846284, 30166382, 56707132, 33282502, 13424425, 29987205, + 26404408, 13001963, + ]), + xy2d: FieldElement2625([ + 35867026, 18138731, 64114613, 8939345, 11562230, 20713762, 41044498, 21932711, + 51703708, 11020692, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 68974887, 59159374, 59210213, 23253421, 12483314, 47031979, 70284499, 21130268, + 28761761, 34961166, + ]), + y_minus_x: FieldElement2625([ + 66660290, 31776765, 13018550, 3194501, 57528444, 22392694, 24760584, 29207344, + 25577410, 20175752, + ]), + xy2d: FieldElement2625([ + 42818486, 4759344, 66418211, 31701615, 2066746, 10693769, 37513074, 9884935, + 57739938, 4745409, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 57967561, 39604145, 47577802, 29213020, 102956929, 43498706, 51646855, + 55797011, 78040786, 21622500, + ]), + y_minus_x: FieldElement2625([ + 50547351, 14112679, 59096219, 4817317, 59068400, 22139825, 44255434, 10856640, + 46638094, 13434653, + ]), + xy2d: FieldElement2625([ + 22759470, 23480998, 50342599, 31683009, 13637441, 23386341, 1765143, 20900106, + 28445306, 28189722, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29875044, 46048045, 69904399, 63322533, 68819482, 48735613, 56913146, 24765756, + 9074233, 34721612, + ]), + y_minus_x: FieldElement2625([ + 40903181, 11014232, 57266213, 30918946, 40200743, 7532293, 48391976, 24018933, + 3843902, 9367684, + ]), + xy2d: FieldElement2625([ + 56139269, 27150720, 9591133, 9582310, 11349256, 108879, 16235123, 8601684, + 66969667, 4242894, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 89201818, 53917740, 65066069, 21585919, 99295616, 55591475, 60534521, 36025091, + 106800361, 16625499, + ]), + y_minus_x: FieldElement2625([ + 56051142, 3042015, 13770083, 24296510, 584235, 33009577, 59338006, 2602724, + 39757248, 14247412, + ]), + xy2d: FieldElement2625([ + 6314156, 23289540, 34336361, 15957556, 56951134, 168749, 58490057, 14290060, + 27108877, 32373552, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 58522248, 26383465, 80350645, 44514587, 34117848, 19759835, 100656839, + 22495542, 107069276, 34536304, + ]), + y_minus_x: FieldElement2625([ + 22833421, 9293594, 34459416, 19935764, 57971897, 14756818, 44180005, 19583651, + 56629059, 17356469, + ]), + xy2d: FieldElement2625([ + 59340277, 3326785, 38997067, 10783823, 19178761, 14905060, 22680049, 13906969, + 51175174, 3797898, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 88830182, 29341685, 54902740, 42864613, 63226624, 19901321, 90849087, 30845199, + 87600846, 59066711, + ]), + y_minus_x: FieldElement2625([ + 9209251, 18419377, 53852306, 27386633, 66377847, 15289672, 25947805, 15286587, + 30997318, 26851369, + ]), + xy2d: FieldElement2625([ + 7392013, 16618386, 23946583, 25514540, 53843699, 32020573, 52911418, 31232855, + 17649997, 33304352, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 57807757, 52915036, 97718388, 30504888, 41933794, 32270679, 51867297, 24028707, + 64875610, 41216577, + ]), + y_minus_x: FieldElement2625([ + 49550191, 1763593, 33994528, 15908609, 37067994, 21380136, 7335079, 25082233, + 63934189, 3440182, + ]), + xy2d: FieldElement2625([ + 47219164, 27577423, 42997570, 23865561, 10799742, 16982475, 40449, 29122597, + 4862399, 1133, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 34252636, 25680474, 61686474, 48415381, 50789832, 41510573, 74366924, 33866292, + 36513872, 26175010, + ]), + y_minus_x: FieldElement2625([ + 63335436, 31988495, 28985339, 7499440, 24445838, 9325937, 29727763, 16527196, + 18278453, 15405622, + ]), + xy2d: FieldElement2625([ + 62726958, 8508651, 47210498, 29880007, 61124410, 15149969, 53795266, 843522, + 45233802, 13626196, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69390312, 20067376, 56193445, 30944521, 68988221, 49718638, 56324981, 37508223, + 80449702, 15928662, + ]), + y_minus_x: FieldElement2625([ + 31727126, 26374577, 48671360, 25270779, 2875792, 17164102, 41838969, 26539605, + 43656557, 5964752, + ]), + xy2d: FieldElement2625([ + 4100401, 27594980, 49929526, 6017713, 48403027, 12227140, 40424029, 11344143, + 2538215, 25983677, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 57675240, 6123112, 78268667, 31397823, 97125143, 48520672, 46633880, 35039852, + 66479607, 17595569, + ]), + y_minus_x: FieldElement2625([ + 40304287, 4260918, 11851389, 9658551, 35091757, 16367491, 46903439, 20363143, + 11659921, 22439314, + ]), + xy2d: FieldElement2625([ + 26180377, 10015009, 36264640, 24973138, 5418196, 9480663, 2231568, 23384352, + 33100371, 32248261, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82229958, 28352560, 56718958, 48982252, 39598926, 17561924, 88779810, 38041106, + 61177053, 19088051, + ]), + y_minus_x: FieldElement2625([ + 16166467, 24070699, 56004733, 6023907, 35182066, 32189508, 2340059, 17299464, + 56373093, 23514607, + ]), + xy2d: FieldElement2625([ + 28042865, 29997343, 54982337, 12259705, 63391366, 26608532, 6766452, 24864833, + 18036435, 5803270, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 66291264, 40318343, 78912424, 35140016, 78067310, 30883266, 23855390, 4598332, + 60949433, 19436993, + ]), + y_minus_x: FieldElement2625([ + 36077558, 19298237, 17332028, 31170912, 31312681, 27587249, 696308, 50292, + 47013125, 11763583, + ]), + xy2d: FieldElement2625([ + 66514282, 31040148, 34874710, 12643979, 12650761, 14811489, 665117, 20940800, + 47335652, 22840869, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97573435, 55845991, 62981386, 20819953, 86944190, 60003250, 109821551, + 35630203, 50088706, 34546902, + ]), + y_minus_x: FieldElement2625([ + 18357166, 26559999, 7766381, 16342475, 37783946, 411173, 14578841, 8080033, + 55534529, 22952821, + ]), + xy2d: FieldElement2625([ + 19598397, 10334610, 12555054, 2555664, 18821899, 23214652, 21873262, 16014234, + 26224780, 16452269, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 36884920, 5145195, 73053412, 49940397, 71085598, 35564328, 122839923, 25936244, + 46575034, 37253081, + ]), + y_minus_x: FieldElement2625([ + 14187449, 3448569, 56472628, 22743496, 44444983, 30120835, 7268409, 22663988, + 27394300, 12015369, + ]), + xy2d: FieldElement2625([ + 19695742, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, 32241655, + 53849736, 30151970, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97968948, 12735207, 65220619, 28854697, 50133957, 35811371, 126051714, + 45852742, 58558339, 23160969, + ]), + y_minus_x: FieldElement2625([ + 61389038, 22309106, 65198214, 15569034, 26642876, 25966672, 61319509, 18435777, + 62132699, 12651792, + ]), + xy2d: FieldElement2625([ + 64260450, 9953420, 11531313, 28271553, 26895122, 20857343, 53990043, 17036529, + 9768697, 31021214, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 109498250, 35449081, 66821165, 28850346, 82457582, 25397901, 32767512, + 46319882, 72048958, 44232657, + ]), + y_minus_x: FieldElement2625([ + 18860224, 15980149, 48121624, 31991861, 40875851, 22482575, 59264981, 13944023, + 42736516, 16582018, + ]), + xy2d: FieldElement2625([ + 51604604, 4970267, 37215820, 4175592, 46115652, 31354675, 55404809, 15444559, + 56105103, 7989036, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 98599278, 39122492, 64696060, 35736814, 34772016, 38086117, 35030594, 39754637, + 47422750, 52308692, + ]), + y_minus_x: FieldElement2625([ + 49800177, 17674491, 35586086, 33551600, 34221481, 16375548, 8680158, 17182719, + 28550067, 26697300, + ]), + xy2d: FieldElement2625([ + 38981977, 27866340, 16837844, 31733974, 60258182, 12700015, 37068883, 4364037, + 1155602, 5988841, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 88999280, 20281524, 121593716, 12154347, 59276991, 48854927, 90257846, + 29083950, 91727270, 41837612, + ]), + y_minus_x: FieldElement2625([ + 33972757, 23041680, 9975415, 6841041, 35549071, 16356535, 3070187, 26528504, + 1466168, 10740210, + ]), + xy2d: FieldElement2625([ + 65599446, 18066246, 53605478, 22898515, 32799043, 909394, 53169961, 27774712, + 34944214, 18227391, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 71069668, 19286628, 39082773, 51190812, 47704004, 46701299, 82676190, 34505938, + 63848542, 32980496, + ]), + y_minus_x: FieldElement2625([ + 24740822, 5052253, 37014733, 8961360, 25877428, 6165135, 42740684, 14397371, + 59728495, 27410326, + ]), + xy2d: FieldElement2625([ + 38220480, 3510802, 39005586, 32395953, 55870735, 22922977, 51667400, 19101303, + 65483377, 27059617, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 67902144, 24323953, 75945165, 27318724, 39747955, 31184838, 100261706, + 62223612, 57202662, 32932579, + ]), + y_minus_x: FieldElement2625([ + 5666214, 525582, 20782575, 25516013, 42570364, 14657739, 16099374, 1468826, + 60937436, 18367850, + ]), + xy2d: FieldElement2625([ + 62249590, 29775088, 64191105, 26806412, 7778749, 11688288, 36704511, 23683193, + 65549940, 23690785, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 10896313, 25834728, 67933138, 34027032, 114757419, 36564017, 25248957, + 48337770, 36527387, 17796587, + ]), + y_minus_x: FieldElement2625([ + 10566929, 12612572, 35164652, 11118702, 54475488, 12362878, 21752402, 8822496, + 24003793, 14264025, + ]), + xy2d: FieldElement2625([ + 27713843, 26198459, 56100623, 9227529, 27050101, 2504721, 23886875, 20436907, + 13958494, 27821979, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 110736080, 38421656, 39861735, 37454952, 29838368, 25342141, 102328328, + 23512649, 74449384, 51698795, + ]), + y_minus_x: FieldElement2625([ + 4646495, 25543308, 44342840, 22021777, 23184552, 8566613, 31366726, 32173371, + 52042079, 23179239, + ]), + xy2d: FieldElement2625([ + 49838347, 12723031, 50115803, 14878793, 21619651, 27356856, 27584816, 3093888, + 58265170, 3849920, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 58043933, 35657603, 92670503, 51983125, 61869038, 43137389, 99585908, 24536476, + 72111157, 18004172, + ]), + y_minus_x: FieldElement2625([ + 55051311, 22376525, 21115584, 20189277, 8808711, 21523724, 16489529, 13378448, + 41263148, 12741425, + ]), + xy2d: FieldElement2625([ + 61162478, 10645102, 36197278, 15390283, 63821882, 26435754, 24306471, 15852464, + 28834118, 25908360, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 49773097, 24447374, 109686448, 42989383, 58636779, 32971069, 54018092, + 34010272, 87570721, 39045736, + ]), + y_minus_x: FieldElement2625([ + 13669229, 17458950, 54626889, 23351392, 52539093, 21661233, 42112877, 11293806, + 38520660, 24132599, + ]), + xy2d: FieldElement2625([ + 28497909, 6272777, 34085870, 14470569, 8906179, 32328802, 18504673, 19389266, + 29867744, 24758489, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50901822, 47071627, 39309233, 19856633, 24009063, 60734973, 60741262, 53933471, + 22853427, 29542421, + ]), + y_minus_x: FieldElement2625([ + 24191359, 16712145, 53177067, 15217830, 14542237, 1646131, 18603514, 22516545, + 12876622, 31441985, + ]), + xy2d: FieldElement2625([ + 17902668, 4518229, 66697162, 30725184, 26878216, 5258055, 54248111, 608396, + 16031844, 3723494, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 105584936, 12763726, 46662418, 41131935, 33001347, 54091119, 17558840, + 59235974, 23896952, 29240187, + ]), + y_minus_x: FieldElement2625([ + 47103464, 21542479, 31520463, 605201, 2543521, 5991821, 64163800, 7229063, + 57189218, 24727572, + ]), + xy2d: FieldElement2625([ + 28816026, 298879, 38943848, 17633493, 19000927, 31888542, 54428030, 30605106, + 49057085, 31471516, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 16000882, 33209536, 70601955, 55661665, 37604267, 20394642, 79686603, 49595699, + 47393623, 7847706, + ]), + y_minus_x: FieldElement2625([ + 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, 34252933, 27035413, + 57088296, 3852847, + ]), + xy2d: FieldElement2625([ + 55678375, 15697595, 45987307, 29133784, 5386313, 15063598, 16514493, 17622322, + 29330898, 18478208, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41609110, 29175637, 51885955, 26653220, 83724594, 35606215, 70412565, 33569921, + 106668931, 45868821, + ]), + y_minus_x: FieldElement2625([ + 15683501, 27551389, 18109119, 23573784, 15337967, 27556609, 50391428, 15921865, + 16103996, 29823217, + ]), + xy2d: FieldElement2625([ + 43939021, 22773182, 13588191, 31925625, 63310306, 32479502, 47835256, 5402698, + 37293151, 23713330, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 90299521, 35939014, 34394523, 37016585, 104314072, 32025298, 55842007, 8911516, + 109011869, 36294143, + ]), + y_minus_x: FieldElement2625([ + 21374101, 30000182, 33584214, 9874410, 15377179, 11831242, 33578960, 6134906, + 4931255, 11987849, + ]), + xy2d: FieldElement2625([ + 67101132, 30575573, 50885377, 7277596, 105524, 33232381, 35628324, 13861387, + 37032554, 10117929, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 37607694, 22809559, 40945095, 13051538, 41483300, 38644074, 127892224, + 40258509, 79998882, 15728939, + ]), + y_minus_x: FieldElement2625([ + 45136504, 21783052, 66157804, 29135591, 14704839, 2695116, 903376, 23126293, + 12885166, 8311031, + ]), + xy2d: FieldElement2625([ + 49592363, 5352193, 10384213, 19742774, 7506450, 13453191, 26423267, 4384730, + 1888765, 28119028, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 108400371, 64001550, 120723127, 30371924, 98005322, 19632702, 101966083, + 20846561, 47644429, 30214188, + ]), + y_minus_x: FieldElement2625([ + 43500868, 30888657, 66582772, 4651135, 5765089, 4618330, 6092245, 14845197, + 17151279, 23700316, + ]), + xy2d: FieldElement2625([ + 42278406, 20820711, 51942885, 10367249, 37577956, 33289075, 22825804, 26467153, + 50242379, 16176524, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 43525570, 40119392, 87172552, 37352659, 129477549, 40913655, 69115045, + 23191005, 38362610, 56911354, + ]), + y_minus_x: FieldElement2625([ + 56482264, 29068029, 53788301, 28429114, 3432135, 27161203, 23632036, 31613822, + 32808309, 1099883, + ]), + xy2d: FieldElement2625([ + 15030958, 5768825, 39657628, 30667132, 60681485, 18193060, 51830967, 26745081, + 2051440, 18328567, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 63746522, 26315059, 74626753, 43379423, 90664713, 33849800, 72257261, 52954675, + 44422508, 50188091, + ]), + y_minus_x: FieldElement2625([ + 4577067, 16802144, 13249840, 18250104, 19958762, 19017158, 18559669, 22794883, + 8402477, 23690159, + ]), + xy2d: FieldElement2625([ + 38702534, 32502850, 40318708, 32646733, 49896449, 22523642, 9453450, 18574360, + 17983009, 9967138, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41346351, 40079153, 93694351, 43523701, 24709297, 34774792, 65430873, 7806336, + 84616260, 37205991, + ]), + y_minus_x: FieldElement2625([ + 56688388, 29436320, 14584638, 15971087, 51340543, 8861009, 26556809, 27979875, + 48555541, 22197296, + ]), + xy2d: FieldElement2625([ + 2839082, 14284142, 4029895, 3472686, 14402957, 12689363, 40466743, 8459446, + 61503401, 25932490, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62269556, 30018987, 76853824, 2871047, 92222842, 36741449, 109106914, 32705364, + 84366947, 25576692, + ]), + y_minus_x: FieldElement2625([ + 18164541, 22959256, 49953981, 32012014, 19237077, 23809137, 23357532, 18337424, + 26908269, 12150756, + ]), + xy2d: FieldElement2625([ + 36843994, 25906566, 5112248, 26517760, 65609056, 26580174, 43167, 28016731, + 34806789, 16215818, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 60209940, 43378825, 54804084, 29153342, 102820586, 27277595, 99683352, + 46087336, 59605791, 24879084, + ]), + y_minus_x: FieldElement2625([ + 39765323, 17038963, 39957339, 22831480, 946345, 16291093, 254968, 7168080, + 21676107, 31611404, + ]), + xy2d: FieldElement2625([ + 21260942, 25129680, 50276977, 21633609, 43430902, 3968120, 63456915, 27338965, + 63552672, 25641356, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 16544735, 46804798, 50304435, 49100673, 62525860, 46311689, 64646555, 24874095, + 48201831, 23891632, + ]), + y_minus_x: FieldElement2625([ + 64693606, 17976703, 18312302, 4964443, 51836334, 20900867, 26820650, 16690659, + 25459437, 28989823, + ]), + xy2d: FieldElement2625([ + 41964155, 11425019, 28423002, 22533875, 60963942, 17728207, 9142794, 31162830, + 60676445, 31909614, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 44004193, 39807907, 16964146, 29785560, 109103755, 54812425, 39651637, + 50764205, 73444554, 40804420, + ]), + y_minus_x: FieldElement2625([ + 36775618, 13979674, 7503222, 21186118, 55152142, 28932738, 36836594, 2682241, + 25993170, 21075909, + ]), + xy2d: FieldElement2625([ + 4364628, 5930691, 32304656, 23509878, 59054082, 15091130, 22857016, 22955477, + 31820367, 15075278, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 98987979, 24635738, 84367624, 33645057, 126175891, 28636721, 91271651, + 23903545, 116247489, 46387475, + ]), + y_minus_x: FieldElement2625([ + 19073683, 14851414, 42705695, 21694263, 7625277, 11091125, 47489674, 2074448, + 57694925, 14905376, + ]), + xy2d: FieldElement2625([ + 24483648, 21618865, 64589997, 22007013, 65555733, 15355505, 41826784, 9253128, + 27628530, 25998952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 84706452, 41895034, 86464480, 34106618, 26198469, 30377849, 71702187, 24396849, + 120106852, 48851446, + ]), + y_minus_x: FieldElement2625([ + 510886, 14337390, 35323607, 16638631, 6328095, 2713355, 46891447, 21690211, + 8683220, 2921426, + ]), + xy2d: FieldElement2625([ + 18606791, 11874196, 27155355, 28272950, 43077121, 6265445, 41930624, 32275507, + 4674689, 13890525, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 13609605, 13069022, 106845367, 20498522, 91469449, 43147405, 82086020, + 43389536, 71498550, 33842827, + ]), + y_minus_x: FieldElement2625([ + 9922506, 33035038, 13613106, 5883594, 48350519, 33120168, 54804801, 8317627, + 23388070, 16052080, + ]), + xy2d: FieldElement2625([ + 12719997, 11937594, 35138804, 28525742, 26900119, 8561328, 46953177, 21921452, + 52354592, 22741539, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 83070703, 47704840, 93825794, 32888599, 111423399, 47157999, 78938436, + 41022275, 38286735, 34483706, + ]), + y_minus_x: FieldElement2625([ + 11038231, 21972036, 39798381, 26237869, 56610336, 17246600, 43629330, 24182562, + 45715720, 2465073, + ]), + xy2d: FieldElement2625([ + 20017144, 29231206, 27915241, 1529148, 12396362, 15675764, 13817261, 23896366, + 2463390, 28932292, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50749967, 20890520, 122152544, 38550884, 65852441, 34628003, 76692421, + 12851106, 71112760, 46228148, + ]), + y_minus_x: FieldElement2625([ + 65377275, 18398561, 63845933, 16143081, 19294135, 13385325, 14741514, 24450706, + 7903885, 2348101, + ]), + xy2d: FieldElement2625([ + 24536016, 17039225, 12715591, 29692277, 1511292, 10047386, 63266518, 26425272, + 38731325, 10048126, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54486638, 27349611, 97827688, 2591311, 56491836, 12192839, 85982162, 59811773, + 34811106, 15221631, + ]), + y_minus_x: FieldElement2625([ + 40630742, 22450567, 11546243, 31701949, 9180879, 7656409, 45764914, 2095754, + 29769758, 6593415, + ]), + xy2d: FieldElement2625([ + 35114656, 30646970, 4176911, 3264766, 12538965, 32686321, 26312344, 27435754, + 30958053, 8292160, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 98538667, 53149747, 96282394, 15632447, 12174511, 64348770, 99917693, 37531617, + 93251999, 30405555, + ]), + y_minus_x: FieldElement2625([ + 22648882, 1402143, 44308880, 13746058, 7936347, 365344, 58440231, 31879998, + 63350620, 31249806, + ]), + xy2d: FieldElement2625([ + 51616947, 8012312, 64594134, 20851969, 43143017, 23300402, 65496150, 32018862, + 50444388, 8194477, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 27338047, 26047012, 59694639, 10140404, 48082437, 26964542, 94386054, 42409807, + 95681149, 36559595, + ]), + y_minus_x: FieldElement2625([ + 26287105, 4821776, 25476601, 29408529, 63344350, 17765447, 49100281, 1182478, + 41014043, 20474836, + ]), + xy2d: FieldElement2625([ + 59937691, 3178079, 23970071, 6201893, 49913287, 29065239, 45232588, 19571804, + 32208682, 32356184, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50451143, 36372074, 56822501, 14811297, 73133531, 46903936, 39793359, 56611021, + 39436277, 22014573, + ]), + y_minus_x: FieldElement2625([ + 15941010, 24148500, 45741813, 8062054, 31876073, 33315803, 51830470, 32110002, + 15397330, 29424239, + ]), + xy2d: FieldElement2625([ + 8934485, 20068965, 43822466, 20131190, 34662773, 14047985, 31170398, 32113411, + 39603297, 15087183, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 115860466, 31397939, 24524912, 16876564, 82629290, 27193655, 118715321, + 11461894, 83897392, 27685489, + ]), + y_minus_x: FieldElement2625([ + 65161459, 16013772, 21750665, 3714552, 49707082, 17498998, 63338576, 23231111, + 31322513, 21938797, + ]), + xy2d: FieldElement2625([ + 21426636, 27904214, 53460576, 28206894, 38296674, 28633461, 48833472, 18933017, + 13040861, 21441484, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 78402740, 46032517, 107081326, 48638180, 104910306, 14748870, 14555558, + 20137329, 68722574, 38451366, + ]), + y_minus_x: FieldElement2625([ + 41213962, 15323293, 58619073, 25496531, 25967125, 20128972, 2825959, 28657387, + 43137087, 22287016, + ]), + xy2d: FieldElement2625([ + 51184079, 28324551, 49665331, 6410663, 3622847, 10243618, 20615400, 12405433, + 43355834, 25118015, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 127126414, 46110638, 114026375, 9025185, 50036385, 4333800, 71487300, 35986461, + 23097948, 32988414, + ]), + y_minus_x: FieldElement2625([ + 4565804, 17528778, 20084411, 25711615, 1724998, 189254, 24767264, 10103221, + 48596551, 2424777, + ]), + xy2d: FieldElement2625([ + 366633, 21577626, 8173089, 26664313, 30788633, 5745705, 59940186, 1344108, + 63466311, 12412658, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 110215918, 41244716, 82038279, 33386174, 102006892, 53695876, 91271559, + 51782359, 63967361, 44733816, + ]), + y_minus_x: FieldElement2625([ + 18289503, 18829478, 8056944, 16430056, 45379140, 7842513, 61107423, 32067534, + 48424218, 22110928, + ]), + xy2d: FieldElement2625([ + 476239, 6601091, 60956074, 23831056, 17503544, 28690532, 27672958, 13403813, + 11052904, 5219329, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 87787372, 25178693, 34436965, 42403554, 129207969, 48129182, 98295834, + 29580701, 9014761, 58529808, + ]), + y_minus_x: FieldElement2625([ + 53464795, 23204192, 51146355, 5075807, 65594203, 22019831, 34006363, 9160279, + 8473550, 30297594, + ]), + xy2d: FieldElement2625([ + 24900749, 14435722, 17209120, 18261891, 44516588, 9878982, 59419555, 17218610, + 42540382, 11788947, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 63990690, 22159237, 53306774, 48351872, 76761311, 26708527, 47071426, 43965164, + 42540393, 32095740, + ]), + y_minus_x: FieldElement2625([ + 51449703, 16736705, 44641714, 10215877, 58011687, 7563910, 11871841, 21049238, + 48595538, 8464117, + ]), + xy2d: FieldElement2625([ + 43708233, 8348506, 52522913, 32692717, 63158658, 27181012, 14325288, 8628612, + 33313881, 25183915, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 46921853, 28586496, 89476219, 38825978, 66011746, 28765593, 109412060, + 23317576, 58168128, 61290594, + ]), + y_minus_x: FieldElement2625([ + 60160060, 31759219, 34483180, 17533252, 32635413, 26180187, 15989196, 20716244, + 28358191, 29300528, + ]), + xy2d: FieldElement2625([ + 43547083, 30755372, 34757181, 31892468, 57961144, 10429266, 50471180, 4072015, + 61757200, 5596588, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 105981130, 30164382, 79421759, 39767609, 3117141, 49632997, 29266238, 36111653, + 68877164, 15373192, + ]), + y_minus_x: FieldElement2625([ + 59865506, 30307471, 62515396, 26001078, 66980936, 32642186, 66017961, 29049440, + 42448372, 3442909, + ]), + xy2d: FieldElement2625([ + 36898293, 5124042, 14181784, 8197961, 18964734, 21615339, 22597930, 7176455, + 48523386, 13365929, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 59231455, 32054473, 75433536, 38244510, 73370723, 34444877, 24538106, 24984246, + 57419264, 30522764, + ]), + y_minus_x: FieldElement2625([ + 25008885, 22782833, 62803832, 23916421, 16265035, 15721635, 683793, 21730648, + 15723478, 18390951, + ]), + xy2d: FieldElement2625([ + 57448220, 12374378, 40101865, 26528283, 59384749, 21239917, 11879681, 5400171, + 519526, 32318556, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 22258378, 50776631, 59239045, 14613015, 44588609, 30603508, 46754982, 40870398, + 16648396, 41160072, + ]), + y_minus_x: FieldElement2625([ + 59027556, 25089834, 58885552, 9719709, 19259459, 18206220, 23994941, 28272877, + 57640015, 4763277, + ]), + xy2d: FieldElement2625([ + 45409620, 9220968, 51378240, 1084136, 41632757, 30702041, 31088446, 25789909, + 55752334, 728111, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 26047201, 55357393, 127317403, 50587064, 91200930, 9158118, 62835319, 20998873, + 104852291, 28056158, + ]), + y_minus_x: FieldElement2625([ + 17510331, 33231575, 5854288, 8403524, 17133918, 30441820, 38997856, 12327944, + 10750447, 10014012, + ]), + xy2d: FieldElement2625([ + 56796096, 3936951, 9156313, 24656749, 16498691, 32559785, 39627812, 32887699, + 3424690, 7540221, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97431206, 26590321, 78469868, 29411114, 74542167, 4989747, 127146306, 50791643, + 57864597, 48812477, + ]), + y_minus_x: FieldElement2625([ + 13054543, 30774935, 19155473, 469045, 54626067, 4566041, 5631406, 2711395, + 1062915, 28418087, + ]), + xy2d: FieldElement2625([ + 47868616, 22299832, 37599834, 26054466, 61273100, 13005410, 61042375, 12194496, + 32960380, 1459310, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 86960860, 40582355, 90778216, 43574797, 75695366, 26896524, 67503060, 27452546, + 85746866, 55933926, + ]), + y_minus_x: FieldElement2625([ + 31395515, 15098109, 26581030, 8030562, 50580950, 28547297, 9012485, 25970078, + 60465776, 28111795, + ]), + xy2d: FieldElement2625([ + 57916680, 31207054, 65111764, 4529533, 25766844, 607986, 67095642, 9677542, + 34813975, 27098423, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64664330, 33404494, 96457765, 8186664, 68982624, 12489862, 103283149, 25714738, + 59256019, 58970434, + ]), + y_minus_x: FieldElement2625([ + 51872508, 18120922, 7766469, 746860, 26346930, 23332670, 39775412, 10754587, + 57677388, 5203575, + ]), + xy2d: FieldElement2625([ + 31834314, 14135496, 66338857, 5159117, 20917671, 16786336, 59640890, 26216907, + 31809242, 7347066, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 57502122, 21680191, 87523322, 46588417, 80825387, 21862550, 86906833, 21343176, + 82301739, 31466941, + ]), + y_minus_x: FieldElement2625([ + 54445282, 31372712, 1168161, 29749623, 26747876, 19416341, 10609329, 12694420, + 33473243, 20172328, + ]), + xy2d: FieldElement2625([ + 33184999, 11180355, 15832085, 22169002, 65475192, 225883, 15089336, 22530529, + 60973201, 14480052, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 98417562, 27934433, 98139703, 31657332, 82783410, 26971548, 72605071, 13685226, + 27595050, 42291707, + ]), + y_minus_x: FieldElement2625([ + 46790012, 18404192, 10933842, 17376410, 8335351, 26008410, 36100512, 20943827, + 26498113, 66511, + ]), + xy2d: FieldElement2625([ + 22644435, 24792703, 50437087, 4884561, 64003250, 19995065, 30540765, 29267685, + 53781076, 26039336, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 106199862, 9834843, 85726071, 30873119, 63706907, 53801357, 75314402, 13585436, + 117090263, 48669869, + ]), + y_minus_x: FieldElement2625([ + 23711543, 32881517, 31206560, 25191721, 6164646, 23844445, 33572981, 32128335, + 8236920, 16492939, + ]), + xy2d: FieldElement2625([ + 43198286, 20038905, 40809380, 29050590, 25005589, 25867162, 19574901, 10071562, + 6708380, 27332008, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69210217, 28624377, 86811594, 35922006, 118790560, 34602105, 72409880, + 42883131, 29955600, 55430554, + ]), + y_minus_x: FieldElement2625([ + 3096359, 9271816, 45488000, 18032587, 52260867, 25961494, 41216721, 20918836, + 57191288, 6216607, + ]), + xy2d: FieldElement2625([ + 34493015, 338662, 41913253, 2510421, 37895298, 19734218, 24822829, 27407865, + 40341383, 7525078, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 44042196, 53123240, 83242349, 25658253, 130828162, 34333218, 66198527, + 30771936, 47722230, 45548532, + ]), + y_minus_x: FieldElement2625([ + 21691500, 19929806, 66467532, 19187410, 3285880, 30070836, 42044197, 9718257, + 59631427, 13381417, + ]), + xy2d: FieldElement2625([ + 18445390, 29352196, 14979845, 11622458, 65381754, 29971451, 23111647, 27179185, + 28535281, 15779576, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 30098034, 36644094, 124983340, 16662133, 45801924, 44862842, 53040409, + 12021729, 77064149, 17251075, + ]), + y_minus_x: FieldElement2625([ + 9734894, 18977602, 59635230, 24415696, 2060391, 11313496, 48682835, 9924398, + 20194861, 13380996, + ]), + xy2d: FieldElement2625([ + 40730762, 25589224, 44941042, 15789296, 49053522, 27385639, 65123949, 15707770, + 26342023, 10146099, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41091971, 33334488, 88448054, 33513043, 86854119, 30675731, 37471583, 35781471, + 21612325, 33008704, + ]), + y_minus_x: FieldElement2625([ + 54031477, 1184227, 23562814, 27583990, 46757619, 27205717, 25764460, 12243797, + 46252298, 11649657, + ]), + xy2d: FieldElement2625([ + 57077370, 11262625, 27384172, 2271902, 26947504, 17556661, 39943, 6114064, + 33514190, 2333242, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 112784121, 54687041, 75228644, 40774344, 45278341, 58092729, 60429112, + 54438225, 91459440, 20104430, + ]), + y_minus_x: FieldElement2625([ + 62992557, 22282898, 43222677, 4843614, 37020525, 690622, 35572776, 23147595, + 8317859, 12352766, + ]), + xy2d: FieldElement2625([ + 18200138, 19078521, 34021104, 30857812, 43406342, 24451920, 43556767, 31266881, + 20712162, 6719373, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 26656189, 39629685, 59250307, 35440503, 105873684, 37816756, 78226393, + 29791221, 26224234, 30256974, + ]), + y_minus_x: FieldElement2625([ + 49939907, 18700334, 63713187, 17184554, 47154818, 14050419, 21728352, 9493610, + 18620611, 17125804, + ]), + xy2d: FieldElement2625([ + 53785524, 13325348, 11432106, 5964811, 18609221, 6062965, 61839393, 23828875, + 36407290, 17074774, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 43248307, 55875704, 94070219, 35195292, 34695751, 16816491, 79357372, 28313792, + 80844205, 35488493, + ]), + y_minus_x: FieldElement2625([ + 25089769, 6742589, 17081145, 20148166, 21909292, 17486451, 51972569, 29789085, + 45830866, 5473615, + ]), + xy2d: FieldElement2625([ + 31883658, 25593331, 1083431, 21982029, 22828470, 13290673, 59983779, 12469655, + 29111212, 28103418, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 91353792, 52058456, 107954750, 36345970, 52111264, 50221109, 91476329, + 39943270, 56813276, 34006814, + ]), + y_minus_x: FieldElement2625([ + 41468082, 30136590, 5217915, 16224624, 19987036, 29472163, 42872612, 27639183, + 15766061, 8407814, + ]), + xy2d: FieldElement2625([ + 46701865, 13990230, 15495425, 16395525, 5377168, 15166495, 58191841, 29165478, + 59040954, 2276717, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 30157899, 46478498, 116505677, 42800183, 87003891, 36922573, 43281276, + 38650650, 89849239, 26251014, + ]), + y_minus_x: FieldElement2625([ + 2041139, 19298082, 7783686, 13876377, 41161879, 20201972, 24051123, 13742383, + 51471265, 13295221, + ]), + xy2d: FieldElement2625([ + 33338218, 25048699, 12532112, 7977527, 9106186, 31839181, 49388668, 28941459, + 62657506, 18884987, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 47063564, 39008528, 52762315, 40001577, 28862070, 35438083, 64639597, 29412551, + 74879432, 43175028, + ]), + y_minus_x: FieldElement2625([ + 23208049, 7979712, 33071466, 8149229, 1758231, 22719437, 30945527, 31860109, + 33606523, 18786461, + ]), + xy2d: FieldElement2625([ + 1439939, 17283952, 66028874, 32760649, 4625401, 10647766, 62065063, 1220117, + 30494170, 22113633, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62071265, 20526136, 64138304, 30492664, 82749837, 26852765, 40369837, 34480481, + 65424524, 20220784, + ]), + y_minus_x: FieldElement2625([ + 13908495, 30005160, 30919927, 27280607, 45587000, 7989038, 9021034, 9078865, + 3353509, 4033511, + ]), + xy2d: FieldElement2625([ + 37445433, 18440821, 32259990, 33209950, 24295848, 20642309, 23161162, 8839127, + 27485041, 7356032, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76769853, 34259874, 79088928, 28184277, 65480320, 14661172, 60762722, 36179446, + 95539899, 50337029, + ]), + y_minus_x: FieldElement2625([ + 43269631, 25243016, 41163352, 7480957, 49427195, 25200248, 44562891, 14150564, + 15970762, 4099461, + ]), + xy2d: FieldElement2625([ + 29262576, 16756590, 26350592, 24760869, 8529670, 22346382, 13617292, 23617289, + 11465738, 8317062, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41615764, 26591503, 99609063, 24135380, 44070139, 31252209, 82007500, 37402886, + 88078197, 28396915, + ]), + y_minus_x: FieldElement2625([ + 46724414, 19206718, 48772458, 13884721, 34069410, 2842113, 45498038, 29904543, + 11177094, 14989547, + ]), + xy2d: FieldElement2625([ + 42612143, 21838415, 16959895, 2278463, 12066309, 10137771, 13515641, 2581286, + 38621356, 9930239, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 49357223, 31456605, 83653163, 54099563, 118302919, 18605349, 18345766, + 53705111, 83400343, 28240393, + ]), + y_minus_x: FieldElement2625([ + 33879670, 2553287, 32678213, 9875984, 8534129, 6889387, 57432090, 6957616, + 4368891, 9788741, + ]), + xy2d: FieldElement2625([ + 16660737, 7281060, 56278106, 12911819, 20108584, 25452756, 45386327, 24941283, + 16250551, 22443329, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 47343357, 35944957, 117666696, 14161978, 69014150, 39969338, 71798447, + 10604806, 104027325, 4782745, + ]), + y_minus_x: FieldElement2625([ + 65754325, 14736940, 59741422, 20261545, 7710541, 19398842, 57127292, 4383044, + 22546403, 437323, + ]), + xy2d: FieldElement2625([ + 31665558, 21373968, 50922033, 1491338, 48740239, 3294681, 27343084, 2786261, + 36475274, 19457415, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 52641566, 32870716, 33734756, 41002983, 19294359, 14334329, 47418233, 35909750, + 47824192, 27440058, + ]), + y_minus_x: FieldElement2625([ + 15121312, 17758270, 6377019, 27523071, 56310752, 20596586, 18952176, 15496498, + 37728731, 11754227, + ]), + xy2d: FieldElement2625([ + 64471568, 20071356, 8488726, 19250536, 12728760, 31931939, 7141595, 11724556, + 22761615, 23420291, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 16918416, 11729663, 49025285, 36577418, 103201995, 53769203, 38367677, + 21327038, 32851221, 11717399, + ]), + y_minus_x: FieldElement2625([ + 11166615, 7338049, 60386341, 4531519, 37640192, 26252376, 31474878, 3483633, + 65915689, 29523600, + ]), + xy2d: FieldElement2625([ + 66923210, 9921304, 31456609, 20017994, 55095045, 13348922, 33142652, 6546660, + 47123585, 29606055, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 101757113, 44821142, 55911756, 25655328, 31703693, 37410335, 58571732, + 20721383, 36336829, 18068118, + ]), + y_minus_x: FieldElement2625([ + 49102387, 12709067, 3991746, 27075244, 45617340, 23004006, 35973516, 17504552, + 10928916, 3011958, + ]), + xy2d: FieldElement2625([ + 60151107, 17960094, 31696058, 334240, 29576716, 14796075, 36277808, 20749251, + 18008030, 10258577, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 44660220, 49210000, 74127342, 29144428, 36794597, 32352840, 65255398, 34921551, + 92236737, 6671742, + ]), + y_minus_x: FieldElement2625([ + 29701166, 19180498, 56230743, 9279287, 67091296, 13127209, 21382910, 11042292, + 25838796, 4642684, + ]), + xy2d: FieldElement2625([ + 46678630, 14955536, 42982517, 8124618, 61739576, 27563961, 30468146, 19653792, + 18423288, 4177476, + ]), + }, + ]), + ]); + +/// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = + NafLookupTable8([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 93076338, 52752828, 29566454, 37215328, 54414518, 37569218, 94653489, 21800160, + 61029707, 35602036, + ]), + y_minus_x: FieldElement2625([ + 54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692, 5043384, + 19500929, 18085054, + ]), + xy2d: FieldElement2625([ + 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918, 11864899, + 42594502, 29115885, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82745136, 23865874, 24204772, 25642034, 67725840, 16869169, 94896463, 52336674, + 28944398, 32004408, + ]), + y_minus_x: FieldElement2625([ + 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576, 21778470, + 7689661, 11199574, + ]), + xy2d: FieldElement2625([ + 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774, 10017326, + 49359771, 23634074, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77970208, 11473153, 27284546, 35535607, 37044514, 46132292, 99976748, 48069538, + 118779423, 44373810, + ]), + y_minus_x: FieldElement2625([ + 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196, 12483687, + 54440373, 5581305, + ]), + xy2d: FieldElement2625([ + 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349, 13850243, + 43430843, 17738489, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 72262591, 43463716, 68832610, 30776557, 97632468, 39071304, 86589715, 38784565, + 43156424, 18378665, + ]), + y_minus_x: FieldElement2625([ + 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025, 16520125, + 30598449, 7715701, + ]), + xy2d: FieldElement2625([ + 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204, 1370707, + 29794553, 32145132, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 44589852, 26862249, 14201701, 24808930, 43598457, 42399157, 85583074, 32192981, + 54046167, 47376308, + ]), + y_minus_x: FieldElement2625([ + 60653668, 25714560, 3374701, 28813570, 40010246, 22982724, 31655027, 26342105, + 18853321, 19333481, + ]), + xy2d: FieldElement2625([ + 4566811, 20590564, 38133974, 21313742, 59506191, 30723862, 58594505, 23123294, + 2207752, 30344648, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41954014, 62923042, 96790006, 41423232, 60254202, 24130566, 121780363, 32891430, + 103106264, 17421994, + ]), + y_minus_x: FieldElement2625([ + 25576264, 30851218, 7349803, 21739588, 16472781, 9300885, 3844789, 15725684, + 171356, 6466918, + ]), + xy2d: FieldElement2625([ + 23103977, 13316479, 9739013, 17404951, 817874, 18515490, 8965338, 19466374, + 36393951, 16193876, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 100695917, 36735143, 64714733, 47558118, 50205389, 17283591, 84347261, 38283886, + 49034350, 9256799, + ]), + y_minus_x: FieldElement2625([ + 41926547, 29380300, 32336397, 5036987, 45872047, 11360616, 22616405, 9761698, + 47281666, 630304, + ]), + xy2d: FieldElement2625([ + 53388152, 2639452, 42871404, 26147950, 9494426, 27780403, 60554312, 17593437, + 64659607, 19263131, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 63957664, 28508356, 76391577, 40420576, 102310665, 32691407, 48168288, 15033783, + 92213982, 25659555, + ]), + y_minus_x: FieldElement2625([ + 42782475, 15950225, 35307649, 18961608, 55446126, 28463506, 1573891, 30928545, + 2198789, 17749813, + ]), + xy2d: FieldElement2625([ + 64009494, 10324966, 64867251, 7453182, 61661885, 30818928, 53296841, 17317989, + 34647629, 21263748, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 17735022, 27114469, 76149336, 40765111, 43325570, 26153544, 26948151, 45905235, + 38656900, 62179684, + ]), + y_minus_x: FieldElement2625([ + 2154119, 14782993, 28737794, 11906199, 36205504, 26488101, 19338132, 16910143, + 50209922, 29794297, + ]), + xy2d: FieldElement2625([ + 29935700, 6336041, 20999566, 30405369, 13628497, 24612108, 61639745, 22359641, + 56973806, 18684690, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29792811, 31379227, 113441390, 20675662, 58452680, 54138549, 42892249, 32958636, + 31674345, 24275271, + ]), + y_minus_x: FieldElement2625([ + 7606599, 22131225, 17376912, 15235046, 32822971, 7512882, 30227203, 14344178, + 9952094, 8804749, + ]), + xy2d: FieldElement2625([ + 32575079, 3961822, 36404898, 17773250, 67073898, 1319543, 30641032, 7823672, + 63309858, 18878784, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77823924, 52933642, 26572931, 18690221, 109143683, 23989794, 79129572, 53326100, + 38888709, 55889506, + ]), + y_minus_x: FieldElement2625([ + 37146997, 554126, 63326061, 20925660, 49205290, 8620615, 53375504, 25938867, + 8752612, 31225894, + ]), + xy2d: FieldElement2625([ + 4529887, 12416158, 60388162, 30157900, 15427957, 27628808, 61150927, 12724463, + 23658330, 23690055, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 102043267, 54823614, 45810225, 19657305, 54297192, 7413280, 66851983, 39718512, + 25005048, 18002658, + ]), + y_minus_x: FieldElement2625([ + 5403481, 24654166, 61855580, 13522652, 14989680, 1879017, 43913069, 25724172, + 20315901, 421248, + ]), + xy2d: FieldElement2625([ + 34818947, 1705239, 25347020, 7938434, 51632025, 1720023, 54809726, 32655885, + 64907986, 5517607, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 88543525, 16557377, 80359887, 30047148, 91602876, 27723948, 62710290, 52707861, + 7715736, 61648232, + ]), + y_minus_x: FieldElement2625([ + 14461032, 6393639, 22681353, 14533514, 52493587, 3544717, 57780998, 24657863, + 59891807, 31628125, + ]), + xy2d: FieldElement2625([ + 60864886, 31199953, 18524951, 11247802, 43517645, 21165456, 26204394, 27268421, + 63221077, 29979135, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97491378, 10077555, 94805128, 42472719, 30231379, 17961119, 76201413, 41182329, + 41405214, 31798052, + ]), + y_minus_x: FieldElement2625([ + 13670592, 720327, 7131696, 19360499, 66651570, 16947532, 3061924, 22871019, + 39814495, 20141336, + ]), + xy2d: FieldElement2625([ + 44847187, 28379568, 38472030, 23697331, 49441718, 3215393, 1669253, 30451034, + 62323912, 29368533, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 74923758, 35244493, 27222384, 30715870, 48444195, 28125622, 116052444, 32330148, + 92609232, 35372537, + ]), + y_minus_x: FieldElement2625([ + 39340596, 15199968, 52787715, 18781603, 18787729, 5464578, 11652644, 8722118, + 57056621, 5153960, + ]), + xy2d: FieldElement2625([ + 5733861, 14534448, 59480402, 15892910, 30737296, 188529, 491756, 17646733, + 33071791, 15771063, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 85239571, 21331573, 119690709, 30172286, 44350959, 55826224, 68258766, 16209406, + 20222151, 32139086, + ]), + y_minus_x: FieldElement2625([ + 52372801, 13847470, 52690845, 3802477, 48387139, 10595589, 13745896, 3112846, + 50361463, 2761905, + ]), + xy2d: FieldElement2625([ + 45982696, 12273933, 15897066, 704320, 31367969, 3120352, 11710867, 16405685, + 19410991, 10591627, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82008850, 34439758, 89319886, 49124188, 34309215, 29866047, 80308709, 27738519, + 71739865, 46909287, + ]), + y_minus_x: FieldElement2625([ + 36631997, 23300851, 59535242, 27474493, 59924914, 29067704, 17551261, 13583017, + 37580567, 31071178, + ]), + xy2d: FieldElement2625([ + 22641770, 21277083, 10843473, 1582748, 37504588, 634914, 15612385, 18139122, + 59415250, 22563863, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76721854, 52814714, 41722368, 35285867, 53022548, 38255176, 93163883, 27627617, + 87963092, 33729456, + ]), + y_minus_x: FieldElement2625([ + 61915349, 11733561, 59403492, 31381562, 29521830, 16845409, 54973419, 26057054, + 49464700, 796779, + ]), + xy2d: FieldElement2625([ + 3855018, 8248512, 12652406, 88331, 2948262, 971326, 15614761, 9441028, 29507685, + 8583792, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76968870, 14808584, 76708906, 57649718, 23400175, 24077237, 63783137, 37471119, + 56750251, 30681804, + ]), + y_minus_x: FieldElement2625([ + 33709664, 3740344, 52888604, 25059045, 46197996, 22678812, 45207164, 6431243, + 21300862, 27646257, + ]), + xy2d: FieldElement2625([ + 49811511, 9216232, 25043921, 18738174, 29145960, 3024227, 65580502, 530149, + 66809973, 22275500, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 23499366, 24936714, 38355445, 35908587, 82540167, 39280880, 46809413, 41143783, + 72530804, 49676198, + ]), + y_minus_x: FieldElement2625([ + 45162189, 23851397, 9380591, 15192763, 36034862, 15525765, 5277811, 25040629, + 33286237, 31693326, + ]), + xy2d: FieldElement2625([ + 62424427, 13336013, 49368582, 1581264, 30884213, 15048226, 66823504, 4736577, + 53805192, 29608355, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 25190215, 26304748, 58928336, 42665707, 64280342, 38580230, 61299598, 20659504, + 30387592, 32519377, + ]), + y_minus_x: FieldElement2625([ + 14480213, 17057820, 2286692, 32980967, 14693157, 22197912, 49247898, 9909859, + 236428, 16857435, + ]), + xy2d: FieldElement2625([ + 7877514, 29872867, 45886243, 25902853, 41998762, 6241604, 35694938, 15657879, + 56797932, 8609105, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54245189, 32562161, 57887697, 19509733, 45323534, 37472546, 27606727, 59528498, + 74398957, 44973176, + ]), + y_minus_x: FieldElement2625([ + 28964163, 20950093, 44929966, 26145892, 34786807, 18058153, 18187179, 27016486, + 42438836, 14869174, + ]), + xy2d: FieldElement2625([ + 55703901, 1222455, 64329400, 24533246, 11330890, 9135834, 3589529, 19555234, + 53275553, 1207212, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 33323313, 35603165, 79328585, 6017848, 71286345, 23804207, 86644124, 44008367, + 55775078, 31816581, + ]), + y_minus_x: FieldElement2625([ + 64814718, 27217688, 29891310, 4504619, 8548709, 21986323, 62140656, 12555980, + 34377058, 21436823, + ]), + xy2d: FieldElement2625([ + 49069441, 9880212, 33350825, 24576421, 24446077, 15616561, 19302117, 9370836, + 55172180, 28526191, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 95404934, 26757208, 123864063, 4572839, 69249194, 43584425, 53559055, 41742046, + 41167331, 24643278, + ]), + y_minus_x: FieldElement2625([ + 35101859, 30958612, 66105296, 3168612, 22836264, 10055966, 22893634, 13045780, + 28576558, 30704591, + ]), + xy2d: FieldElement2625([ + 59987873, 21166324, 43296694, 15387892, 39447987, 19996270, 5059183, 19972934, + 30207804, 29631666, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 67444156, 16132892, 88330413, 37924284, 68147855, 57949418, 91481571, 24889160, + 62329722, 50712214, + ]), + y_minus_x: FieldElement2625([ + 56922508, 1347520, 23300731, 27393371, 42651667, 8512932, 27610931, 24436993, + 3998295, 3835244, + ]), + xy2d: FieldElement2625([ + 16327050, 22776956, 14746360, 22599650, 23700920, 11727222, 25900154, 21823218, + 34907363, 25105813, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 59807886, 12089757, 115624210, 41476837, 67589715, 26361580, 71355762, 44268661, + 67753061, 13128476, + ]), + y_minus_x: FieldElement2625([ + 7174885, 26592113, 59892333, 6465478, 4145835, 17673606, 38764952, 22293290, + 1360980, 25805937, + ]), + xy2d: FieldElement2625([ + 40179568, 6331649, 42386021, 20205884, 15635073, 6103612, 56391180, 6789942, + 7597240, 24095312, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54776568, 36935932, 18757261, 41429535, 67215081, 34700142, 86560976, 61204154, + 26496794, 19612129, + ]), + y_minus_x: FieldElement2625([ + 46701540, 24101444, 49515651, 25946994, 45338156, 9941093, 55509371, 31298943, + 1347425, 15381335, + ]), + xy2d: FieldElement2625([ + 53576449, 26135856, 17092785, 3684747, 57829121, 27109516, 2987881, 10987137, + 52269096, 15465522, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 80033010, 26264316, 72380996, 10039544, 94605936, 30615493, 60406855, 30400829, + 120765849, 45301372, + ]), + y_minus_x: FieldElement2625([ + 35668062, 24246990, 47788280, 25128298, 37456967, 19518969, 43459670, 10724644, + 7294162, 4471290, + ]), + xy2d: FieldElement2625([ + 33813988, 3549109, 101112, 21464449, 4858392, 3029943, 59999440, 21424738, + 34313875, 1512799, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29494960, 28240930, 51093230, 28823678, 92791151, 54796794, 77571888, 37795542, + 75765856, 10649531, + ]), + y_minus_x: FieldElement2625([ + 63536751, 7572551, 62249759, 25202639, 32046232, 32318941, 29315141, 15424555, + 24706712, 28857648, + ]), + xy2d: FieldElement2625([ + 47618751, 5819839, 19528172, 20715950, 40655763, 20611047, 4960954, 6496879, + 2790858, 28045273, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 85174457, 55843901, 111946683, 31021158, 32797785, 48944265, 78338887, 31144772, + 82688001, 38470222, + ]), + y_minus_x: FieldElement2625([ + 49664705, 3638040, 57888693, 19234931, 40104182, 28143840, 28667142, 18386877, + 18584835, 3592929, + ]), + xy2d: FieldElement2625([ + 12065039, 18867394, 6430594, 17107159, 1727094, 13096957, 61520237, 27056604, + 27026997, 13543966, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 68512926, 37577278, 94695528, 14209106, 95849194, 30038709, 51818051, 20241476, + 68980056, 42251074, + ]), + y_minus_x: FieldElement2625([ + 17325298, 33376175, 65271265, 4931225, 31708266, 6292284, 23064744, 22072792, + 43945505, 9236924, + ]), + xy2d: FieldElement2625([ + 51955585, 20268063, 61151838, 26383348, 4766519, 20788033, 21173534, 27030753, + 9509140, 7790046, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 24124086, 38918775, 28620390, 10538620, 59433851, 19581010, 60862718, 43500219, + 77600721, 32213801, + ]), + y_minus_x: FieldElement2625([ + 7062127, 13930079, 2259902, 6463144, 32137099, 24748848, 41557343, 29331342, + 47345194, 13022814, + ]), + xy2d: FieldElement2625([ + 18921826, 392002, 55817981, 6420686, 8000611, 22415972, 14722962, 26246290, + 20604450, 8079345, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 67710253, 26257798, 51499391, 46550521, 30228769, 53940987, 76234206, 43362242, + 77953697, 21034392, + ]), + y_minus_x: FieldElement2625([ + 25817710, 8020883, 50134679, 21244805, 47057788, 8766556, 29308546, 22307963, + 49449920, 23874253, + ]), + xy2d: FieldElement2625([ + 11081015, 13522660, 12474691, 29260223, 48687631, 9341946, 16850694, 18637605, + 6199839, 14303642, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64518173, 19894035, 117213833, 43031641, 79641718, 39533880, 66531934, 41205092, + 117735515, 13989682, + ]), + y_minus_x: FieldElement2625([ + 6921800, 4421166, 59739491, 30510778, 43106355, 30941531, 9363541, 3394240, + 50874187, 23872585, + ]), + xy2d: FieldElement2625([ + 54293979, 23466866, 47184247, 20627378, 8313211, 5865878, 5948507, 32290343, + 52583140, 23139870, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 111574723, 24134616, 49842442, 23485580, 34844037, 45228427, 67103167, 25858409, + 38508586, 35097070, + ]), + y_minus_x: FieldElement2625([ + 19879846, 15259900, 25020018, 14261729, 22075205, 25189303, 787540, 31325033, + 62422289, 16131171, + ]), + xy2d: FieldElement2625([ + 39487053, 27893575, 34654176, 25620816, 60209846, 23603919, 8931189, 12275052, + 38626469, 33438928, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 105416367, 9568747, 62672739, 49685015, 106242995, 4547918, 18403901, 38581738, + 60829966, 33150322, + ]), + y_minus_x: FieldElement2625([ + 7950033, 25841033, 47276506, 3884935, 62418883, 2342083, 50269031, 14194015, + 27013685, 3320257, + ]), + xy2d: FieldElement2625([ + 35270691, 18076829, 46994271, 4273335, 43595882, 31742297, 58328702, 4594760, + 49180851, 18144010, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 30194115, 50068680, 49746331, 27470090, 40428285, 23271051, 70252167, 16153483, + 123511881, 27809602, + ]), + y_minus_x: FieldElement2625([ + 27113466, 6865046, 4512771, 29327742, 29021084, 7405965, 33302911, 9322435, + 4307527, 32438240, + ]), + xy2d: FieldElement2625([ + 29337813, 24673346, 10359233, 30347534, 57709483, 9930840, 60607771, 24076133, + 20985293, 22480923, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 14579237, 33467236, 85745988, 15769997, 101228358, 21649866, 82685456, 59023858, + 86175344, 24337101, + ]), + y_minus_x: FieldElement2625([ + 4472119, 14702190, 10432042, 22460027, 708461, 18783996, 34234374, 30870323, + 63796457, 10370850, + ]), + xy2d: FieldElement2625([ + 36957127, 19555637, 16244231, 24367549, 58999881, 13440043, 35147632, 8718974, + 43101064, 18487380, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 21818223, 34477173, 23913863, 22441963, 129271975, 14842154, 43035020, 9485973, + 53819529, 22318987, + ]), + y_minus_x: FieldElement2625([ + 10874834, 4351765, 66252340, 17269436, 64427034, 30735311, 5883785, 28998531, + 44403022, 26064601, + ]), + xy2d: FieldElement2625([ + 64017630, 9755550, 37507935, 22752543, 4031638, 29903925, 47267417, 32706846, + 39147952, 21635901, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 81365001, 44927611, 97395185, 43985591, 66242539, 38517499, 52937891, 37374973, + 73352483, 38476849, + ]), + y_minus_x: FieldElement2625([ + 43460763, 24260930, 21493330, 30888969, 23329454, 24545577, 58286855, 12750266, + 22391140, 26198125, + ]), + xy2d: FieldElement2625([ + 20477567, 24078713, 1674568, 4102219, 25208396, 13972305, 30389482, 19572626, + 1485666, 17679765, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 100511110, 23887606, 116505658, 30877106, 45483774, 25222431, 67931340, 37154158, + 32618865, 18610785, + ]), + y_minus_x: FieldElement2625([ + 48647066, 166413, 55454758, 8889513, 21027475, 32728181, 43100067, 4690060, + 7520989, 16421303, + ]), + xy2d: FieldElement2625([ + 14868391, 20996450, 64836606, 1042490, 27060176, 10253541, 53431276, 19516737, + 41808946, 2239538, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50228416, 29594943, 62030348, 10307368, 70970997, 20292574, 126292474, 51543890, + 67827181, 15848795, + ]), + y_minus_x: FieldElement2625([ + 5548701, 17911007, 33137864, 32764443, 31146554, 17931096, 64023370, 7290289, + 6361313, 32861205, + ]), + xy2d: FieldElement2625([ + 63374742, 30320053, 4091667, 30955480, 44819449, 2212055, 52638826, 22391938, + 38484599, 7051029, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50485560, 7033600, 57711425, 10740562, 72347547, 42328739, 7593987, 46950560, + 85560721, 41970063, + ]), + y_minus_x: FieldElement2625([ + 40930651, 3776911, 39108529, 2508077, 19371703, 7626128, 4092943, 15778278, + 42044145, 24540103, + ]), + xy2d: FieldElement2625([ + 44128555, 8867576, 8645499, 22222278, 11497130, 4344907, 10788462, 23382703, + 3547104, 15368835, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 81786515, 51902785, 74560130, 22753403, 52379722, 41395524, 57994925, 6818020, + 57707296, 16352835, + ]), + y_minus_x: FieldElement2625([ + 21622574, 18581624, 36511951, 1212467, 36930308, 7910192, 20622927, 2438677, + 52628762, 29068327, + ]), + xy2d: FieldElement2625([ + 6797431, 2854059, 4269865, 8037366, 32016522, 15223213, 34765784, 15297582, + 3559197, 26425254, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 107761639, 61759660, 79235166, 8794359, 48418924, 60111631, 87862210, 33613219, + 68436482, 40229362, + ]), + y_minus_x: FieldElement2625([ + 52388944, 32880897, 37676257, 8253690, 32826330, 2707379, 25088512, 17182878, + 15053907, 11601568, + ]), + xy2d: FieldElement2625([ + 43894091, 25425955, 50962615, 28097648, 30129084, 13258436, 39364589, 8197601, + 58181660, 15003422, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 13470722, 47835674, 31012390, 30525035, 89789519, 50713267, 39648035, 13815677, + 94028755, 62582101, + ]), + y_minus_x: FieldElement2625([ + 54478677, 14782829, 56712503, 7094748, 41775828, 29409658, 9084386, 30179063, + 64014926, 32519086, + ]), + xy2d: FieldElement2625([ + 6314429, 20018828, 12535891, 19610611, 10074031, 28087963, 50489447, 26314252, + 24553876, 32746308, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 105768482, 46629424, 103418946, 65789027, 85765355, 28316167, 56299027, 22780838, + 122676432, 32376204, + ]), + y_minus_x: FieldElement2625([ + 5654403, 26425050, 39347935, 963424, 5032477, 19850195, 30011537, 11153401, + 63182039, 13343989, + ]), + xy2d: FieldElement2625([ + 1130444, 29814849, 40569426, 8144467, 24179188, 6267924, 63847147, 2912740, + 63870704, 29186744, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 49722534, 11073633, 52865263, 50829611, 33921405, 38614719, 32360242, 35465390, + 50107050, 45035301, + ]), + y_minus_x: FieldElement2625([ + 2003571, 2472803, 46902183, 1716406, 58609069, 15922982, 43766122, 27456369, + 33468339, 29346282, + ]), + xy2d: FieldElement2625([ + 18834217, 8245144, 29896065, 3490830, 62967493, 7220277, 146130, 18459164, + 57533060, 30070422, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77805507, 38474121, 73459597, 18553340, 107508318, 52705654, 33655873, 27331956, + 44498407, 13768350, + ]), + y_minus_x: FieldElement2625([ + 23652128, 27647291, 43351590, 13262712, 65238054, 26296349, 11902126, 2949002, + 34445239, 25602117, + ]), + xy2d: FieldElement2625([ + 55906958, 19046111, 28501158, 28224561, 14495533, 14714956, 32929972, 2643566, + 17034893, 11645825, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 38181639, 29751709, 73650473, 17760526, 80753587, 17992258, 72670209, 41214427, + 87524152, 37630124, + ]), + y_minus_x: FieldElement2625([ + 6498441, 12053607, 10375600, 14764370, 24795955, 16159258, 57849421, 16071837, + 31008329, 3792564, + ]), + xy2d: FieldElement2625([ + 47930485, 9176956, 54248931, 8732776, 58000258, 10333519, 96092, 29273884, + 13051277, 20121493, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54190492, 49837594, 61282066, 10734597, 67926686, 36967416, 115462142, 30339271, + 37200685, 30036936, + ]), + y_minus_x: FieldElement2625([ + 21193614, 19929501, 18841215, 29565554, 64002173, 11123558, 14111648, 6069945, + 30307604, 25935103, + ]), + xy2d: FieldElement2625([ + 58539773, 2098685, 38301131, 15844175, 41633654, 16934366, 15145895, 5543861, + 64050790, 6595361, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 34107945, 34731353, 51956038, 5614778, 79079051, 30288154, 47460410, 22186730, + 30689695, 19628976, + ]), + y_minus_x: FieldElement2625([ + 25043248, 19224237, 46048097, 32289319, 29339134, 12397721, 37385860, 12978240, + 57951631, 31419653, + ]), + xy2d: FieldElement2625([ + 46038439, 28501736, 62566522, 12609283, 35236982, 30457796, 64113609, 14800343, + 6412849, 6276813, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 124528774, 39505727, 83050803, 41361190, 116071796, 37845759, 61633481, 38385016, + 71255100, 31629488, + ]), + y_minus_x: FieldElement2625([ + 249426, 17196749, 35434953, 13884216, 11701636, 24553269, 51821986, 12900910, + 34844073, 16150118, + ]), + xy2d: FieldElement2625([ + 2520516, 14697628, 15319213, 22684490, 62866663, 29666431, 13872507, 7473319, + 12419515, 2958466, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 101517167, 22298305, 98222207, 59471046, 61547444, 50370568, 97111094, 42539051, + 14298448, 49873561, + ]), + y_minus_x: FieldElement2625([ + 19427905, 12004555, 9971383, 28189868, 32306269, 23648270, 34176633, 10760437, + 53354280, 5634974, + ]), + xy2d: FieldElement2625([ + 30044319, 23677863, 60273406, 14563839, 9734978, 19808149, 30899064, 30835691, + 22828539, 23633348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 25513026, 37111929, 37113703, 29589233, 77394412, 34745965, 95889446, 61766763, + 92876242, 37566563, + ]), + y_minus_x: FieldElement2625([ + 42139852, 9176396, 16274786, 33467453, 52558621, 7190768, 1490604, 31312359, + 44767199, 18491072, + ]), + xy2d: FieldElement2625([ + 4272877, 21431483, 45594743, 13027605, 59232641, 24151956, 38390319, 12906718, + 45915869, 15503563, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29874396, 35808736, 25494239, 37976524, 43036007, 37144111, 18198811, 35141252, + 53490316, 47742788, + ]), + y_minus_x: FieldElement2625([ + 59518553, 28520621, 59946871, 29462027, 3630300, 29398589, 60425462, 24588735, + 53129947, 28399367, + ]), + xy2d: FieldElement2625([ + 18192774, 12787801, 32021061, 9158184, 48389348, 16385092, 11799402, 9492011, + 43154220, 15950102, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 68768204, 54638026, 33464925, 53430209, 66037964, 35360373, 22565155, 39168685, + 46605438, 51897954, + ]), + y_minus_x: FieldElement2625([ + 57660336, 29715319, 64414626, 32753338, 16894121, 935644, 53848937, 22684138, + 10541713, 14174330, + ]), + xy2d: FieldElement2625([ + 22888141, 12700209, 40301697, 6435658, 56329485, 5524686, 56715961, 6520808, + 15754965, 9355803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 79549820, 26746924, 54931884, 38547877, 49672847, 19708985, 52599424, 12757151, + 93328625, 39524327, + ]), + y_minus_x: FieldElement2625([ + 33888606, 13911610, 18921581, 1162763, 46616901, 13799218, 29525142, 21929286, + 59295464, 503508, + ]), + xy2d: FieldElement2625([ + 57865531, 22043577, 17998312, 3038439, 52838371, 9832208, 43311531, 660991, + 25265267, 18977724, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64010269, 23727746, 42277281, 48089313, 102316973, 34946803, 127880577, 38411468, + 114816699, 43712746, + ]), + y_minus_x: FieldElement2625([ + 56859315, 32558245, 41017090, 22610758, 13704990, 23215119, 2475037, 32344984, + 12799418, 11135856, + ]), + xy2d: FieldElement2625([ + 1867214, 27167702, 19772099, 16925005, 15366693, 25797692, 10829276, 15372827, + 26582557, 31642714, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 57265197, 20059797, 107314987, 30587501, 60553812, 25602102, 29690666, 37127097, + 103070929, 51772159, + ]), + y_minus_x: FieldElement2625([ + 56432653, 6329655, 42770975, 4187982, 30677076, 9335071, 60103332, 14755050, + 9451294, 574767, + ]), + xy2d: FieldElement2625([ + 52859018, 2867107, 56258365, 15719081, 5959372, 8703738, 29137781, 21575537, + 20249840, 31808689, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 74749335, 47235127, 9995910, 52200224, 92069015, 8964515, 33248715, 21201554, + 57573145, 31605506, + ]), + y_minus_x: FieldElement2625([ + 56307055, 23891752, 3613811, 30787942, 49031222, 26667524, 26985478, 31973510, + 26785294, 29587427, + ]), + xy2d: FieldElement2625([ + 30891460, 5254655, 47414930, 12769216, 42912782, 11830405, 7411958, 1394027, + 18778535, 18209370, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 61227949, 26179350, 57501473, 13585864, 102855675, 40344975, 54134826, 59707765, + 74122694, 12256219, + ]), + y_minus_x: FieldElement2625([ + 5975515, 16302413, 24341148, 28270615, 18786096, 22405501, 28243950, 28328004, + 53412289, 4381960, + ]), + xy2d: FieldElement2625([ + 9394648, 8758552, 26189703, 16642536, 35993528, 5117040, 5977877, 13955594, + 19244020, 24493735, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 111388362, 51822507, 30193028, 3993472, 110736308, 44014764, 107346699, 48464072, + 92830877, 56442511, + ]), + y_minus_x: FieldElement2625([ + 7236795, 30433657, 63588571, 620817, 11118384, 24979014, 66780154, 19877679, + 16217590, 26311105, + ]), + xy2d: FieldElement2625([ + 42540794, 21657271, 16455973, 23630199, 3992015, 21894417, 44876052, 19291718, + 55429803, 30442389, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69421833, 26972132, 58859271, 20240912, 119664007, 29643940, 93968457, 34515112, + 110902491, 44996669, + ]), + y_minus_x: FieldElement2625([ + 3428668, 27807272, 41139948, 24786894, 4167808, 21423270, 52199622, 8021269, + 53172251, 18070808, + ]), + xy2d: FieldElement2625([ + 30631113, 26363656, 21279866, 23275794, 18311406, 466071, 42527968, 7989982, + 29641567, 29446694, + ]), + }, + ]); diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/field.rs new file mode 100644 index 0000000..603ed3f --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/field.rs @@ -0,0 +1,577 @@ +// -*- mode: rust; coding: utf-8; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(32\\)-bit +//! limbs with \\(64\\)-bit products. +//! +//! This code was originally derived from Adam Langley's Golang ed25519 +//! implementation, and was then rewritten to use unsigned limbs instead +//! of signed limbs. + +use core::fmt::Debug; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Sub, SubAssign}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use zeroize::Zeroize; + +/// A `FieldElement2625` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// In the 32-bit implementation, a `FieldElement` is represented in +/// radix \\(2\^{25.5}\\) as ten `u32`s. This means that a field +/// element \\(x\\) is represented as +/// $$ +/// x = \sum\_{i=0}\^9 x\_i 2\^{\lceil i \frac {51} 2 \rceil} +/// = x\_0 + x\_1 2\^{26} + x\_2 2\^{51} + x\_3 2\^{77} + \cdots + x\_9 2\^{230}; +/// $$ +/// the coefficients are alternately bounded by \\(2\^{25}\\) and +/// \\(2\^{26}\\). The limbs are allowed to grow between reductions up +/// to \\(2\^{25+b}\\) or \\(2\^{26+b}\\), where \\(b = 1.75\\). +/// +/// # Note +/// +/// The `curve25519_dalek::field` module provides a type alias +/// `curve25519_dalek::field::FieldElement` to either `FieldElement51` +/// or `FieldElement2625`. +/// +/// The backend-specific type `FieldElement2625` should not be used +/// outside of the `curve25519_dalek::field` module. +#[derive(Copy, Clone)] +pub struct FieldElement2625(pub (crate) [u32; 10]); + +impl Debug for FieldElement2625 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "FieldElement2625({:?})", &self.0[..]) + } +} + +impl Zeroize for FieldElement2625 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl<'b> AddAssign<&'b FieldElement2625> for FieldElement2625 { + fn add_assign(&mut self, _rhs: &'b FieldElement2625) { + for i in 0..10 { + self.0[i] += _rhs.0[i]; + } + } +} + +impl<'a, 'b> Add<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn add(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut output = *self; + output += _rhs; + output + } +} + +impl<'b> SubAssign<&'b FieldElement2625> for FieldElement2625 { + fn sub_assign(&mut self, _rhs: &'b FieldElement2625) { + // See comment in FieldElement51::Sub + // + // Compute a - b as ((a + 2^4 * p) - b) to avoid underflow. + let b = &_rhs.0; + self.0 = FieldElement2625::reduce([ + ((self.0[0] + (0x3ffffed << 4)) - b[0]) as u64, + ((self.0[1] + (0x1ffffff << 4)) - b[1]) as u64, + ((self.0[2] + (0x3ffffff << 4)) - b[2]) as u64, + ((self.0[3] + (0x1ffffff << 4)) - b[3]) as u64, + ((self.0[4] + (0x3ffffff << 4)) - b[4]) as u64, + ((self.0[5] + (0x1ffffff << 4)) - b[5]) as u64, + ((self.0[6] + (0x3ffffff << 4)) - b[6]) as u64, + ((self.0[7] + (0x1ffffff << 4)) - b[7]) as u64, + ((self.0[8] + (0x3ffffff << 4)) - b[8]) as u64, + ((self.0[9] + (0x1ffffff << 4)) - b[9]) as u64, + ]).0; + } +} + +impl<'a, 'b> Sub<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn sub(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut output = *self; + output -= _rhs; + output + } +} + +impl<'b> MulAssign<&'b FieldElement2625> for FieldElement2625 { + fn mul_assign(&mut self, _rhs: &'b FieldElement2625) { + let result = (self as &FieldElement2625) * _rhs; + self.0 = result.0; + } +} + +impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn mul(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + /// Helper function to multiply two 32-bit integers with 64 bits + /// of output. + #[inline(always)] + fn m(x: u32, y: u32) -> u64 { (x as u64) * (y as u64) } + + // Alias self, _rhs for more readable formulas + let x: &[u32;10] = &self.0; let y: &[u32;10] = &_rhs.0; + + // We assume that the input limbs x[i], y[i] are bounded by: + // + // x[i], y[i] < 2^(26 + b) if i even + // x[i], y[i] < 2^(25 + b) if i odd + // + // where b is a (real) parameter representing the excess bits of + // the limbs. We track the bitsizes of all variables through + // the computation and solve at the end for the allowable + // headroom bitsize b (which determines how many additions we + // can perform between reductions or multiplications). + + let y1_19 = 19 * y[1]; // This fits in a u32 + let y2_19 = 19 * y[2]; // iff 26 + b + lg(19) < 32 + let y3_19 = 19 * y[3]; // if b < 32 - 26 - 4.248 = 1.752 + let y4_19 = 19 * y[4]; + let y5_19 = 19 * y[5]; // below, b<2.5: this is a bottleneck, + let y6_19 = 19 * y[6]; // could be avoided by promoting to + let y7_19 = 19 * y[7]; // u64 here instead of in m() + let y8_19 = 19 * y[8]; + let y9_19 = 19 * y[9]; + + // What happens when we multiply x[i] with y[j] and place the + // result into the (i+j)-th limb? + // + // x[i] represents the value x[i]*2^ceil(i*51/2) + // y[j] represents the value y[j]*2^ceil(j*51/2) + // z[i+j] represents the value z[i+j]*2^ceil((i+j)*51/2) + // x[i]*y[j] represents the value x[i]*y[i]*2^(ceil(i*51/2)+ceil(j*51/2)) + // + // Since the radix is already accounted for, the result placed + // into the (i+j)-th limb should be + // + // x[i]*y[i]*2^(ceil(i*51/2)+ceil(j*51/2) - ceil((i+j)*51/2)). + // + // The value of ceil(i*51/2)+ceil(j*51/2) - ceil((i+j)*51/2) is + // 1 when both i and j are odd, and 0 otherwise. So we add + // + // x[i]*y[j] if either i or j is even + // 2*x[i]*y[j] if i and j are both odd + // + // by using precomputed multiples of x[i] for odd i: + + let x1_2 = 2 * x[1]; // This fits in a u32 iff 25 + b + 1 < 32 + let x3_2 = 2 * x[3]; // iff b < 6 + let x5_2 = 2 * x[5]; + let x7_2 = 2 * x[7]; + let x9_2 = 2 * x[9]; + + let z0 = m(x[0],y[0]) + m(x1_2,y9_19) + m(x[2],y8_19) + m(x3_2,y7_19) + m(x[4],y6_19) + m(x5_2,y5_19) + m(x[6],y4_19) + m(x7_2,y3_19) + m(x[8],y2_19) + m(x9_2,y1_19); + let z1 = m(x[0],y[1]) + m(x[1],y[0]) + m(x[2],y9_19) + m(x[3],y8_19) + m(x[4],y7_19) + m(x[5],y6_19) + m(x[6],y5_19) + m(x[7],y4_19) + m(x[8],y3_19) + m(x[9],y2_19); + let z2 = m(x[0],y[2]) + m(x1_2,y[1]) + m(x[2],y[0]) + m(x3_2,y9_19) + m(x[4],y8_19) + m(x5_2,y7_19) + m(x[6],y6_19) + m(x7_2,y5_19) + m(x[8],y4_19) + m(x9_2,y3_19); + let z3 = m(x[0],y[3]) + m(x[1],y[2]) + m(x[2],y[1]) + m(x[3],y[0]) + m(x[4],y9_19) + m(x[5],y8_19) + m(x[6],y7_19) + m(x[7],y6_19) + m(x[8],y5_19) + m(x[9],y4_19); + let z4 = m(x[0],y[4]) + m(x1_2,y[3]) + m(x[2],y[2]) + m(x3_2,y[1]) + m(x[4],y[0]) + m(x5_2,y9_19) + m(x[6],y8_19) + m(x7_2,y7_19) + m(x[8],y6_19) + m(x9_2,y5_19); + let z5 = m(x[0],y[5]) + m(x[1],y[4]) + m(x[2],y[3]) + m(x[3],y[2]) + m(x[4],y[1]) + m(x[5],y[0]) + m(x[6],y9_19) + m(x[7],y8_19) + m(x[8],y7_19) + m(x[9],y6_19); + let z6 = m(x[0],y[6]) + m(x1_2,y[5]) + m(x[2],y[4]) + m(x3_2,y[3]) + m(x[4],y[2]) + m(x5_2,y[1]) + m(x[6],y[0]) + m(x7_2,y9_19) + m(x[8],y8_19) + m(x9_2,y7_19); + let z7 = m(x[0],y[7]) + m(x[1],y[6]) + m(x[2],y[5]) + m(x[3],y[4]) + m(x[4],y[3]) + m(x[5],y[2]) + m(x[6],y[1]) + m(x[7],y[0]) + m(x[8],y9_19) + m(x[9],y8_19); + let z8 = m(x[0],y[8]) + m(x1_2,y[7]) + m(x[2],y[6]) + m(x3_2,y[5]) + m(x[4],y[4]) + m(x5_2,y[3]) + m(x[6],y[2]) + m(x7_2,y[1]) + m(x[8],y[0]) + m(x9_2,y9_19); + let z9 = m(x[0],y[9]) + m(x[1],y[8]) + m(x[2],y[7]) + m(x[3],y[6]) + m(x[4],y[5]) + m(x[5],y[4]) + m(x[6],y[3]) + m(x[7],y[2]) + m(x[8],y[1]) + m(x[9],y[0]); + + // How big is the contribution to z[i+j] from x[i], y[j]? + // + // Using the bounds above, we get: + // + // i even, j even: x[i]*y[j] < 2^(26+b)*2^(26+b) = 2*2^(51+2*b) + // i odd, j even: x[i]*y[j] < 2^(25+b)*2^(26+b) = 1*2^(51+2*b) + // i even, j odd: x[i]*y[j] < 2^(26+b)*2^(25+b) = 1*2^(51+2*b) + // i odd, j odd: 2*x[i]*y[j] < 2*2^(25+b)*2^(25+b) = 1*2^(51+2*b) + // + // We perform inline reduction mod p by replacing 2^255 by 19 + // (since 2^255 - 19 = 0 mod p). This adds a factor of 19, so + // we get the bounds (z0 is the biggest one, but calculated for + // posterity here in case finer estimation is needed later): + // + // z0 < ( 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 249*2^(51 + 2*b) + // z1 < ( 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 154*2^(51 + 2*b) + // z2 < ( 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 195*2^(51 + 2*b) + // z3 < ( 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 118*2^(51 + 2*b) + // z4 < ( 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 141*2^(51 + 2*b) + // z5 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 82*2^(51 + 2*b) + // z6 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 87*2^(51 + 2*b) + // z7 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 )*2^(51 + 2b) = 46*2^(51 + 2*b) + // z6 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 )*2^(51 + 2b) = 33*2^(51 + 2*b) + // z7 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 )*2^(51 + 2b) = 10*2^(51 + 2*b) + // + // So z[0] fits into a u64 if 51 + 2*b + lg(249) < 64 + // if b < 2.5. + FieldElement2625::reduce([z0, z1, z2, z3, z4, z5, z6, z7, z8, z9]) + } +} + +impl<'a> Neg for &'a FieldElement2625 { + type Output = FieldElement2625; + fn neg(self) -> FieldElement2625 { + let mut output = *self; + output.negate(); + output + } +} + +impl ConditionallySelectable for FieldElement2625 { + fn conditional_select( + a: &FieldElement2625, + b: &FieldElement2625, + choice: Choice, + ) -> FieldElement2625 { + FieldElement2625([ + u32::conditional_select(&a.0[0], &b.0[0], choice), + u32::conditional_select(&a.0[1], &b.0[1], choice), + u32::conditional_select(&a.0[2], &b.0[2], choice), + u32::conditional_select(&a.0[3], &b.0[3], choice), + u32::conditional_select(&a.0[4], &b.0[4], choice), + u32::conditional_select(&a.0[5], &b.0[5], choice), + u32::conditional_select(&a.0[6], &b.0[6], choice), + u32::conditional_select(&a.0[7], &b.0[7], choice), + u32::conditional_select(&a.0[8], &b.0[8], choice), + u32::conditional_select(&a.0[9], &b.0[9], choice), + ]) + } + + fn conditional_assign(&mut self, other: &FieldElement2625, choice: Choice) { + self.0[0].conditional_assign(&other.0[0], choice); + self.0[1].conditional_assign(&other.0[1], choice); + self.0[2].conditional_assign(&other.0[2], choice); + self.0[3].conditional_assign(&other.0[3], choice); + self.0[4].conditional_assign(&other.0[4], choice); + self.0[5].conditional_assign(&other.0[5], choice); + self.0[6].conditional_assign(&other.0[6], choice); + self.0[7].conditional_assign(&other.0[7], choice); + self.0[8].conditional_assign(&other.0[8], choice); + self.0[9].conditional_assign(&other.0[9], choice); + } + + fn conditional_swap(a: &mut FieldElement2625, b: &mut FieldElement2625, choice: Choice) { + u32::conditional_swap(&mut a.0[0], &mut b.0[0], choice); + u32::conditional_swap(&mut a.0[1], &mut b.0[1], choice); + u32::conditional_swap(&mut a.0[2], &mut b.0[2], choice); + u32::conditional_swap(&mut a.0[3], &mut b.0[3], choice); + u32::conditional_swap(&mut a.0[4], &mut b.0[4], choice); + u32::conditional_swap(&mut a.0[5], &mut b.0[5], choice); + u32::conditional_swap(&mut a.0[6], &mut b.0[6], choice); + u32::conditional_swap(&mut a.0[7], &mut b.0[7], choice); + u32::conditional_swap(&mut a.0[8], &mut b.0[8], choice); + u32::conditional_swap(&mut a.0[9], &mut b.0[9], choice); + } +} + +impl FieldElement2625 { + /// Invert the sign of this field element + pub fn negate(&mut self) { + // Compute -b as ((2^4 * p) - b) to avoid underflow. + let neg = FieldElement2625::reduce([ + ((0x3ffffed << 4) - self.0[0]) as u64, + ((0x1ffffff << 4) - self.0[1]) as u64, + ((0x3ffffff << 4) - self.0[2]) as u64, + ((0x1ffffff << 4) - self.0[3]) as u64, + ((0x3ffffff << 4) - self.0[4]) as u64, + ((0x1ffffff << 4) - self.0[5]) as u64, + ((0x3ffffff << 4) - self.0[6]) as u64, + ((0x1ffffff << 4) - self.0[7]) as u64, + ((0x3ffffff << 4) - self.0[8]) as u64, + ((0x1ffffff << 4) - self.0[9]) as u64, + ]); + self.0 = neg.0; + } + + /// Construct zero. + pub fn zero() -> FieldElement2625 { + FieldElement2625([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) + } + + /// Construct one. + pub fn one() -> FieldElement2625 { + FieldElement2625([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) + } + + /// Construct -1. + pub fn minus_one() -> FieldElement2625 { + FieldElement2625([ + 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, + 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, + ]) + } + + /// Given `k > 0`, return `self^(2^k)`. + pub fn pow2k(&self, k: u32) -> FieldElement2625 { + debug_assert!( k > 0 ); + let mut z = self.square(); + for _ in 1..k { + z = z.square(); + } + z + } + + /// Given unreduced coefficients `z[0], ..., z[9]` of any size, + /// carry and reduce them mod p to obtain a `FieldElement2625` + /// whose coefficients have excess `b < 0.007`. + /// + /// In other words, each coefficient of the result is bounded by + /// either `2^(25 + 0.007)` or `2^(26 + 0.007)`, as appropriate. + fn reduce(mut z: [u64; 10]) -> FieldElement2625 { + + const LOW_25_BITS: u64 = (1 << 25) - 1; + const LOW_26_BITS: u64 = (1 << 26) - 1; + + /// Carry the value from limb i = 0..8 to limb i+1 + #[inline(always)] + fn carry(z: &mut [u64; 10], i: usize) { + debug_assert!(i < 9); + if i % 2 == 0 { + // Even limbs have 26 bits + z[i+1] += z[i] >> 26; + z[i] &= LOW_26_BITS; + } else { + // Odd limbs have 25 bits + z[i+1] += z[i] >> 25; + z[i] &= LOW_25_BITS; + } + } + + // Perform two halves of the carry chain in parallel. + carry(&mut z, 0); carry(&mut z, 4); + carry(&mut z, 1); carry(&mut z, 5); + carry(&mut z, 2); carry(&mut z, 6); + carry(&mut z, 3); carry(&mut z, 7); + // Since z[3] < 2^64, c < 2^(64-25) = 2^39, + // so z[4] < 2^26 + 2^39 < 2^39.0002 + carry(&mut z, 4); carry(&mut z, 8); + // Now z[4] < 2^26 + // and z[5] < 2^25 + 2^13.0002 < 2^25.0004 (good enough) + + // Last carry has a multiplication by 19: + z[0] += 19*(z[9] >> 25); + z[9] &= LOW_25_BITS; + + // Since z[9] < 2^64, c < 2^(64-25) = 2^39, + // so z[0] + 19*c < 2^26 + 2^43.248 < 2^43.249. + carry(&mut z, 0); + // Now z[1] < 2^25 - 2^(43.249 - 26) + // < 2^25.007 (good enough) + // and we're done. + + FieldElement2625([ + z[0] as u32, z[1] as u32, z[2] as u32, z[3] as u32, z[4] as u32, + z[5] as u32, z[6] as u32, z[7] as u32, z[8] as u32, z[9] as u32, + ]) + } + + /// Load a `FieldElement51` from the low 255 bits of a 256-bit + /// input. + /// + /// # Warning + /// + /// This function does not check that the input used the canonical + /// representative. It masks the high bit, but it will happily + /// decode 2^255 - 18 to 1. Applications that require a canonical + /// encoding of every field element should decode, re-encode to + /// the canonical encoding, and check that the input was + /// canonical. + pub fn from_bytes(data: &[u8; 32]) -> FieldElement2625 { //FeFromBytes + #[inline] + fn load3(b: &[u8]) -> u64 { + (b[0] as u64) | ((b[1] as u64) << 8) | ((b[2] as u64) << 16) + } + + #[inline] + fn load4(b: &[u8]) -> u64 { + (b[0] as u64) | ((b[1] as u64) << 8) | ((b[2] as u64) << 16) | ((b[3] as u64) << 24) + } + + let mut h = [0u64;10]; + const LOW_23_BITS: u64 = (1 << 23) - 1; + h[0] = load4(&data[ 0..]); + h[1] = load3(&data[ 4..]) << 6; + h[2] = load3(&data[ 7..]) << 5; + h[3] = load3(&data[10..]) << 3; + h[4] = load3(&data[13..]) << 2; + h[5] = load4(&data[16..]); + h[6] = load3(&data[20..]) << 7; + h[7] = load3(&data[23..]) << 5; + h[8] = load3(&data[26..]) << 4; + h[9] = (load3(&data[29..]) & LOW_23_BITS) << 2; + + FieldElement2625::reduce(h) + } + + /// Serialize this `FieldElement51` to a 32-byte array. The + /// encoding is canonical. + pub fn to_bytes(&self) -> [u8; 32] { + + let inp = &self.0; + // Reduce the value represented by `in` to the range [0,2*p) + let mut h: [u32; 10] = FieldElement2625::reduce([ + // XXX this cast is annoying + inp[0] as u64, inp[1] as u64, inp[2] as u64, inp[3] as u64, inp[4] as u64, + inp[5] as u64, inp[6] as u64, inp[7] as u64, inp[8] as u64, inp[9] as u64, + ]).0; + + // Let h be the value to encode. + // + // Write h = pq + r with 0 <= r < p. We want to compute r = h mod p. + // + // Since h < 2*p, q = 0 or 1, with q = 0 when h < p and q = 1 when h >= p. + // + // Notice that h >= p <==> h + 19 >= p + 19 <==> h + 19 >= 2^255. + // Therefore q can be computed as the carry bit of h + 19. + + let mut q: u32 = (h[0] + 19) >> 26; + q = (h[1] + q) >> 25; + q = (h[2] + q) >> 26; + q = (h[3] + q) >> 25; + q = (h[4] + q) >> 26; + q = (h[5] + q) >> 25; + q = (h[6] + q) >> 26; + q = (h[7] + q) >> 25; + q = (h[8] + q) >> 26; + q = (h[9] + q) >> 25; + + debug_assert!( q == 0 || q == 1 ); + + // Now we can compute r as r = h - pq = r - (2^255-19)q = r + 19q - 2^255q + + const LOW_25_BITS: u32 = (1 << 25) - 1; + const LOW_26_BITS: u32 = (1 << 26) - 1; + + h[0] += 19*q; + + // Now carry the result to compute r + 19q... + h[1] += h[0] >> 26; + h[0] = h[0] & LOW_26_BITS; + h[2] += h[1] >> 25; + h[1] = h[1] & LOW_25_BITS; + h[3] += h[2] >> 26; + h[2] = h[2] & LOW_26_BITS; + h[4] += h[3] >> 25; + h[3] = h[3] & LOW_25_BITS; + h[5] += h[4] >> 26; + h[4] = h[4] & LOW_26_BITS; + h[6] += h[5] >> 25; + h[5] = h[5] & LOW_25_BITS; + h[7] += h[6] >> 26; + h[6] = h[6] & LOW_26_BITS; + h[8] += h[7] >> 25; + h[7] = h[7] & LOW_25_BITS; + h[9] += h[8] >> 26; + h[8] = h[8] & LOW_26_BITS; + + // ... but instead of carrying the value + // (h[9] >> 25) = q*2^255 into another limb, + // discard it, subtracting the value from h. + debug_assert!( (h[9] >> 25) == 0 || (h[9] >> 25) == 1); + h[9] = h[9] & LOW_25_BITS; + + let mut s = [0u8; 32]; + s[0] = (h[0] >> 0) as u8; + s[1] = (h[0] >> 8) as u8; + s[2] = (h[0] >> 16) as u8; + s[3] = ((h[0] >> 24) | (h[1] << 2)) as u8; + s[4] = (h[1] >> 6) as u8; + s[5] = (h[1] >> 14) as u8; + s[6] = ((h[1] >> 22) | (h[2] << 3)) as u8; + s[7] = (h[2] >> 5) as u8; + s[8] = (h[2] >> 13) as u8; + s[9] = ((h[2] >> 21) | (h[3] << 5)) as u8; + s[10] = (h[3] >> 3) as u8; + s[11] = (h[3] >> 11) as u8; + s[12] = ((h[3] >> 19) | (h[4] << 6)) as u8; + s[13] = (h[4] >> 2) as u8; + s[14] = (h[4] >> 10) as u8; + s[15] = (h[4] >> 18) as u8; + s[16] = (h[5] >> 0) as u8; + s[17] = (h[5] >> 8) as u8; + s[18] = (h[5] >> 16) as u8; + s[19] = ((h[5] >> 24) | (h[6] << 1)) as u8; + s[20] = (h[6] >> 7) as u8; + s[21] = (h[6] >> 15) as u8; + s[22] = ((h[6] >> 23) | (h[7] << 3)) as u8; + s[23] = (h[7] >> 5) as u8; + s[24] = (h[7] >> 13) as u8; + s[25] = ((h[7] >> 21) | (h[8] << 4)) as u8; + s[26] = (h[8] >> 4) as u8; + s[27] = (h[8] >> 12) as u8; + s[28] = ((h[8] >> 20) | (h[9] << 6)) as u8; + s[29] = (h[9] >> 2) as u8; + s[30] = (h[9] >> 10) as u8; + s[31] = (h[9] >> 18) as u8; + + // Check that high bit is cleared + debug_assert!((s[31] & 0b1000_0000u8) == 0u8); + + s + } + + fn square_inner(&self) -> [u64; 10] { + // Optimized version of multiplication for the case of squaring. + // Pre- and post- conditions identical to multiplication function. + let x = &self.0; + let x0_2 = 2 * x[0]; + let x1_2 = 2 * x[1]; + let x2_2 = 2 * x[2]; + let x3_2 = 2 * x[3]; + let x4_2 = 2 * x[4]; + let x5_2 = 2 * x[5]; + let x6_2 = 2 * x[6]; + let x7_2 = 2 * x[7]; + let x5_19 = 19 * x[5]; + let x6_19 = 19 * x[6]; + let x7_19 = 19 * x[7]; + let x8_19 = 19 * x[8]; + let x9_19 = 19 * x[9]; + + /// Helper function to multiply two 32-bit integers with 64 bits + /// of output. + #[inline(always)] + fn m(x: u32, y: u32) -> u64 { (x as u64) * (y as u64) } + + // This block is rearranged so that instead of doing a 32-bit multiplication by 38, we do a + // 64-bit multiplication by 2 on the results. This is because lg(38) is too big: we would + // have less than 1 bit of headroom left, which is too little. + let mut z = [0u64;10]; + z[0] = m(x[0],x[0]) + m(x2_2,x8_19) + m(x4_2,x6_19) + (m(x1_2,x9_19) + m(x3_2,x7_19) + m(x[5],x5_19))*2; + z[1] = m(x0_2,x[1]) + m(x3_2,x8_19) + m(x5_2,x6_19) + (m(x[2],x9_19) + m(x[4],x7_19))*2; + z[2] = m(x0_2,x[2]) + m(x1_2,x[1]) + m(x4_2,x8_19) + m(x[6],x6_19) + (m(x3_2,x9_19) + m(x5_2,x7_19))*2; + z[3] = m(x0_2,x[3]) + m(x1_2,x[2]) + m(x5_2,x8_19) + (m(x[4],x9_19) + m(x[6],x7_19))*2; + z[4] = m(x0_2,x[4]) + m(x1_2,x3_2) + m(x[2],x[2]) + m(x6_2,x8_19) + (m(x5_2,x9_19) + m(x[7],x7_19))*2; + z[5] = m(x0_2,x[5]) + m(x1_2,x[4]) + m(x2_2,x[3]) + m(x7_2,x8_19) + m(x[6],x9_19)*2; + z[6] = m(x0_2,x[6]) + m(x1_2,x5_2) + m(x2_2,x[4]) + m(x3_2,x[3]) + m(x[8],x8_19) + m(x7_2,x9_19)*2; + z[7] = m(x0_2,x[7]) + m(x1_2,x[6]) + m(x2_2,x[5]) + m(x3_2,x[4]) + m(x[8],x9_19)*2; + z[8] = m(x0_2,x[8]) + m(x1_2,x7_2) + m(x2_2,x[6]) + m(x3_2,x5_2) + m(x[4],x[4]) + m(x[9],x9_19)*2; + z[9] = m(x0_2,x[9]) + m(x1_2,x[8]) + m(x2_2,x[7]) + m(x3_2,x[6]) + m(x4_2,x[5]) ; + + z + } + + /// Compute `self^2`. + pub fn square(&self) -> FieldElement2625 { + FieldElement2625::reduce(self.square_inner()) + } + + /// Compute `2*self^2`. + pub fn square2(&self) -> FieldElement2625 { + let mut coeffs = self.square_inner(); + for i in 0..self.0.len() { + coeffs[i] += coeffs[i]; + } + FieldElement2625::reduce(coeffs) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/mod.rs new file mode 100644 index 0000000..e0f344f --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/mod.rs @@ -0,0 +1,21 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier. +//! +//! This code is intended to be portable, but it requires that +//! multiplication of two \\(32\\)-bit values to a \\(64\\)-bit result +//! is constant-time on the target platform. + +pub mod field; + +pub mod scalar; + +pub mod constants; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/scalar.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/scalar.rs new file mode 100644 index 0000000..8dd54bd --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u32/scalar.rs @@ -0,0 +1,529 @@ +//! Arithmetic mod 2^252 + 27742317777372353535851937790883648493 +//! with 9 29-bit unsigned limbs +//! +//! To see that this is safe for intermediate results, note that +//! the largest limb in a 9 by 9 product of 29-bit limbs will be +//! (0x1fffffff^2) * 9 = 0x23fffffdc0000009 (62 bits). +//! +//! For a one level Karatsuba decomposition, the specific ranges +//! depend on how the limbs are combined, but will stay within +//! -0x1ffffffe00000008 (62 bits with sign bit) to +//! 0x43fffffbc0000011 (63 bits), which is still safe. + +use core::fmt::Debug; +use core::ops::{Index, IndexMut}; + +use zeroize::Zeroize; + +use constants; + +/// The `Scalar29` struct represents an element in ℤ/lℤ as 9 29-bit limbs +#[derive(Copy,Clone)] +pub struct Scalar29(pub [u32; 9]); + +impl Debug for Scalar29 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "Scalar29: {:?}", &self.0[..]) + } +} + +impl Zeroize for Scalar29 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl Index for Scalar29 { + type Output = u32; + fn index(&self, _index: usize) -> &u32 { + &(self.0[_index]) + } +} + +impl IndexMut for Scalar29 { + fn index_mut(&mut self, _index: usize) -> &mut u32 { + &mut (self.0[_index]) + } +} + +/// u32 * u32 = u64 multiply helper +#[inline(always)] +fn m(x: u32, y: u32) -> u64 { + (x as u64) * (y as u64) +} + +impl Scalar29 { + /// Return the zero scalar. + pub fn zero() -> Scalar29 { + Scalar29([0,0,0,0,0,0,0,0,0]) + } + + /// Unpack a 32 byte / 256 bit scalar into 9 29-bit limbs. + pub fn from_bytes(bytes: &[u8; 32]) -> Scalar29 { + let mut words = [0u32; 8]; + for i in 0..8 { + for j in 0..4 { + words[i] |= (bytes[(i * 4) + j] as u32) << (j * 8); + } + } + + let mask = (1u32 << 29) - 1; + let top_mask = (1u32 << 24) - 1; + let mut s = Scalar29::zero(); + + s[ 0] = words[0] & mask; + s[ 1] = ((words[0] >> 29) | (words[1] << 3)) & mask; + s[ 2] = ((words[1] >> 26) | (words[2] << 6)) & mask; + s[ 3] = ((words[2] >> 23) | (words[3] << 9)) & mask; + s[ 4] = ((words[3] >> 20) | (words[4] << 12)) & mask; + s[ 5] = ((words[4] >> 17) | (words[5] << 15)) & mask; + s[ 6] = ((words[5] >> 14) | (words[6] << 18)) & mask; + s[ 7] = ((words[6] >> 11) | (words[7] << 21)) & mask; + s[ 8] = (words[7] >> 8) & top_mask; + + s + } + + /// Reduce a 64 byte / 512 bit scalar mod l. + pub fn from_bytes_wide(bytes: &[u8; 64]) -> Scalar29 { + let mut words = [0u32; 16]; + for i in 0..16 { + for j in 0..4 { + words[i] |= (bytes[(i * 4) + j] as u32) << (j * 8); + } + } + + let mask = (1u32 << 29) - 1; + let mut lo = Scalar29::zero(); + let mut hi = Scalar29::zero(); + + lo[0] = words[ 0] & mask; + lo[1] = ((words[ 0] >> 29) | (words[ 1] << 3)) & mask; + lo[2] = ((words[ 1] >> 26) | (words[ 2] << 6)) & mask; + lo[3] = ((words[ 2] >> 23) | (words[ 3] << 9)) & mask; + lo[4] = ((words[ 3] >> 20) | (words[ 4] << 12)) & mask; + lo[5] = ((words[ 4] >> 17) | (words[ 5] << 15)) & mask; + lo[6] = ((words[ 5] >> 14) | (words[ 6] << 18)) & mask; + lo[7] = ((words[ 6] >> 11) | (words[ 7] << 21)) & mask; + lo[8] = ((words[ 7] >> 8) | (words[ 8] << 24)) & mask; + hi[0] = ((words[ 8] >> 5) | (words[ 9] << 27)) & mask; + hi[1] = (words[ 9] >> 2) & mask; + hi[2] = ((words[ 9] >> 31) | (words[10] << 1)) & mask; + hi[3] = ((words[10] >> 28) | (words[11] << 4)) & mask; + hi[4] = ((words[11] >> 25) | (words[12] << 7)) & mask; + hi[5] = ((words[12] >> 22) | (words[13] << 10)) & mask; + hi[6] = ((words[13] >> 19) | (words[14] << 13)) & mask; + hi[7] = ((words[14] >> 16) | (words[15] << 16)) & mask; + hi[8] = words[15] >> 13 ; + + lo = Scalar29::montgomery_mul(&lo, &constants::R); // (lo * R) / R = lo + hi = Scalar29::montgomery_mul(&hi, &constants::RR); // (hi * R^2) / R = hi * R + + Scalar29::add(&hi, &lo) // (hi * R) + lo + } + + /// Pack the limbs of this `Scalar29` into 32 bytes. + pub fn to_bytes(&self) -> [u8; 32] { + let mut s = [0u8; 32]; + + s[0] = (self.0[ 0] >> 0) as u8; + s[1] = (self.0[ 0] >> 8) as u8; + s[2] = (self.0[ 0] >> 16) as u8; + s[3] = ((self.0[ 0] >> 24) | (self.0[ 1] << 5)) as u8; + s[4] = (self.0[ 1] >> 3) as u8; + s[5] = (self.0[ 1] >> 11) as u8; + s[6] = (self.0[ 1] >> 19) as u8; + s[7] = ((self.0[ 1] >> 27) | (self.0[ 2] << 2)) as u8; + s[8] = (self.0[ 2] >> 6) as u8; + s[9] = (self.0[ 2] >> 14) as u8; + s[10] = ((self.0[ 2] >> 22) | (self.0[ 3] << 7)) as u8; + s[11] = (self.0[ 3] >> 1) as u8; + s[12] = (self.0[ 3] >> 9) as u8; + s[13] = (self.0[ 3] >> 17) as u8; + s[14] = ((self.0[ 3] >> 25) | (self.0[ 4] << 4)) as u8; + s[15] = (self.0[ 4] >> 4) as u8; + s[16] = (self.0[ 4] >> 12) as u8; + s[17] = (self.0[ 4] >> 20) as u8; + s[18] = ((self.0[ 4] >> 28) | (self.0[ 5] << 1)) as u8; + s[19] = (self.0[ 5] >> 7) as u8; + s[20] = (self.0[ 5] >> 15) as u8; + s[21] = ((self.0[ 5] >> 23) | (self.0[ 6] << 6)) as u8; + s[22] = (self.0[ 6] >> 2) as u8; + s[23] = (self.0[ 6] >> 10) as u8; + s[24] = (self.0[ 6] >> 18) as u8; + s[25] = ((self.0[ 6] >> 26) | (self.0[ 7] << 3)) as u8; + s[26] = (self.0[ 7] >> 5) as u8; + s[27] = (self.0[ 7] >> 13) as u8; + s[28] = (self.0[ 7] >> 21) as u8; + s[29] = (self.0[ 8] >> 0) as u8; + s[30] = (self.0[ 8] >> 8) as u8; + s[31] = (self.0[ 8] >> 16) as u8; + + s + } + + /// Compute `a + b` (mod l). + pub fn add(a: &Scalar29, b: &Scalar29) -> Scalar29 { + let mut sum = Scalar29::zero(); + let mask = (1u32 << 29) - 1; + + // a + b + let mut carry: u32 = 0; + for i in 0..9 { + carry = a[i] + b[i] + (carry >> 29); + sum[i] = carry & mask; + } + + // subtract l if the sum is >= l + Scalar29::sub(&sum, &constants::L) + } + + /// Compute `a - b` (mod l). + pub fn sub(a: &Scalar29, b: &Scalar29) -> Scalar29 { + let mut difference = Scalar29::zero(); + let mask = (1u32 << 29) - 1; + + // a - b + let mut borrow: u32 = 0; + for i in 0..9 { + borrow = a[i].wrapping_sub(b[i] + (borrow >> 31)); + difference[i] = borrow & mask; + } + + // conditionally add l if the difference is negative + let underflow_mask = ((borrow >> 31) ^ 1).wrapping_sub(1); + let mut carry: u32 = 0; + for i in 0..9 { + carry = (carry >> 29) + difference[i] + (constants::L[i] & underflow_mask); + difference[i] = carry & mask; + } + + difference + } + + /// Compute `a * b`. + /// + /// This is implemented with a one-level refined Karatsuba decomposition + #[inline(always)] + pub (crate) fn mul_internal(a: &Scalar29, b: &Scalar29) -> [u64; 17] { + let mut z = [0u64; 17]; + + z[0] = m(a[0],b[0]); // c00 + z[1] = m(a[0],b[1]) + m(a[1],b[0]); // c01 + z[2] = m(a[0],b[2]) + m(a[1],b[1]) + m(a[2],b[0]); // c02 + z[3] = m(a[0],b[3]) + m(a[1],b[2]) + m(a[2],b[1]) + m(a[3],b[0]); // c03 + z[4] = m(a[0],b[4]) + m(a[1],b[3]) + m(a[2],b[2]) + m(a[3],b[1]) + m(a[4],b[0]); // c04 + z[5] = m(a[1],b[4]) + m(a[2],b[3]) + m(a[3],b[2]) + m(a[4],b[1]); // c05 + z[6] = m(a[2],b[4]) + m(a[3],b[3]) + m(a[4],b[2]); // c06 + z[7] = m(a[3],b[4]) + m(a[4],b[3]); // c07 + z[8] = (m(a[4],b[4])).wrapping_sub(z[3]); // c08 - c03 + + z[10] = z[5].wrapping_sub(m(a[5],b[5])); // c05mc10 + z[11] = z[6].wrapping_sub(m(a[5],b[6]) + m(a[6],b[5])); // c06mc11 + z[12] = z[7].wrapping_sub(m(a[5],b[7]) + m(a[6],b[6]) + m(a[7],b[5])); // c07mc12 + z[13] = m(a[5],b[8]) + m(a[6],b[7]) + m(a[7],b[6]) + m(a[8],b[5]); // c13 + z[14] = m(a[6],b[8]) + m(a[7],b[7]) + m(a[8],b[6]); // c14 + z[15] = m(a[7],b[8]) + m(a[8],b[7]); // c15 + z[16] = m(a[8],b[8]); // c16 + + z[ 5] = z[10].wrapping_sub(z[ 0]); // c05mc10 - c00 + z[ 6] = z[11].wrapping_sub(z[ 1]); // c06mc11 - c01 + z[ 7] = z[12].wrapping_sub(z[ 2]); // c07mc12 - c02 + z[ 8] = z[ 8].wrapping_sub(z[13]); // c08mc13 - c03 + z[ 9] = z[14].wrapping_add(z[ 4]); // c14 + c04 + z[10] = z[15].wrapping_add(z[10]); // c15 + c05mc10 + z[11] = z[16].wrapping_add(z[11]); // c16 + c06mc11 + + let aa = [ + a[0]+a[5], + a[1]+a[6], + a[2]+a[7], + a[3]+a[8] + ]; + + let bb = [ + b[0]+b[5], + b[1]+b[6], + b[2]+b[7], + b[3]+b[8] + ]; + + z[ 5] = (m(aa[0],bb[0])) .wrapping_add(z[ 5]); // c20 + c05mc10 - c00 + z[ 6] = (m(aa[0],bb[1]) + m(aa[1],bb[0])) .wrapping_add(z[ 6]); // c21 + c06mc11 - c01 + z[ 7] = (m(aa[0],bb[2]) + m(aa[1],bb[1]) + m(aa[2],bb[0])) .wrapping_add(z[ 7]); // c22 + c07mc12 - c02 + z[ 8] = (m(aa[0],bb[3]) + m(aa[1],bb[2]) + m(aa[2],bb[1]) + m(aa[3],bb[0])) .wrapping_add(z[ 8]); // c23 + c08mc13 - c03 + z[ 9] = (m(aa[0], b[4]) + m(aa[1],bb[3]) + m(aa[2],bb[2]) + m(aa[3],bb[1]) + m(a[4],bb[0])).wrapping_sub(z[ 9]); // c24 - c14 - c04 + z[10] = ( m(aa[1], b[4]) + m(aa[2],bb[3]) + m(aa[3],bb[2]) + m(a[4],bb[1])).wrapping_sub(z[10]); // c25 - c15 - c05mc10 + z[11] = ( m(aa[2], b[4]) + m(aa[3],bb[3]) + m(a[4],bb[2])).wrapping_sub(z[11]); // c26 - c16 - c06mc11 + z[12] = ( m(aa[3], b[4]) + m(a[4],bb[3])).wrapping_sub(z[12]); // c27 - c07mc12 + + z + } + + /// Compute `a^2`. + #[inline(always)] + fn square_internal(a: &Scalar29) -> [u64; 17] { + let aa = [ + a[0]*2, + a[1]*2, + a[2]*2, + a[3]*2, + a[4]*2, + a[5]*2, + a[6]*2, + a[7]*2 + ]; + + [ + m( a[0],a[0]), + m(aa[0],a[1]), + m(aa[0],a[2]) + m( a[1],a[1]), + m(aa[0],a[3]) + m(aa[1],a[2]), + m(aa[0],a[4]) + m(aa[1],a[3]) + m( a[2],a[2]), + m(aa[0],a[5]) + m(aa[1],a[4]) + m(aa[2],a[3]), + m(aa[0],a[6]) + m(aa[1],a[5]) + m(aa[2],a[4]) + m( a[3],a[3]), + m(aa[0],a[7]) + m(aa[1],a[6]) + m(aa[2],a[5]) + m(aa[3],a[4]), + m(aa[0],a[8]) + m(aa[1],a[7]) + m(aa[2],a[6]) + m(aa[3],a[5]) + m( a[4],a[4]), + m(aa[1],a[8]) + m(aa[2],a[7]) + m(aa[3],a[6]) + m(aa[4],a[5]), + m(aa[2],a[8]) + m(aa[3],a[7]) + m(aa[4],a[6]) + m( a[5],a[5]), + m(aa[3],a[8]) + m(aa[4],a[7]) + m(aa[5],a[6]), + m(aa[4],a[8]) + m(aa[5],a[7]) + m( a[6],a[6]), + m(aa[5],a[8]) + m(aa[6],a[7]), + m(aa[6],a[8]) + m( a[7],a[7]), + m(aa[7],a[8]), + m( a[8],a[8]), + ] + } + + /// Compute `limbs/R` (mod l), where R is the Montgomery modulus 2^261 + #[inline(always)] + pub (crate) fn montgomery_reduce(limbs: &[u64; 17]) -> Scalar29 { + + #[inline(always)] + fn part1(sum: u64) -> (u64, u32) { + let p = (sum as u32).wrapping_mul(constants::LFACTOR) & ((1u32 << 29) - 1); + ((sum + m(p,constants::L[0])) >> 29, p) + } + + #[inline(always)] + fn part2(sum: u64) -> (u64, u32) { + let w = (sum as u32) & ((1u32 << 29) - 1); + (sum >> 29, w) + } + + // note: l5,l6,l7 are zero, so their multiplies can be skipped + let l = &constants::L; + + // the first half computes the Montgomery adjustment factor n, and begins adding n*l to make limbs divisible by R + let (carry, n0) = part1( limbs[ 0]); + let (carry, n1) = part1(carry + limbs[ 1] + m(n0,l[1])); + let (carry, n2) = part1(carry + limbs[ 2] + m(n0,l[2]) + m(n1,l[1])); + let (carry, n3) = part1(carry + limbs[ 3] + m(n0,l[3]) + m(n1,l[2]) + m(n2,l[1])); + let (carry, n4) = part1(carry + limbs[ 4] + m(n0,l[4]) + m(n1,l[3]) + m(n2,l[2]) + m(n3,l[1])); + let (carry, n5) = part1(carry + limbs[ 5] + m(n1,l[4]) + m(n2,l[3]) + m(n3,l[2]) + m(n4,l[1])); + let (carry, n6) = part1(carry + limbs[ 6] + m(n2,l[4]) + m(n3,l[3]) + m(n4,l[2]) + m(n5,l[1])); + let (carry, n7) = part1(carry + limbs[ 7] + m(n3,l[4]) + m(n4,l[3]) + m(n5,l[2]) + m(n6,l[1])); + let (carry, n8) = part1(carry + limbs[ 8] + m(n0,l[8]) + m(n4,l[4]) + m(n5,l[3]) + m(n6,l[2]) + m(n7,l[1])); + + // limbs is divisible by R now, so we can divide by R by simply storing the upper half as the result + let (carry, r0) = part2(carry + limbs[ 9] + m(n1,l[8]) + m(n5,l[4]) + m(n6,l[3]) + m(n7,l[2]) + m(n8,l[1])); + let (carry, r1) = part2(carry + limbs[10] + m(n2,l[8]) + m(n6,l[4]) + m(n7,l[3]) + m(n8,l[2])); + let (carry, r2) = part2(carry + limbs[11] + m(n3,l[8]) + m(n7,l[4]) + m(n8,l[3])); + let (carry, r3) = part2(carry + limbs[12] + m(n4,l[8]) + m(n8,l[4])); + let (carry, r4) = part2(carry + limbs[13] + m(n5,l[8]) ); + let (carry, r5) = part2(carry + limbs[14] + m(n6,l[8]) ); + let (carry, r6) = part2(carry + limbs[15] + m(n7,l[8]) ); + let (carry, r7) = part2(carry + limbs[16] + m(n8,l[8])); + let r8 = carry as u32; + + // result may be >= l, so attempt to subtract l + Scalar29::sub(&Scalar29([r0,r1,r2,r3,r4,r5,r6,r7,r8]), l) + } + + /// Compute `a * b` (mod l). + #[inline(never)] + pub fn mul(a: &Scalar29, b: &Scalar29) -> Scalar29 { + let ab = Scalar29::montgomery_reduce(&Scalar29::mul_internal(a, b)); + Scalar29::montgomery_reduce(&Scalar29::mul_internal(&ab, &constants::RR)) + } + + /// Compute `a^2` (mod l). + #[inline(never)] + #[allow(dead_code)] // XXX we don't expose square() via the Scalar API + pub fn square(&self) -> Scalar29 { + let aa = Scalar29::montgomery_reduce(&Scalar29::square_internal(self)); + Scalar29::montgomery_reduce(&Scalar29::mul_internal(&aa, &constants::RR)) + } + + /// Compute `(a * b) / R` (mod l), where R is the Montgomery modulus 2^261 + #[inline(never)] + pub fn montgomery_mul(a: &Scalar29, b: &Scalar29) -> Scalar29 { + Scalar29::montgomery_reduce(&Scalar29::mul_internal(a, b)) + } + + /// Compute `(a^2) / R` (mod l) in Montgomery form, where R is the Montgomery modulus 2^261 + #[inline(never)] + pub fn montgomery_square(&self) -> Scalar29 { + Scalar29::montgomery_reduce(&Scalar29::square_internal(self)) + } + + /// Puts a Scalar29 in to Montgomery form, i.e. computes `a*R (mod l)` + #[inline(never)] + pub fn to_montgomery(&self) -> Scalar29 { + Scalar29::montgomery_mul(self, &constants::RR) + } + + /// Takes a Scalar29 out of Montgomery form, i.e. computes `a/R (mod l)` + pub fn from_montgomery(&self) -> Scalar29 { + let mut limbs = [0u64; 17]; + for i in 0..9 { + limbs[i] = self[i] as u64; + } + Scalar29::montgomery_reduce(&limbs) + } +} + +#[cfg(test)] +mod test { + use super::*; + + /// Note: x is 2^253-1 which is slightly larger than the largest scalar produced by + /// this implementation (l-1), and should verify there are no overflows for valid scalars + /// + /// x = 2^253-1 = 14474011154664524427946373126085988481658748083205070504932198000989141204991 + /// x = 7237005577332262213973186563042994240801631723825162898930247062703686954002 mod l + /// x = 5147078182513738803124273553712992179887200054963030844803268920753008712037*R mod l in Montgomery form + pub static X: Scalar29 = Scalar29( + [0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, + 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, + 0x001fffff]); + + /// x^2 = 3078544782642840487852506753550082162405942681916160040940637093560259278169 mod l + pub static XX: Scalar29 = Scalar29( + [0x00217559, 0x000b3401, 0x103ff43b, 0x1462a62c, + 0x1d6f9f38, 0x18e7a42f, 0x09a3dcee, 0x008dbe18, + 0x0006ce65]); + + /// x^2 = 2912514428060642753613814151688322857484807845836623976981729207238463947987*R mod l in Montgomery form + pub static XX_MONT: Scalar29 = Scalar29( + [0x152b4d2e, 0x0571d53b, 0x1da6d964, 0x188663b6, + 0x1d1b5f92, 0x19d50e3f, 0x12306c29, 0x0c6f26fe, + 0x00030edb]); + + /// y = 6145104759870991071742105800796537629880401874866217824609283457819451087098 + pub static Y: Scalar29 = Scalar29( + [0x1e1458fa, 0x165ba838, 0x1d787b36, 0x0e577f3a, + 0x1d2baf06, 0x1d689a19, 0x1fff3047, 0x117704ab, + 0x000d9601]); + + /// x*y = 36752150652102274958925982391442301741 + pub static XY: Scalar29 = Scalar29( + [0x0ba7632d, 0x017736bb, 0x15c76138, 0x0c69daa1, + 0x000001ba, 0x00000000, 0x00000000, 0x00000000, + 0x00000000]); + + /// x*y = 3783114862749659543382438697751927473898937741870308063443170013240655651591*R mod l in Montgomery form + pub static XY_MONT: Scalar29 = Scalar29( + [0x077b51e1, 0x1c64e119, 0x02a19ef5, 0x18d2129e, + 0x00de0430, 0x045a7bc8, 0x04cfc7c9, 0x1c002681, + 0x000bdc1c]); + + /// a = 2351415481556538453565687241199399922945659411799870114962672658845158063753 + pub static A: Scalar29 = Scalar29( + [0x07b3be89, 0x02291b60, 0x14a99f03, 0x07dc3787, + 0x0a782aae, 0x16262525, 0x0cfdb93f, 0x13f5718d, + 0x000532da]); + + /// b = 4885590095775723760407499321843594317911456947580037491039278279440296187236 + pub static B: Scalar29 = Scalar29( + [0x15421564, 0x1e69fd72, 0x093d9692, 0x161785be, + 0x1587d69f, 0x09d9dada, 0x130246c0, 0x0c0a8e72, + 0x000acd25]); + + /// a+b = 0 + /// a-b = 4702830963113076907131374482398799845891318823599740229925345317690316127506 + pub static AB: Scalar29 = Scalar29( + [0x0f677d12, 0x045236c0, 0x09533e06, 0x0fb86f0f, + 0x14f0555c, 0x0c4c4a4a, 0x19fb727f, 0x07eae31a, + 0x000a65b5]); + + // c = (2^512 - 1) % l = 1627715501170711445284395025044413883736156588369414752970002579683115011840 + pub static C: Scalar29 = Scalar29( + [0x049c0f00, 0x00308f1a, 0x0164d1e9, 0x1c374ed1, + 0x1be65d00, 0x19e90bfa, 0x08f73bb1, 0x036f8613, + 0x00039941]); + + #[test] + fn mul_max() { + let res = Scalar29::mul(&X, &X); + for i in 0..9 { + assert!(res[i] == XX[i]); + } + } + + #[test] + fn square_max() { + let res = X.square(); + for i in 0..9 { + assert!(res[i] == XX[i]); + } + } + + #[test] + fn montgomery_mul_max() { + let res = Scalar29::montgomery_mul(&X, &X); + for i in 0..9 { + assert!(res[i] == XX_MONT[i]); + } + } + + #[test] + fn montgomery_square_max() { + let res = X.montgomery_square(); + for i in 0..9 { + assert!(res[i] == XX_MONT[i]); + } + } + + #[test] + fn mul() { + let res = Scalar29::mul(&X, &Y); + for i in 0..9 { + assert!(res[i] == XY[i]); + } + } + + #[test] + fn montgomery_mul() { + let res = Scalar29::montgomery_mul(&X, &Y); + for i in 0..9 { + assert!(res[i] == XY_MONT[i]); + } + } + + #[test] + fn add() { + let res = Scalar29::add(&A, &B); + let zero = Scalar29::zero(); + for i in 0..9 { + assert!(res[i] == zero[i]); + } + } + + #[test] + fn sub() { + let res = Scalar29::sub(&A, &B); + for i in 0..9 { + assert!(res[i] == AB[i]); + } + } + + #[test] + fn from_bytes_wide() { + let bignum = [255u8; 64]; // 2^512 - 1 + let reduced = Scalar29::from_bytes_wide(&bignum); + for i in 0..9 { + assert!(reduced[i] == C[i]); + } + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/constants.rs new file mode 100644 index 0000000..fc8c6da --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/constants.rs @@ -0,0 +1,7743 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. + +use backend::serial::curve_models::AffineNielsPoint; +use backend::serial::u64::field::FieldElement51; +use backend::serial::u64::scalar::Scalar52; +use edwards::{EdwardsBasepointTable, EdwardsPoint}; +use window::{LookupTable, NafLookupTable8}; + +/// The value of minus one, equal to `-&FieldElement::one()` +pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([ + 2251799813685228, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247 +]); + +/// Edwards `d` value, equal to `-121665/121666 mod p`. +pub(crate) const EDWARDS_D: FieldElement51 = FieldElement51([ + 929955233495203, + 466365720129213, + 1662059464998953, + 2033849074728123, + 1442794654840575, +]); + +/// Edwards `2*d` value, equal to `2*(-121665/121666) mod p`. +pub(crate) const EDWARDS_D2: FieldElement51 = FieldElement51([ + 1859910466990425, + 932731440258426, + 1072319116312658, + 1815898335770999, + 633789495995903, +]); + +/// One minus edwards `d` value squared, equal to `(1 - (-121665/121666) mod p) pow 2` +pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement51 = FieldElement51([ + 1136626929484150, + 1998550399581263, + 496427632559748, + 118527312129759, + 45110755273534 +]); + +/// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2` +pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement51 = FieldElement51([ + 1507062230895904, + 1572317787530805, + 683053064812840, + 317374165784489, + 1572899562415810 +]); + +/// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const SQRT_AD_MINUS_ONE: FieldElement51 = FieldElement51([ + 2241493124984347, + 425987919032274, + 2207028919301688, + 1220490630685848, + 974799131293748, +]); + +/// `= 1/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const INVSQRT_A_MINUS_D: FieldElement51 = FieldElement51([ + 278908739862762, + 821645201101625, + 8113234426968, + 1777959178193151, + 2118520810568447, +]); + +/// Precomputed value of one of the square roots of -1 (mod p) +pub(crate) const SQRT_M1: FieldElement51 = FieldElement51([ + 1718705420411056, + 234908883556509, + 2233514472574048, + 2117202627021982, + 765476049583133, +]); + +/// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) +pub(crate) const APLUS2_OVER_FOUR: FieldElement51 = FieldElement51([121666, 0, 0, 0, 0]); + +/// `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493 +pub(crate) const L: Scalar52 = Scalar52([ + 0x0002631a5cf5d3ed, + 0x000dea2f79cd6581, + 0x000000000014def9, + 0x0000000000000000, + 0x0000100000000000, +]); + +/// `L` * `LFACTOR` = -1 (mod 2^52) +pub(crate) const LFACTOR: u64 = 0x51da312547e1b; + +/// `R` = R % L where R = 2^260 +pub(crate) const R: Scalar52 = Scalar52([ + 0x000f48bd6721e6ed, + 0x0003bab5ac67e45a, + 0x000fffffeb35e51b, + 0x000fffffffffffff, + 0x00000fffffffffff, +]); + +/// `RR` = (R^2) % L where R = 2^260 +pub(crate) const RR: Scalar52 = Scalar52([ + 0x0009d265e952d13b, + 0x000d63c715bea69f, + 0x0005be65cb687604, + 0x0003dceec73d217f, + 0x000009411b7c309a, +]); + +/// The Ed25519 basepoint, as an `EdwardsPoint`. +/// +/// This is called `_POINT` to distinguish it from +/// `ED25519_BASEPOINT_TABLE`, which should be used for scalar +/// multiplication (it's much faster). +pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { + X: FieldElement51([ + 1738742601995546, + 1146398526822698, + 2070867633025821, + 562264141797630, + 587772402128613, + ]), + Y: FieldElement51([ + 1801439850948184, + 1351079888211148, + 450359962737049, + 900719925474099, + 1801439850948198, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([ + 1841354044333475, + 16398895984059, + 755974180946558, + 900171276175154, + 1821297809914039, + ]), +}; + +/// The 8-torsion subgroup \\(\mathcal E [8]\\). +/// +/// In the case of Curve25519, it is cyclic; the \\(i\\)-th element of +/// the array is \\([i]P\\), where \\(P\\) is a point of order \\(8\\) +/// generating \\(\mathcal E[8]\\). +/// +/// Thus \\(\mathcal E[4]\\) is the points indexed by `0,2,4,6`, and +/// \\(\mathcal E[2]\\) is the points indexed by `0,4`. +pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN; + +/// Inner item used to hide limb constants from cargo doc output. +#[doc(hidden)] +pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ + EdwardsPoint { + X: FieldElement51([0, 0, 0, 0, 0]), + Y: FieldElement51([1, 0, 0, 0, 0]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51([ + 358744748052810, + 1691584618240980, + 977650209285361, + 1429865912637724, + 560044844278676, + ]), + Y: FieldElement51([ + 84926274344903, + 473620666599931, + 365590438845504, + 1028470286882429, + 2146499180330972, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([ + 1448326834587521, + 1857896831960481, + 1093722731865333, + 1677408490711241, + 1915505153018406, + ]), + }, + EdwardsPoint { + X: FieldElement51([ + 533094393274173, + 2016890930128738, + 18285341111199, + 134597186663265, + 1486323764102114, + ]), + Y: FieldElement51([0, 0, 0, 0, 0]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51([ + 358744748052810, + 1691584618240980, + 977650209285361, + 1429865912637724, + 560044844278676, + ]), + Y: FieldElement51([ + 2166873539340326, + 1778179147085316, + 1886209374839743, + 1223329526802818, + 105300633354275, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([ + 803472979097708, + 393902981724766, + 1158077081819914, + 574391322974006, + 336294660666841, + ]), + }, + EdwardsPoint { + X: FieldElement51([0, 0, 0, 0, 0]), + Y: FieldElement51([ + 2251799813685228, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51([ + 1893055065632419, + 560215195444267, + 1274149604399886, + 821933901047523, + 1691754969406571, + ]), + Y: FieldElement51([ + 2166873539340326, + 1778179147085316, + 1886209374839743, + 1223329526802818, + 105300633354275, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([ + 1448326834587521, + 1857896831960481, + 1093722731865333, + 1677408490711241, + 1915505153018406, + ]), + }, + EdwardsPoint { + X: FieldElement51([ + 1718705420411056, + 234908883556509, + 2233514472574048, + 2117202627021982, + 765476049583133, + ]), + Y: FieldElement51([0, 0, 0, 0, 0]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51([ + 1893055065632419, + 560215195444267, + 1274149604399886, + 821933901047523, + 1691754969406571, + ]), + Y: FieldElement51([ + 84926274344903, + 473620666599931, + 365590438845504, + 1028470286882429, + 2146499180330972, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([ + 803472979097708, + 393902981724766, + 1158077081819914, + 574391322974006, + 336294660666841, + ]), + }, +]; + +/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). +pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; + +/// Inner constant, used to avoid filling the docs with precomputed points. +#[doc(hidden)] +pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = + EdwardsBasepointTable([ + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3540182452943730, + 2497478415033846, + 2521227595762870, + 1462984067271729, + 2389212253076811, + ]), + y_minus_x: FieldElement51([ + 62697248952638, + 204681361388450, + 631292143396476, + 338455783676468, + 1213667448819585, + ]), + xy2d: FieldElement51([ + 301289933810280, + 1259582250014073, + 1422107436869536, + 796239922652654, + 1953934009299142, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3632771708514775, + 790832306631235, + 2067202295274102, + 1995808275510000, + 1566530869037010, + ]), + y_minus_x: FieldElement51([ + 463307831301544, + 432984605774163, + 1610641361907204, + 750899048855000, + 1894842303421586, + ]), + xy2d: FieldElement51([ + 748439484463711, + 1033211726465151, + 1396005112841647, + 1611506220286469, + 1972177495910992, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1601611775252272, + 1720807796594148, + 1132070835939856, + 3512254832574799, + 2147779492816910, + ]), + y_minus_x: FieldElement51([ + 316559037616741, + 2177824224946892, + 1459442586438991, + 1461528397712656, + 751590696113597, + ]), + xy2d: FieldElement51([ + 1850748884277385, + 1200145853858453, + 1068094770532492, + 672251375690438, + 1586055907191707, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 934282339813791, + 1846903124198670, + 1172395437954843, + 1007037127761661, + 1830588347719256, + ]), + y_minus_x: FieldElement51([ + 1694390458783935, + 1735906047636159, + 705069562067493, + 648033061693059, + 696214010414170, + ]), + xy2d: FieldElement51([ + 1121406372216585, + 192876649532226, + 190294192191717, + 1994165897297032, + 2245000007398739, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 769950342298400, + 2384754244604994, + 3095885746880802, + 3225892188161580, + 2977876099231263, + ]), + y_minus_x: FieldElement51([ + 425251763115706, + 608463272472562, + 442562545713235, + 837766094556764, + 374555092627893, + ]), + xy2d: FieldElement51([ + 1086255230780037, + 274979815921559, + 1960002765731872, + 929474102396301, + 1190409889297339, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1388594989461809, + 316767091099457, + 2646098655878230, + 1230079486801004, + 1440737038838979, + ]), + y_minus_x: FieldElement51([ + 7380825640100, + 146210432690483, + 304903576448906, + 1198869323871120, + 997689833219095, + ]), + xy2d: FieldElement51([ + 1181317918772081, + 114573476638901, + 262805072233344, + 265712217171332, + 294181933805782, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2916800678241215, + 2065379846933858, + 2622030924071124, + 2602788184473875, + 1233371373142984, + ]), + y_minus_x: FieldElement51([ + 2019367628972465, + 676711900706637, + 110710997811333, + 1108646842542025, + 517791959672113, + ]), + xy2d: FieldElement51([ + 965130719900578, + 247011430587952, + 526356006571389, + 91986625355052, + 2157223321444601, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4320419353804412, + 4218074731744053, + 957728544705548, + 729906502578991, + 2411634706750414, + ]), + y_minus_x: FieldElement51([ + 2073601412052185, + 31021124762708, + 264500969797082, + 248034690651703, + 1030252227928288, + ]), + xy2d: FieldElement51([ + 551790716293402, + 1989538725166328, + 801169423371717, + 2052451893578887, + 678432056995012, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1368953770187805, + 3042147450398169, + 2689308289352409, + 2142576377050579, + 1932081720066286, + ]), + y_minus_x: FieldElement51([ + 953638594433374, + 1092333936795051, + 1419774766716690, + 805677984380077, + 859228993502513, + ]), + xy2d: FieldElement51([ + 1200766035879111, + 20142053207432, + 1465634435977050, + 1645256912097844, + 295121984874596, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1735718747031538, + 1248237894295956, + 1204753118328107, + 976066523550493, + 2317743583219840, + ]), + y_minus_x: FieldElement51([ + 1060098822528990, + 1586825862073490, + 212301317240126, + 1975302711403555, + 666724059764335, + ]), + xy2d: FieldElement51([ + 1091990273418756, + 1572899409348578, + 80968014455247, + 306009358661350, + 1520450739132526, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3732317023121341, + 1511153322193951, + 3496143672676420, + 2556587964178488, + 2620936670181690, + ]), + y_minus_x: FieldElement51([ + 2151330273626164, + 762045184746182, + 1688074332551515, + 823046109005759, + 907602769079491, + ]), + xy2d: FieldElement51([ + 2047386910586836, + 168470092900250, + 1552838872594810, + 340951180073789, + 360819374702533, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1982622644432037, + 2014393600336956, + 2380709022489462, + 3869592437614438, + 2357094095599062, + ]), + y_minus_x: FieldElement51([ + 980234343912898, + 1712256739246056, + 588935272190264, + 204298813091998, + 841798321043288, + ]), + xy2d: FieldElement51([ + 197561292938973, + 454817274782871, + 1963754960082318, + 2113372252160468, + 971377527342673, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2416499262514576, + 2254927265442919, + 3451304785234000, + 1766155447043651, + 1899238924683527, + ]), + y_minus_x: FieldElement51([ + 732262946680281, + 1674412764227063, + 2182456405662809, + 1350894754474250, + 558458873295247, + ]), + xy2d: FieldElement51([ + 2103305098582922, + 1960809151316468, + 715134605001343, + 1454892949167181, + 40827143824949, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1239289043050193, + 1744654158124578, + 758702410031698, + 4048562808759936, + 2253402870349013, + ]), + y_minus_x: FieldElement51([ + 2232056027107988, + 987343914584615, + 2115594492994461, + 1819598072792159, + 1119305654014850, + ]), + xy2d: FieldElement51([ + 320153677847348, + 939613871605645, + 641883205761567, + 1930009789398224, + 329165806634126, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3232730304159378, + 1242488692177892, + 1251446316964684, + 1086618677993530, + 1961430968465772, + ]), + y_minus_x: FieldElement51([ + 276821765317453, + 1536835591188030, + 1305212741412361, + 61473904210175, + 2051377036983058, + ]), + xy2d: FieldElement51([ + 833449923882501, + 1750270368490475, + 1123347002068295, + 185477424765687, + 278090826653186, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 794524995833413, + 1849907304548286, + 2305148486158393, + 1272368559505216, + 1147304168324779, + ]), + y_minus_x: FieldElement51([ + 1504846112759364, + 1203096289004681, + 562139421471418, + 274333017451844, + 1284344053775441, + ]), + xy2d: FieldElement51([ + 483048732424432, + 2116063063343382, + 30120189902313, + 292451576741007, + 1156379271702225, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3180171966714267, + 2147692869914563, + 1455665844462196, + 1986737809425946, + 2437006863943337, + ]), + y_minus_x: FieldElement51([ + 137732961814206, + 706670923917341, + 1387038086865771, + 1965643813686352, + 1384777115696347, + ]), + xy2d: FieldElement51([ + 481144981981577, + 2053319313589856, + 2065402289827512, + 617954271490316, + 1106602634668125, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2948097833334040, + 3145099472726142, + 1148636718636008, + 2278533891034865, + 2203955659340680, + ]), + y_minus_x: FieldElement51([ + 657390353372855, + 998499966885562, + 991893336905797, + 810470207106761, + 343139804608786, + ]), + xy2d: FieldElement51([ + 791736669492960, + 934767652997115, + 824656780392914, + 1759463253018643, + 361530362383518, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2022541353055578, + 4346500076272714, + 3802807888710933, + 2494585331103411, + 2947785218648809, + ]), + y_minus_x: FieldElement51([ + 1287487199965223, + 2215311941380308, + 1552928390931986, + 1664859529680196, + 1125004975265243, + ]), + xy2d: FieldElement51([ + 677434665154918, + 989582503122485, + 1817429540898386, + 1052904935475344, + 1143826298169798, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2619066141993637, + 2570231002607651, + 2947429167440602, + 2885885471266079, + 2276381426249673, + ]), + y_minus_x: FieldElement51([ + 773360688841258, + 1815381330538070, + 363773437667376, + 539629987070205, + 783280434248437, + ]), + xy2d: FieldElement51([ + 180820816194166, + 168937968377394, + 748416242794470, + 1227281252254508, + 1567587861004268, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2730575372268893, + 2062896624554806, + 2951191072970647, + 2609899222113120, + 1277310261461760, + ]), + y_minus_x: FieldElement51([ + 1984740906540026, + 1079164179400229, + 1056021349262661, + 1659958556483663, + 1088529069025527, + ]), + xy2d: FieldElement51([ + 580736401511151, + 1842931091388998, + 1177201471228238, + 2075460256527244, + 1301133425678027, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1515728832059163, + 1575261009617579, + 1510246567196186, + 2442877836294952, + 2368461529974388, + ]), + y_minus_x: FieldElement51([ + 1295295738269652, + 1714742313707026, + 545583042462581, + 2034411676262552, + 1513248090013606, + ]), + xy2d: FieldElement51([ + 230710545179830, + 30821514358353, + 760704303452229, + 390668103790604, + 573437871383156, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3421179921230875, + 2514967047430861, + 4274701112739695, + 3071700566936367, + 4275698278559832, + ]), + y_minus_x: FieldElement51([ + 2102254323485823, + 1570832666216754, + 34696906544624, + 1993213739807337, + 70638552271463, + ]), + xy2d: FieldElement51([ + 894132856735058, + 548675863558441, + 845349339503395, + 1942269668326667, + 1615682209874691, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3539470031223082, + 1222355136884919, + 1846481788678694, + 1150426571265110, + 1613523400722047, + ]), + y_minus_x: FieldElement51([ + 793388516527298, + 1315457083650035, + 1972286999342417, + 1901825953052455, + 338269477222410, + ]), + xy2d: FieldElement51([ + 550201530671806, + 778605267108140, + 2063911101902983, + 115500557286349, + 2041641272971022, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 717255318455100, + 519313764361315, + 2080406977303708, + 541981206705521, + 774328150311600, + ]), + y_minus_x: FieldElement51([ + 261715221532238, + 1795354330069993, + 1496878026850283, + 499739720521052, + 389031152673770, + ]), + xy2d: FieldElement51([ + 1997217696294013, + 1717306351628065, + 1684313917746180, + 1644426076011410, + 1857378133465451, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3727234538477877, + 2328731709971226, + 3368528843456914, + 2002544139318041, + 2977347647489186, + ]), + y_minus_x: FieldElement51([ + 2022306639183567, + 726296063571875, + 315345054448644, + 1058733329149221, + 1448201136060677, + ]), + xy2d: FieldElement51([ + 1710065158525665, + 1895094923036397, + 123988286168546, + 1145519900776355, + 1607510767693874, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2813405189107769, + 1071733543815036, + 2383296312486238, + 1946868434569998, + 3079937947649451, + ]), + y_minus_x: FieldElement51([ + 1548495173745801, + 442310529226540, + 998072547000384, + 553054358385281, + 644824326376171, + ]), + xy2d: FieldElement51([ + 1445526537029440, + 2225519789662536, + 914628859347385, + 1064754194555068, + 1660295614401091, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3451490036797185, + 2275827949507588, + 2318438102929588, + 2309425969971222, + 2816893781664854, + ]), + y_minus_x: FieldElement51([ + 876926774220824, + 554618976488214, + 1012056309841565, + 839961821554611, + 1414499340307677, + ]), + xy2d: FieldElement51([ + 703047626104145, + 1266841406201770, + 165556500219173, + 486991595001879, + 1011325891650656, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1622861044480487, + 1156394801573634, + 4120932379100752, + 2578903799462977, + 2095342781472283, + ]), + y_minus_x: FieldElement51([ + 334886927423922, + 489511099221528, + 129160865966726, + 1720809113143481, + 619700195649254, + ]), + xy2d: FieldElement51([ + 1646545795166119, + 1758370782583567, + 714746174550637, + 1472693650165135, + 898994790308209, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2585203586724508, + 2547572356138185, + 1693106465353609, + 912330357530760, + 2723035471635610, + ]), + y_minus_x: FieldElement51([ + 1811196219982022, + 1068969825533602, + 289602974833439, + 1988956043611592, + 863562343398367, + ]), + xy2d: FieldElement51([ + 906282429780072, + 2108672665779781, + 432396390473936, + 150625823801893, + 1708930497638539, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 925664675702309, + 2273216662253932, + 4083236455546587, + 601157008940112, + 2623617868729744, + ]), + y_minus_x: FieldElement51([ + 1479786007267725, + 1738881859066675, + 68646196476567, + 2146507056100328, + 1247662817535471, + ]), + xy2d: FieldElement51([ + 52035296774456, + 939969390708103, + 312023458773250, + 59873523517659, + 1231345905848899, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2895154920100990, + 2541986621181021, + 2013561737429022, + 2571447883196794, + 2645536492181409, + ]), + y_minus_x: FieldElement51([ + 129358342392716, + 1932811617704777, + 1176749390799681, + 398040349861790, + 1170779668090425, + ]), + xy2d: FieldElement51([ + 2051980782668029, + 121859921510665, + 2048329875753063, + 1235229850149665, + 519062146124755, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3859970785658325, + 2667608874045675, + 1350468408164765, + 2038620059057678, + 3278704299674360, + ]), + y_minus_x: FieldElement51([ + 1837656083115103, + 1510134048812070, + 906263674192061, + 1821064197805734, + 565375124676301, + ]), + xy2d: FieldElement51([ + 578027192365650, + 2034800251375322, + 2128954087207123, + 478816193810521, + 2196171989962750, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1633188840273120, + 3104586986058956, + 1548762607215795, + 1266275218902681, + 3359018017010381, + ]), + y_minus_x: FieldElement51([ + 462189358480054, + 1784816734159228, + 1611334301651368, + 1303938263943540, + 707589560319424, + ]), + xy2d: FieldElement51([ + 1038829280972848, + 38176604650029, + 753193246598573, + 1136076426528122, + 595709990562434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3660251634545082, + 2194984964010832, + 2198361797561729, + 1061962440055713, + 1645147963442934, + ]), + y_minus_x: FieldElement51([ + 4701053362120, + 1647641066302348, + 1047553002242085, + 1923635013395977, + 206970314902065, + ]), + xy2d: FieldElement51([ + 1750479161778571, + 1362553355169293, + 1891721260220598, + 966109370862782, + 1024913988299801, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2464498862816952, + 1117950018299774, + 1873945661751056, + 3655602735669306, + 2382695896337945, + ]), + y_minus_x: FieldElement51([ + 636808533673210, + 1262201711667560, + 390951380330599, + 1663420692697294, + 561951321757406, + ]), + xy2d: FieldElement51([ + 520731594438141, + 1446301499955692, + 273753264629267, + 1565101517999256, + 1019411827004672, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3178327305714638, + 3443653291096626, + 734233225181170, + 2435838701226518, + 4042225960010590, + ]), + y_minus_x: FieldElement51([ + 1464651961852572, + 1483737295721717, + 1519450561335517, + 1161429831763785, + 405914998179977, + ]), + xy2d: FieldElement51([ + 996126634382301, + 796204125879525, + 127517800546509, + 344155944689303, + 615279846169038, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2990523894660505, + 2188666632415295, + 1961313708559162, + 1506545807547587, + 3403101452654988, + ]), + y_minus_x: FieldElement51([ + 622917337413835, + 1218989177089035, + 1284857712846592, + 970502061709359, + 351025208117090, + ]), + xy2d: FieldElement51([ + 2067814584765580, + 1677855129927492, + 2086109782475197, + 235286517313238, + 1416314046739645, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2838644076315587, + 2559244195637442, + 458399356043425, + 2853867838192310, + 3280348017100490, + ]), + y_minus_x: FieldElement51([ + 678489922928203, + 2016657584724032, + 90977383049628, + 1026831907234582, + 615271492942522, + ]), + xy2d: FieldElement51([ + 301225714012278, + 1094837270268560, + 1202288391010439, + 644352775178361, + 1647055902137983, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1210746697896459, + 1416608304244708, + 2938287290903104, + 3496931005119382, + 3303038150540984, + ]), + y_minus_x: FieldElement51([ + 1135604073198207, + 1683322080485474, + 769147804376683, + 2086688130589414, + 900445683120379, + ]), + xy2d: FieldElement51([ + 1971518477615628, + 401909519527336, + 448627091057375, + 1409486868273821, + 1214789035034363, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1364039144731711, + 1897497433586190, + 2203097701135459, + 2397261210496499, + 1349844460790698, + ]), + y_minus_x: FieldElement51([ + 1045230323257973, + 818206601145807, + 630513189076103, + 1672046528998132, + 807204017562437, + ]), + xy2d: FieldElement51([ + 439961968385997, + 386362664488986, + 1382706320807688, + 309894000125359, + 2207801346498567, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3480804500082836, + 3172443782216110, + 2375775707596425, + 2933223806901024, + 1400559197080972, + ]), + y_minus_x: FieldElement51([ + 2003766096898049, + 170074059235165, + 1141124258967971, + 1485419893480973, + 1573762821028725, + ]), + xy2d: FieldElement51([ + 729905708611432, + 1270323270673202, + 123353058984288, + 426460209632942, + 2195574535456672, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1271140255321216, + 2044363183174497, + 2303925201319937, + 3696920060379952, + 3194341800024331, + ]), + y_minus_x: FieldElement51([ + 1761608437466135, + 583360847526804, + 1586706389685493, + 2157056599579261, + 1170692369685772, + ]), + xy2d: FieldElement51([ + 871476219910823, + 1878769545097794, + 2241832391238412, + 548957640601001, + 690047440233174, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2548994545820755, + 1366347803776819, + 3552985325930849, + 561849853336293, + 1533554921345731, + ]), + y_minus_x: FieldElement51([ + 999628998628371, + 1132836708493400, + 2084741674517453, + 469343353015612, + 678782988708035, + ]), + xy2d: FieldElement51([ + 2189427607417022, + 699801937082607, + 412764402319267, + 1478091893643349, + 2244675696854460, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3964091869651792, + 2456213404310121, + 3657538451018088, + 2660781114515010, + 3112882032961968, + ]), + y_minus_x: FieldElement51([ + 508561155940631, + 966928475686665, + 2236717801150132, + 424543858577297, + 2089272956986143, + ]), + xy2d: FieldElement51([ + 221245220129925, + 1156020201681217, + 491145634799213, + 542422431960839, + 828100817819207, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2405556784925632, + 1299874139923976, + 2644898978945750, + 1058234455773021, + 996989038681183, + ]), + y_minus_x: FieldElement51([ + 559086812798481, + 573177704212711, + 1629737083816402, + 1399819713462595, + 1646954378266038, + ]), + xy2d: FieldElement51([ + 1887963056288059, + 228507035730124, + 1468368348640282, + 930557653420194, + 613513962454686, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1224529808187534, + 1577022856702685, + 2206946542980843, + 625883007765001, + 2531730607197406, + ]), + y_minus_x: FieldElement51([ + 1076287717051609, + 1114455570543035, + 187297059715481, + 250446884292121, + 1885187512550540, + ]), + xy2d: FieldElement51([ + 902497362940219, + 76749815795675, + 1657927525633846, + 1420238379745202, + 1340321636548352, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1129576631190765, + 3533793823712575, + 996844254743017, + 2509676177174497, + 3402650555740265, + ]), + y_minus_x: FieldElement51([ + 628740660038789, + 1943038498527841, + 467786347793886, + 1093341428303375, + 235413859513003, + ]), + xy2d: FieldElement51([ + 237425418909360, + 469614029179605, + 1512389769174935, + 1241726368345357, + 441602891065214, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3988217766743784, + 726531315520507, + 1833335034432527, + 1629442561574747, + 2876218732971333, + ]), + y_minus_x: FieldElement51([ + 1960754663920689, + 497040957888962, + 1909832851283095, + 1271432136996826, + 2219780368020940, + ]), + xy2d: FieldElement51([ + 1537037379417136, + 1358865369268262, + 2130838645654099, + 828733687040705, + 1999987652890901, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 629042105241795, + 1098854999137608, + 887281544569320, + 3674901833560025, + 2259711072636808, + ]), + y_minus_x: FieldElement51([ + 1811562332665373, + 1501882019007673, + 2213763501088999, + 359573079719636, + 36370565049116, + ]), + xy2d: FieldElement51([ + 218907117361280, + 1209298913016966, + 1944312619096112, + 1130690631451061, + 1342327389191701, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1369976867854685, + 1396479602419169, + 4017456468084104, + 2203659200586298, + 3250127649802489, + ]), + y_minus_x: FieldElement51([ + 2230701885562825, + 1348173180338974, + 2172856128624598, + 1426538746123771, + 444193481326151, + ]), + xy2d: FieldElement51([ + 784210426627951, + 918204562375674, + 1284546780452985, + 1324534636134684, + 1872449409642708, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2571438643225542, + 2848082470493653, + 2037902696412607, + 1557219121643918, + 341938082688094, + ]), + y_minus_x: FieldElement51([ + 1901860206695915, + 2004489122065736, + 1625847061568236, + 973529743399879, + 2075287685312905, + ]), + xy2d: FieldElement51([ + 1371853944110545, + 1042332820512553, + 1949855697918254, + 1791195775521505, + 37487364849293, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 687200189577836, + 1082536651125675, + 2896024754556794, + 2592723009743198, + 2595381160432643, + ]), + y_minus_x: FieldElement51([ + 2082717129583892, + 27829425539422, + 145655066671970, + 1690527209845512, + 1865260509673478, + ]), + xy2d: FieldElement51([ + 1059729620568824, + 2163709103470266, + 1440302280256872, + 1769143160546397, + 869830310425069, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3861316033464273, + 777277757338816, + 2101121130363987, + 550762194946473, + 1905542338659364, + ]), + y_minus_x: FieldElement51([ + 2024821921041576, + 426948675450149, + 595133284085473, + 471860860885970, + 600321679413000, + ]), + xy2d: FieldElement51([ + 598474602406721, + 1468128276358244, + 1191923149557635, + 1501376424093216, + 1281662691293476, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1721138489890688, + 1264336102277790, + 2684864359106535, + 1359988423149465, + 3813671107094695, + ]), + y_minus_x: FieldElement51([ + 719520245587143, + 393380711632345, + 132350400863381, + 1543271270810729, + 1819543295798660, + ]), + xy2d: FieldElement51([ + 396397949784152, + 1811354474471839, + 1362679985304303, + 2117033964846756, + 498041172552279, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1812471844975748, + 1856491995543149, + 126579494584102, + 3288044672967868, + 1975108050082549, + ]), + y_minus_x: FieldElement51([ + 650623932407995, + 1137551288410575, + 2125223403615539, + 1725658013221271, + 2134892965117796, + ]), + xy2d: FieldElement51([ + 522584000310195, + 1241762481390450, + 1743702789495384, + 2227404127826575, + 1686746002148897, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 427904865186293, + 1703211129693455, + 1585368107547509, + 3688784302429584, + 3012988348299225, + ]), + y_minus_x: FieldElement51([ + 318101947455002, + 248138407995851, + 1481904195303927, + 309278454311197, + 1258516760217879, + ]), + xy2d: FieldElement51([ + 1275068538599310, + 513726919533379, + 349926553492294, + 688428871968420, + 1702400196000666, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3313663849950481, + 3213411074010628, + 2573659446386085, + 3297400443644764, + 1985130202504037, + ]), + y_minus_x: FieldElement51([ + 1558816436882417, + 1962896332636523, + 1337709822062152, + 1501413830776938, + 294436165831932, + ]), + xy2d: FieldElement51([ + 818359826554971, + 1862173000996177, + 626821592884859, + 573655738872376, + 1749691246745455, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1988022651432119, + 3333911312271288, + 1834020786104820, + 3706626690108935, + 692929915223121, + ]), + y_minus_x: FieldElement51([ + 2146513703733331, + 584788900394667, + 464965657279958, + 2183973639356127, + 238371159456790, + ]), + xy2d: FieldElement51([ + 1129007025494441, + 2197883144413266, + 265142755578169, + 971864464758890, + 1983715884903702, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1291366624493056, + 2633256531874362, + 1711482489312443, + 1815233647702022, + 3144079596677715, + ]), + y_minus_x: FieldElement51([ + 444548969917454, + 1452286453853356, + 2113731441506810, + 645188273895859, + 810317625309512, + ]), + xy2d: FieldElement51([ + 2242724082797924, + 1373354730327868, + 1006520110883049, + 2147330369940688, + 1151816104883620, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3997520014069025, + 4163522956860564, + 2056329390702073, + 2607026987995097, + 3131032608056347, + ]), + y_minus_x: FieldElement51([ + 163723479936298, + 115424889803150, + 1156016391581227, + 1894942220753364, + 1970549419986329, + ]), + xy2d: FieldElement51([ + 681981452362484, + 267208874112496, + 1374683991933094, + 638600984916117, + 646178654558546, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2265178468539480, + 2358037120714814, + 1944412051589650, + 4093776581610705, + 2482502633520820, + ]), + y_minus_x: FieldElement51([ + 260683893467075, + 854060306077237, + 913639551980112, + 4704576840123, + 280254810808712, + ]), + xy2d: FieldElement51([ + 715374893080287, + 1173334812210491, + 1806524662079626, + 1894596008000979, + 398905715033393, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2751826223412909, + 3848231101880618, + 1420380351989369, + 3237011375206737, + 392444930785632, + ]), + y_minus_x: FieldElement51([ + 2096421546958141, + 1922523000950363, + 789831022876840, + 427295144688779, + 320923973161730, + ]), + xy2d: FieldElement51([ + 1927770723575450, + 1485792977512719, + 1850996108474547, + 551696031508956, + 2126047405475647, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2112099158080129, + 2994370617594963, + 2258284371762679, + 1951119898618915, + 2344890196388664, + ]), + y_minus_x: FieldElement51([ + 383905201636970, + 859946997631870, + 855623867637644, + 1017125780577795, + 794250831877809, + ]), + xy2d: FieldElement51([ + 77571826285752, + 999304298101753, + 487841111777762, + 1038031143212339, + 339066367948762, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2926794589205781, + 2517835660016036, + 826951213393477, + 1405007746162285, + 1781791018620876, + ]), + y_minus_x: FieldElement51([ + 1001412661522686, + 348196197067298, + 1666614366723946, + 888424995032760, + 580747687801357, + ]), + xy2d: FieldElement51([ + 1939560076207777, + 1409892634407635, + 552574736069277, + 383854338280405, + 190706709864139, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2177087163428741, + 1439255351721944, + 3459870654068041, + 2230616362004768, + 1396886392021913, + ]), + y_minus_x: FieldElement51([ + 676962063230039, + 1880275537148808, + 2046721011602706, + 888463247083003, + 1318301552024067, + ]), + xy2d: FieldElement51([ + 1466980508178206, + 617045217998949, + 652303580573628, + 757303753529064, + 207583137376902, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3762856566592150, + 2357202940576524, + 2745234706458093, + 1091943425335975, + 1802717338077427, + ]), + y_minus_x: FieldElement51([ + 1853982405405128, + 1878664056251147, + 1528011020803992, + 1019626468153565, + 1128438412189035, + ]), + xy2d: FieldElement51([ + 1963939888391106, + 293456433791664, + 697897559513649, + 985882796904380, + 796244541237972, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2668570812315008, + 2641455366112301, + 1314476859406755, + 1749382513022778, + 3413705412424739, + ]), + y_minus_x: FieldElement51([ + 1428358296490651, + 1027115282420478, + 304840698058337, + 441410174026628, + 1819358356278573, + ]), + xy2d: FieldElement51([ + 204943430200135, + 1554861433819175, + 216426658514651, + 264149070665950, + 2047097371738319, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1934415182909015, + 1393285083565062, + 2768209145458208, + 3409490548679139, + 2372839480279515, + ]), + y_minus_x: FieldElement51([ + 662035583584445, + 286736105093098, + 1131773000510616, + 818494214211439, + 472943792054479, + ]), + xy2d: FieldElement51([ + 665784778135882, + 1893179629898606, + 808313193813106, + 276797254706413, + 1563426179676396, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 945205108984213, + 2778077376644543, + 1324180513733565, + 1666970227868664, + 2405347422974421, + ]), + y_minus_x: FieldElement51([ + 2031433403516252, + 203996615228162, + 170487168837083, + 981513604791390, + 843573964916831, + ]), + xy2d: FieldElement51([ + 1476570093962618, + 838514669399805, + 1857930577281364, + 2017007352225784, + 317085545220047, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1461557121912823, + 1600674043318359, + 2157134900399597, + 1670641601940616, + 2379565397488531, + ]), + y_minus_x: FieldElement51([ + 1293543509393474, + 2143624609202546, + 1058361566797508, + 214097127393994, + 946888515472729, + ]), + xy2d: FieldElement51([ + 357067959932916, + 1290876214345711, + 521245575443703, + 1494975468601005, + 800942377643885, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2817916472785262, + 820247422481739, + 994464017954148, + 2578957425371613, + 2344391131796991, + ]), + y_minus_x: FieldElement51([ + 617256647603209, + 1652107761099439, + 1857213046645471, + 1085597175214970, + 817432759830522, + ]), + xy2d: FieldElement51([ + 771808161440705, + 1323510426395069, + 680497615846440, + 851580615547985, + 1320806384849017, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1219260086131896, + 2898968820282063, + 2331400938444953, + 2161724213426747, + 2656661710745446, + ]), + y_minus_x: FieldElement51([ + 1327968293887866, + 1335500852943256, + 1401587164534264, + 558137311952440, + 1551360549268902, + ]), + xy2d: FieldElement51([ + 417621685193956, + 1429953819744454, + 396157358457099, + 1940470778873255, + 214000046234152, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1268047918491954, + 2172375426948536, + 1533916099229249, + 1761293575457130, + 3842422480712013, + ]), + y_minus_x: FieldElement51([ + 1627072914981959, + 2211603081280073, + 1912369601616504, + 1191770436221309, + 2187309757525860, + ]), + xy2d: FieldElement51([ + 1149147819689533, + 378692712667677, + 828475842424202, + 2218619146419342, + 70688125792186, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3551539230764990, + 3690416477138006, + 3788528892189659, + 2053896748919837, + 3260220846276494, + ]), + y_minus_x: FieldElement51([ + 2040723824657366, + 399555637875075, + 632543375452995, + 872649937008051, + 1235394727030233, + ]), + xy2d: FieldElement51([ + 2211311599327900, + 2139787259888175, + 938706616835350, + 12609661139114, + 2081897930719789, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1324994503390431, + 2588782144267879, + 1183998925654176, + 3343454479598522, + 2300527487656566, + ]), + y_minus_x: FieldElement51([ + 1845522914617879, + 1222198248335542, + 150841072760134, + 1927029069940982, + 1189913404498011, + ]), + xy2d: FieldElement51([ + 1079559557592645, + 2215338383666441, + 1903569501302605, + 49033973033940, + 305703433934152, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2346453219102138, + 3637921163538246, + 3313930291577009, + 2288353761164521, + 3085469462634093, + ]), + y_minus_x: FieldElement51([ + 1432015813136298, + 440364795295369, + 1395647062821501, + 1976874522764578, + 934452372723352, + ]), + xy2d: FieldElement51([ + 1296625309219774, + 2068273464883862, + 1858621048097805, + 1492281814208508, + 2235868981918946, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1490330266465551, + 1858795661361448, + 3688040948655011, + 2546373032584894, + 3459939824714180, + ]), + y_minus_x: FieldElement51([ + 1282462923712748, + 741885683986255, + 2027754642827561, + 518989529541027, + 1826610009555945, + ]), + xy2d: FieldElement51([ + 1525827120027511, + 723686461809551, + 1597702369236987, + 244802101764964, + 1502833890372311, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2365421849929742, + 3485539881431101, + 2925909765963743, + 2114345180342964, + 2418564326541511, + ]), + y_minus_x: FieldElement51([ + 2041668749310338, + 2184405322203901, + 1633400637611036, + 2110682505536899, + 2048144390084644, + ]), + xy2d: FieldElement51([ + 503058759232932, + 760293024620937, + 2027152777219493, + 666858468148475, + 1539184379870952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1916168475367211, + 3167426246226591, + 883217071712574, + 363427871374304, + 1976029821251593, + ]), + y_minus_x: FieldElement51([ + 678039535434506, + 570587290189340, + 1605302676614120, + 2147762562875701, + 1706063797091704, + ]), + xy2d: FieldElement51([ + 1439489648586438, + 2194580753290951, + 832380563557396, + 561521973970522, + 584497280718389, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2439789269177838, + 681223515948274, + 1933493571072456, + 1872921007304880, + 2739962177820919, + ]), + y_minus_x: FieldElement51([ + 1413466089534451, + 410844090765630, + 1397263346404072, + 408227143123410, + 1594561803147811, + ]), + xy2d: FieldElement51([ + 2102170800973153, + 719462588665004, + 1479649438510153, + 1097529543970028, + 1302363283777685, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3193865531532443, + 3321113493038208, + 2007341951411050, + 2322773230131539, + 1419433790163705, + ]), + y_minus_x: FieldElement51([ + 1146565545556377, + 1661971299445212, + 406681704748893, + 564452436406089, + 1109109865829139, + ]), + xy2d: FieldElement51([ + 2214421081775077, + 1165671861210569, + 1890453018796184, + 3556249878661, + 442116172656317, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3005630360306059, + 1666955059895018, + 1530775289309243, + 3371786842789394, + 2164156153857579, + ]), + y_minus_x: FieldElement51([ + 615171919212796, + 1523849404854568, + 854560460547503, + 2067097370290715, + 1765325848586042, + ]), + xy2d: FieldElement51([ + 1094538949313667, + 1796592198908825, + 870221004284388, + 2025558921863561, + 1699010892802384, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1951351290725195, + 1916457206844795, + 2449824998123274, + 1909076887557594, + 1938542290318919, + ]), + y_minus_x: FieldElement51([ + 1014323197538413, + 869150639940606, + 1756009942696599, + 1334952557375672, + 1544945379082874, + ]), + xy2d: FieldElement51([ + 764055910920305, + 1603590757375439, + 146805246592357, + 1843313433854297, + 954279890114939, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 80113526615731, + 764536758732259, + 3306939158785481, + 2721052465444637, + 2869697326116762, + ]), + y_minus_x: FieldElement51([ + 74497112547268, + 740094153192149, + 1745254631717581, + 727713886503130, + 1283034364416928, + ]), + xy2d: FieldElement51([ + 525892105991110, + 1723776830270342, + 1476444848991936, + 573789489857760, + 133864092632978, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2794411533877810, + 1986812262899320, + 1162535242465837, + 2733298779828712, + 2796400347268869, + ]), + y_minus_x: FieldElement51([ + 64123227344372, + 1239927720647794, + 1360722983445904, + 222610813654661, + 62429487187991, + ]), + xy2d: FieldElement51([ + 1793193323953132, + 91096687857833, + 70945970938921, + 2158587638946380, + 1537042406482111, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1895854577604590, + 3646695522634664, + 1728548428495943, + 3392664713925397, + 2815445147288308, + ]), + y_minus_x: FieldElement51([ + 141358280486863, + 91435889572504, + 1087208572552643, + 1829599652522921, + 1193307020643647, + ]), + xy2d: FieldElement51([ + 1611230858525381, + 950720175540785, + 499589887488610, + 2001656988495019, + 88977313255908, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3440880315164906, + 2184348804772596, + 3292618539427567, + 2018318290311833, + 1712060030915354, + ]), + y_minus_x: FieldElement51([ + 873966876953756, + 1090638350350440, + 1708559325189137, + 672344594801910, + 1320437969700239, + ]), + xy2d: FieldElement51([ + 1508590048271766, + 1131769479776094, + 101550868699323, + 428297785557897, + 561791648661744, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3008217384184691, + 2489682092917849, + 2136263418594015, + 1701968045454886, + 2955512998822720, + ]), + y_minus_x: FieldElement51([ + 1781187809325462, + 1697624151492346, + 1381393690939988, + 175194132284669, + 1483054666415238, + ]), + xy2d: FieldElement51([ + 2175517777364616, + 708781536456029, + 955668231122942, + 1967557500069555, + 2021208005604118, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3366935780292116, + 2476017186636029, + 915967306279221, + 593866251291540, + 2813546907893254, + ]), + y_minus_x: FieldElement51([ + 1443163092879439, + 391875531646162, + 2180847134654632, + 464538543018753, + 1594098196837178, + ]), + xy2d: FieldElement51([ + 850858855888869, + 319436476624586, + 327807784938441, + 740785849558761, + 17128415486016, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2132756334090048, + 2788047633840893, + 2300706964962114, + 2860273011285942, + 3513489358708031, + ]), + y_minus_x: FieldElement51([ + 1525176236978354, + 974205476721062, + 293436255662638, + 148269621098039, + 137961998433963, + ]), + xy2d: FieldElement51([ + 1121075518299410, + 2071745529082111, + 1265567917414828, + 1648196578317805, + 496232102750820, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2374121042985030, + 3274721891178932, + 2001275453369483, + 2017441881607947, + 3245005694463250, + ]), + y_minus_x: FieldElement51([ + 654925550560074, + 1168810995576858, + 575655959430926, + 905758704861388, + 496774564663534, + ]), + xy2d: FieldElement51([ + 1954109525779738, + 2117022646152485, + 338102630417180, + 1194140505732026, + 107881734943492, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1714785840001267, + 4288299832366837, + 1876380234251965, + 2056717182974196, + 1645855254384642, + ]), + y_minus_x: FieldElement51([ + 106431476499341, + 62482972120563, + 1513446655109411, + 807258751769522, + 538491469114, + ]), + xy2d: FieldElement51([ + 2002850762893643, + 1243624520538135, + 1486040410574605, + 2184752338181213, + 378495998083531, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 922510868424903, + 1089502620807680, + 402544072617374, + 1131446598479839, + 1290278588136533, + ]), + y_minus_x: FieldElement51([ + 1867998812076769, + 715425053580701, + 39968586461416, + 2173068014586163, + 653822651801304, + ]), + xy2d: FieldElement51([ + 162892278589453, + 182585796682149, + 75093073137630, + 497037941226502, + 133871727117371, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4166396390264918, + 1608999621851577, + 1987629837704609, + 1519655314857977, + 1819193753409464, + ]), + y_minus_x: FieldElement51([ + 1949315551096831, + 1069003344994464, + 1939165033499916, + 1548227205730856, + 1933767655861407, + ]), + xy2d: FieldElement51([ + 1730519386931635, + 1393284965610134, + 1597143735726030, + 416032382447158, + 1429665248828629, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 360275475604546, + 2799635544748326, + 2467160717872776, + 2848446553564254, + 2584509464110332, + ]), + y_minus_x: FieldElement51([ + 47602113726801, + 1522314509708010, + 437706261372925, + 814035330438027, + 335930650933545, + ]), + xy2d: FieldElement51([ + 1291597595523886, + 1058020588994081, + 402837842324045, + 1363323695882781, + 2105763393033193, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2361321796251793, + 3967057562270386, + 1112231216891515, + 2046641005101484, + 2386048970842261, + ]), + y_minus_x: FieldElement51([ + 2156991030936798, + 2227544497153325, + 1869050094431622, + 754875860479115, + 1754242344267058, + ]), + xy2d: FieldElement51([ + 1846089562873800, + 98894784984326, + 1412430299204844, + 171351226625762, + 1100604760929008, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2335972195815721, + 2751510784385293, + 425749630620777, + 1762872794206857, + 2864642415813208, + ]), + y_minus_x: FieldElement51([ + 868309334532756, + 1703010512741873, + 1952690008738057, + 4325269926064, + 2071083554962116, + ]), + xy2d: FieldElement51([ + 523094549451158, + 401938899487815, + 1407690589076010, + 2022387426254453, + 158660516411257, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 612867287630009, + 2700012425789062, + 2823428891104443, + 1466796750919375, + 1728478129663858, + ]), + y_minus_x: FieldElement51([ + 1723848973783452, + 2208822520534681, + 1718748322776940, + 1974268454121942, + 1194212502258141, + ]), + xy2d: FieldElement51([ + 1254114807944608, + 977770684047110, + 2010756238954993, + 1783628927194099, + 1525962994408256, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2484263871921055, + 1948628555342433, + 1835348780427694, + 1031609499437291, + 2316271920603621, + ]), + y_minus_x: FieldElement51([ + 767338676040683, + 754089548318405, + 1523192045639075, + 435746025122062, + 512692508440385, + ]), + xy2d: FieldElement51([ + 1255955808701983, + 1700487367990941, + 1166401238800299, + 1175121994891534, + 1190934801395380, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2600943821853521, + 1337012557669161, + 1475912332999108, + 3573418268585706, + 2299411105589567, + ]), + y_minus_x: FieldElement51([ + 877519947135419, + 2172838026132651, + 272304391224129, + 1655143327559984, + 886229406429814, + ]), + xy2d: FieldElement51([ + 375806028254706, + 214463229793940, + 572906353144089, + 572168269875638, + 697556386112979, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1168827102357825, + 823864273033637, + 4323338565789945, + 788062026895923, + 2851378154428610, + ]), + y_minus_x: FieldElement51([ + 1948116082078088, + 2054898304487796, + 2204939184983900, + 210526805152138, + 786593586607626, + ]), + xy2d: FieldElement51([ + 1915320147894736, + 156481169009469, + 655050471180417, + 592917090415421, + 2165897438660879, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1726336468579724, + 1119932070398949, + 1929199510967666, + 2285718602008207, + 1836837863503149, + ]), + y_minus_x: FieldElement51([ + 829996854845988, + 217061778005138, + 1686565909803640, + 1346948817219846, + 1723823550730181, + ]), + xy2d: FieldElement51([ + 384301494966394, + 687038900403062, + 2211195391021739, + 254684538421383, + 1245698430589680, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1247567493562669, + 4229981908141095, + 2435671288478202, + 806570235643434, + 2540261331753164, + ]), + y_minus_x: FieldElement51([ + 1449077384734201, + 38285445457996, + 2136537659177832, + 2146493000841573, + 725161151123125, + ]), + xy2d: FieldElement51([ + 1201928866368855, + 800415690605445, + 1703146756828343, + 997278587541744, + 1858284414104014, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2608268623334125, + 3034173730618399, + 1718002439402869, + 3644022065904502, + 663171266061950, + ]), + y_minus_x: FieldElement51([ + 759628738230460, + 1012693474275852, + 353780233086498, + 246080061387552, + 2030378857679162, + ]), + xy2d: FieldElement51([ + 2040672435071076, + 888593182036908, + 1298443657189359, + 1804780278521327, + 354070726137060, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1894938527423184, + 3715012855162525, + 2726210319182898, + 2499094776718546, + 877975941029127, + ]), + y_minus_x: FieldElement51([ + 207937160991127, + 12966911039119, + 820997788283092, + 1010440472205286, + 1701372890140810, + ]), + xy2d: FieldElement51([ + 218882774543183, + 533427444716285, + 1233243976733245, + 435054256891319, + 1509568989549904, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4140638349397055, + 3303977572025869, + 3465353617009382, + 2420981822812579, + 2715174081801119, + ]), + y_minus_x: FieldElement51([ + 299137589460312, + 1594371588983567, + 868058494039073, + 257771590636681, + 1805012993142921, + ]), + xy2d: FieldElement51([ + 1806842755664364, + 2098896946025095, + 1356630998422878, + 1458279806348064, + 347755825962072, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1402334161391744, + 3811883484731547, + 1008585416617746, + 1147797150908892, + 1420416683642459, + ]), + y_minus_x: FieldElement51([ + 665506704253369, + 273770475169863, + 799236974202630, + 848328990077558, + 1811448782807931, + ]), + xy2d: FieldElement51([ + 1468412523962641, + 771866649897997, + 1931766110147832, + 799561180078482, + 524837559150077, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2223212657821831, + 2882216061048914, + 2144451165500327, + 3068710944633039, + 3276150872095279, + ]), + y_minus_x: FieldElement51([ + 1266603897524861, + 156378408858100, + 1275649024228779, + 447738405888420, + 253186462063095, + ]), + xy2d: FieldElement51([ + 2022215964509735, + 136144366993649, + 1800716593296582, + 1193970603800203, + 871675847064218, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1862751661970309, + 851596246739884, + 1519315554814041, + 3794598280232697, + 3669775149586767, + ]), + y_minus_x: FieldElement51([ + 1228168094547481, + 334133883362894, + 587567568420081, + 433612590281181, + 603390400373205, + ]), + xy2d: FieldElement51([ + 121893973206505, + 1843345804916664, + 1703118377384911, + 497810164760654, + 101150811654673, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2710146069631716, + 2542709749304591, + 1452768413850678, + 2802722688939463, + 1537286854336537, + ]), + y_minus_x: FieldElement51([ + 584322311184395, + 380661238802118, + 114839394528060, + 655082270500073, + 2111856026034852, + ]), + xy2d: FieldElement51([ + 996965581008991, + 2148998626477022, + 1012273164934654, + 1073876063914522, + 1688031788934939, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3175286832534829, + 2085106799623354, + 2779882615305384, + 1606206360876187, + 2987706905397772, + ]), + y_minus_x: FieldElement51([ + 1697697887804317, + 1335343703828273, + 831288615207040, + 949416685250051, + 288760277392022, + ]), + xy2d: FieldElement51([ + 1419122478109648, + 1325574567803701, + 602393874111094, + 2107893372601700, + 1314159682671307, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2201150872731785, + 2180241023425241, + 2349463270108411, + 1633405770247823, + 3100744856129234, + ]), + y_minus_x: FieldElement51([ + 1173339555550611, + 818605084277583, + 47521504364289, + 924108720564965, + 735423405754506, + ]), + xy2d: FieldElement51([ + 830104860549448, + 1886653193241086, + 1600929509383773, + 1475051275443631, + 286679780900937, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3828911108518224, + 3282698983453994, + 2396700729978777, + 4216472406664814, + 2820189914640497, + ]), + y_minus_x: FieldElement51([ + 278388655910247, + 487143369099838, + 927762205508727, + 181017540174210, + 1616886700741287, + ]), + xy2d: FieldElement51([ + 1191033906638969, + 940823957346562, + 1606870843663445, + 861684761499847, + 658674867251089, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1875032594195527, + 1427106132796197, + 2976536204647406, + 3153660325729987, + 2887068310954007, + ]), + y_minus_x: FieldElement51([ + 622869792298357, + 1903919278950367, + 1922588621661629, + 1520574711600434, + 1087100760174640, + ]), + xy2d: FieldElement51([ + 25465949416618, + 1693639527318811, + 1526153382657203, + 125943137857169, + 145276964043999, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2466539671654587, + 920212862967914, + 4191701364657517, + 3463662605460468, + 2336897329405367, + ]), + y_minus_x: FieldElement51([ + 2006245852772938, + 734762734836159, + 254642929763427, + 1406213292755966, + 239303749517686, + ]), + xy2d: FieldElement51([ + 1619678837192149, + 1919424032779215, + 1357391272956794, + 1525634040073113, + 1310226789796241, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3292563523447371, + 1704449869235351, + 2857062884141577, + 1998838089036354, + 1312142911487502, + ]), + y_minus_x: FieldElement51([ + 1996723311435669, + 1844342766567060, + 985455700466044, + 1165924681400960, + 311508689870129, + ]), + xy2d: FieldElement51([ + 43173156290518, + 2202883069785309, + 1137787467085917, + 1733636061944606, + 1394992037553852, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 670078326344559, + 2807454838744604, + 2723759199967685, + 2141455487356408, + 849015953823125, + ]), + y_minus_x: FieldElement51([ + 2197214573372804, + 794254097241315, + 1030190060513737, + 267632515541902, + 2040478049202624, + ]), + xy2d: FieldElement51([ + 1812516004670529, + 1609256702920783, + 1706897079364493, + 258549904773295, + 996051247540686, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1540374301420565, + 1764656898914615, + 1810104162020396, + 3175608592848336, + 2916189887881826, + ]), + y_minus_x: FieldElement51([ + 1323460699404750, + 1262690757880991, + 871777133477900, + 1060078894988977, + 1712236889662886, + ]), + xy2d: FieldElement51([ + 1696163952057966, + 1391710137550823, + 608793846867416, + 1034391509472039, + 1780770894075012, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1367603834210822, + 4383788460268472, + 890353773628143, + 1908908219165595, + 2522636708938139, + ]), + y_minus_x: FieldElement51([ + 597536315471731, + 40375058742586, + 1942256403956049, + 1185484645495932, + 312666282024145, + ]), + xy2d: FieldElement51([ + 1919411405316294, + 1234508526402192, + 1066863051997083, + 1008444703737597, + 1348810787701552, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2102881477513865, + 3822074379630609, + 1573617900503707, + 2270462449417831, + 2232324307922097, + ]), + y_minus_x: FieldElement51([ + 1853931367696942, + 8107973870707, + 350214504129299, + 775206934582587, + 1752317649166792, + ]), + xy2d: FieldElement51([ + 1417148368003523, + 721357181628282, + 505725498207811, + 373232277872983, + 261634707184480, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2186733281493248, + 2250694917008620, + 1014829812957440, + 2731797975137637, + 2335366007561721, + ]), + y_minus_x: FieldElement51([ + 1268116367301224, + 560157088142809, + 802626839600444, + 2210189936605713, + 1129993785579988, + ]), + xy2d: FieldElement51([ + 615183387352312, + 917611676109240, + 878893615973325, + 978940963313282, + 938686890583575, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 522024729211672, + 3296859129001056, + 1892245413707789, + 1907891107684253, + 2059998109500714, + ]), + y_minus_x: FieldElement51([ + 1799679152208884, + 912132775900387, + 25967768040979, + 432130448590461, + 274568990261996, + ]), + xy2d: FieldElement51([ + 98698809797682, + 2144627600856209, + 1907959298569602, + 811491302610148, + 1262481774981493, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1791451399743152, + 1713538728337276, + 2370149810942738, + 1882306388849953, + 158235232210248, + ]), + y_minus_x: FieldElement51([ + 1217809823321928, + 2173947284933160, + 1986927836272325, + 1388114931125539, + 12686131160169, + ]), + xy2d: FieldElement51([ + 1650875518872272, + 1136263858253897, + 1732115601395988, + 734312880662190, + 1252904681142109, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2624786269799113, + 2777230729143418, + 2116279931702134, + 2753222527273063, + 1907002872974924, + ]), + y_minus_x: FieldElement51([ + 803147181835288, + 868941437997146, + 316299302989663, + 943495589630550, + 571224287904572, + ]), + xy2d: FieldElement51([ + 227742695588364, + 1776969298667369, + 628602552821802, + 457210915378118, + 2041906378111140, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 815000523470260, + 3164885502413555, + 3303859931956420, + 1345536665214222, + 541623413135555, + ]), + y_minus_x: FieldElement51([ + 1580216071604333, + 1877997504342444, + 857147161260913, + 703522726778478, + 2182763974211603, + ]), + xy2d: FieldElement51([ + 1870080310923419, + 71988220958492, + 1783225432016732, + 615915287105016, + 1035570475990230, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2982787564515398, + 857613889540279, + 1083813157271766, + 1002817255970169, + 1719228484436074, + ]), + y_minus_x: FieldElement51([ + 377616581647602, + 1581980403078513, + 804044118130621, + 2034382823044191, + 643844048472185, + ]), + xy2d: FieldElement51([ + 176957326463017, + 1573744060478586, + 528642225008045, + 1816109618372371, + 1515140189765006, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1888911448245718, + 3638910709296328, + 4176303607751676, + 1731539523700948, + 2230378382645454, + ]), + y_minus_x: FieldElement51([ + 443392177002051, + 233793396845137, + 2199506622312416, + 1011858706515937, + 974676837063129, + ]), + xy2d: FieldElement51([ + 1846351103143623, + 1949984838808427, + 671247021915253, + 1946756846184401, + 1929296930380217, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 849646212451983, + 1410198775302919, + 2325567699868943, + 1641663456615811, + 3014056086137659, + ]), + y_minus_x: FieldElement51([ + 692017667358279, + 723305578826727, + 1638042139863265, + 748219305990306, + 334589200523901, + ]), + xy2d: FieldElement51([ + 22893968530686, + 2235758574399251, + 1661465835630252, + 925707319443452, + 1203475116966621, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3053098849470395, + 3985092410411378, + 1664508947088595, + 2719548934677170, + 3899298398220870, + ]), + y_minus_x: FieldElement51([ + 903105258014366, + 427141894933047, + 561187017169777, + 1884330244401954, + 1914145708422219, + ]), + xy2d: FieldElement51([ + 1344191060517578, + 1960935031767890, + 1518838929955259, + 1781502350597190, + 1564784025565682, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2925523165433334, + 1979969272514922, + 3427087126180756, + 1187589090978665, + 1881897672213940, + ]), + y_minus_x: FieldElement51([ + 1917185587363432, + 1098342571752737, + 5935801044414, + 2000527662351839, + 1538640296181569, + ]), + xy2d: FieldElement51([ + 2495540013192, + 678856913479236, + 224998292422872, + 219635787698590, + 1972465269000940, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 271413961212179, + 3604851875156899, + 2596511104968730, + 2014925838520661, + 2006221033113941, + ]), + y_minus_x: FieldElement51([ + 194583029968109, + 514316781467765, + 829677956235672, + 1676415686873082, + 810104584395840, + ]), + xy2d: FieldElement51([ + 1980510813313589, + 1948645276483975, + 152063780665900, + 129968026417582, + 256984195613935, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1860190562533083, + 1936576191345085, + 2712900106391212, + 1811043097042829, + 3209286562992083, + ]), + y_minus_x: FieldElement51([ + 796664815624365, + 1543160838872951, + 1500897791837765, + 1667315977988401, + 599303877030711, + ]), + xy2d: FieldElement51([ + 1151480509533204, + 2136010406720455, + 738796060240027, + 319298003765044, + 1150614464349587, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1731069268103131, + 2987442261301335, + 1364750481334267, + 2669032653668119, + 3178908082812908, + ]), + y_minus_x: FieldElement51([ + 1017222050227968, + 1987716148359, + 2234319589635701, + 621282683093392, + 2132553131763026, + ]), + xy2d: FieldElement51([ + 1567828528453324, + 1017807205202360, + 565295260895298, + 829541698429100, + 307243822276582, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 249079270936229, + 1501514259790706, + 3199709537890096, + 944551802437486, + 2804458577667728, + ]), + y_minus_x: FieldElement51([ + 2089966982947227, + 1854140343916181, + 2151980759220007, + 2139781292261749, + 158070445864917, + ]), + xy2d: FieldElement51([ + 1338766321464554, + 1906702607371284, + 1519569445519894, + 115384726262267, + 1393058953390992, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3616421371950629, + 3764188048593604, + 1926731583198685, + 2041482526432505, + 3172200936019022, + ]), + y_minus_x: FieldElement51([ + 1884844597333588, + 601480070269079, + 620203503079537, + 1079527400117915, + 1202076693132015, + ]), + xy2d: FieldElement51([ + 840922919763324, + 727955812569642, + 1303406629750194, + 522898432152867, + 294161410441865, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2605560604520539, + 1598361541848742, + 3374705511887547, + 4174333403844152, + 2670907514351827, + ]), + y_minus_x: FieldElement51([ + 359856369838236, + 180914355488683, + 861726472646627, + 218807937262986, + 575626773232501, + ]), + xy2d: FieldElement51([ + 755467689082474, + 909202735047934, + 730078068932500, + 936309075711518, + 2007798262842972, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1609384177904054, + 2614544999293875, + 1335318541768200, + 3052765584121496, + 2799677792952659, + ]), + y_minus_x: FieldElement51([ + 984339177776787, + 815727786505884, + 1645154585713747, + 1659074964378553, + 1686601651984156, + ]), + xy2d: FieldElement51([ + 1697863093781930, + 599794399429786, + 1104556219769607, + 830560774794755, + 12812858601017, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1168737550514982, + 897832437380552, + 463140296333799, + 2554364413707795, + 2008360505135500, + ]), + y_minus_x: FieldElement51([ + 1856930662813910, + 678090852002597, + 1920179140755167, + 1259527833759868, + 55540971895511, + ]), + xy2d: FieldElement51([ + 1158643631044921, + 476554103621892, + 178447851439725, + 1305025542653569, + 103433927680625, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2176793111709008, + 3828525530035639, + 2009350167273522, + 2012390194631546, + 2125297410909580, + ]), + y_minus_x: FieldElement51([ + 825403285195098, + 2144208587560784, + 1925552004644643, + 1915177840006985, + 1015952128947864, + ]), + xy2d: FieldElement51([ + 1807108316634472, + 1534392066433717, + 347342975407218, + 1153820745616376, + 7375003497471, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3234860815484973, + 2683011703586488, + 2201903782961092, + 3069193724749589, + 2214616493042166, + ]), + y_minus_x: FieldElement51([ + 228567918409756, + 865093958780220, + 358083886450556, + 159617889659320, + 1360637926292598, + ]), + xy2d: FieldElement51([ + 234147501399755, + 2229469128637390, + 2175289352258889, + 1397401514549353, + 1885288963089922, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3363562226636810, + 2504649386192636, + 3300514047508588, + 2397910909286693, + 1237505378776769, + ]), + y_minus_x: FieldElement51([ + 1113790697840279, + 1051167139966244, + 1045930658550944, + 2011366241542643, + 1686166824620755, + ]), + xy2d: FieldElement51([ + 1054097349305049, + 1872495070333352, + 182121071220717, + 1064378906787311, + 100273572924182, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3558210666856834, + 1627717417672446, + 2302783034773665, + 1109249951172249, + 3122001602766640, + ]), + y_minus_x: FieldElement51([ + 104233794644221, + 1548919791188248, + 2224541913267306, + 2054909377116478, + 1043803389015153, + ]), + xy2d: FieldElement51([ + 216762189468802, + 707284285441622, + 190678557969733, + 973969342604308, + 1403009538434867, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3530824104723725, + 2596576648903557, + 2525521909702446, + 4086000250496689, + 634517197663803, + ]), + y_minus_x: FieldElement51([ + 343805853118335, + 1302216857414201, + 566872543223541, + 2051138939539004, + 321428858384280, + ]), + xy2d: FieldElement51([ + 470067171324852, + 1618629234173951, + 2000092177515639, + 7307679772789, + 1117521120249968, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2529951391976704, + 1810282338562946, + 1771599529530998, + 3635459223356879, + 2937173228157088, + ]), + y_minus_x: FieldElement51([ + 577009397403102, + 1791440261786291, + 2177643735971638, + 174546149911960, + 1412505077782326, + ]), + xy2d: FieldElement51([ + 893719721537457, + 1201282458018197, + 1522349501711173, + 58011597740583, + 1130406465887139, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 412607348255434, + 1280455764199780, + 2233277987330768, + 2265979894086913, + 2583384512102412, + ]), + y_minus_x: FieldElement51([ + 262483770854550, + 990511055108216, + 526885552771698, + 571664396646158, + 354086190278723, + ]), + xy2d: FieldElement51([ + 1820352417585487, + 24495617171480, + 1547899057533253, + 10041836186225, + 480457105094042, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2023310314989233, + 2889705151211129, + 2106474638900686, + 2809620524769320, + 1687858215057825, + ]), + y_minus_x: FieldElement51([ + 1144168702609745, + 604444390410187, + 1544541121756138, + 1925315550126027, + 626401428894002, + ]), + xy2d: FieldElement51([ + 1922168257351784, + 2018674099908659, + 1776454117494445, + 956539191509034, + 36031129147635, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2796444352433270, + 1039872944430373, + 3128550222815858, + 2962457525011798, + 3468752501170219, + ]), + y_minus_x: FieldElement51([ + 58242421545916, + 2035812695641843, + 2118491866122923, + 1191684463816273, + 46921517454099, + ]), + xy2d: FieldElement51([ + 272268252444639, + 1374166457774292, + 2230115177009552, + 1053149803909880, + 1354288411641016, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1857910905368338, + 1754729879288912, + 3137745277795125, + 1516096106802165, + 1602902393369811, + ]), + y_minus_x: FieldElement51([ + 1193437069800958, + 901107149704790, + 999672920611411, + 477584824802207, + 364239578697845, + ]), + xy2d: FieldElement51([ + 886299989548838, + 1538292895758047, + 1590564179491896, + 1944527126709657, + 837344427345298, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3006358179063534, + 1712186480903617, + 3955456640022779, + 3002110732175033, + 2770795853936147, + ]), + y_minus_x: FieldElement51([ + 1309847803895382, + 1462151862813074, + 211370866671570, + 1544595152703681, + 1027691798954090, + ]), + xy2d: FieldElement51([ + 803217563745370, + 1884799722343599, + 1357706345069218, + 2244955901722095, + 730869460037413, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2941099284981214, + 1831210565161070, + 3626987155270686, + 3358084791231418, + 1893781834054268, + ]), + y_minus_x: FieldElement51([ + 696351368613042, + 1494385251239250, + 738037133616932, + 636385507851544, + 927483222611406, + ]), + xy2d: FieldElement51([ + 1949114198209333, + 1104419699537997, + 783495707664463, + 1747473107602770, + 2002634765788641, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1607325776830197, + 2782683755100581, + 1451089452727894, + 3833490970768671, + 496100432831153, + ]), + y_minus_x: FieldElement51([ + 1068900648804224, + 2006891997072550, + 1134049269345549, + 1638760646180091, + 2055396084625778, + ]), + xy2d: FieldElement51([ + 2222475519314561, + 1870703901472013, + 1884051508440561, + 1344072275216753, + 1318025677799069, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 155711679280637, + 681100400509288, + 389811735211209, + 2135723811340709, + 2660533024889373, + ]), + y_minus_x: FieldElement51([ + 7813206966729, + 194444201427550, + 2071405409526507, + 1065605076176312, + 1645486789731291, + ]), + xy2d: FieldElement51([ + 16625790644959, + 1647648827778410, + 1579910185572704, + 436452271048548, + 121070048451050, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3289062842237779, + 2820185594063076, + 2549752917829677, + 3810384325616458, + 2238221839292470, + ]), + y_minus_x: FieldElement51([ + 190565267697443, + 672855706028058, + 338796554369226, + 337687268493904, + 853246848691734, + ]), + xy2d: FieldElement51([ + 1763863028400139, + 766498079432444, + 1321118624818005, + 69494294452268, + 858786744165651, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3543856582248253, + 1456632109855637, + 3352431060735432, + 1386133165675320, + 3484698163879000, + ]), + y_minus_x: FieldElement51([ + 366253102478259, + 525676242508811, + 1449610995265438, + 1183300845322183, + 185960306491545, + ]), + xy2d: FieldElement51([ + 28315355815982, + 460422265558930, + 1799675876678724, + 1969256312504498, + 1051823843138725, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2408714813047231, + 3857948219405196, + 1665208410108429, + 2569443092377519, + 1383783705665319, + ]), + y_minus_x: FieldElement51([ + 54684536365732, + 2210010038536222, + 1194984798155308, + 535239027773705, + 1516355079301361, + ]), + xy2d: FieldElement51([ + 1484387703771650, + 198537510937949, + 2186282186359116, + 617687444857508, + 647477376402122, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2147715541830533, + 2751832352131065, + 2898179830570073, + 2604027669016369, + 1488268620408051, + ]), + y_minus_x: FieldElement51([ + 159386186465542, + 1877626593362941, + 618737197060512, + 1026674284330807, + 1158121760792685, + ]), + xy2d: FieldElement51([ + 1744544377739822, + 1964054180355661, + 1685781755873170, + 2169740670377448, + 1286112621104591, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2333777063470241, + 3919742931398333, + 3920783633320113, + 1605016835177614, + 1353960708075544, + ]), + y_minus_x: FieldElement51([ + 1602253788689063, + 439542044889886, + 2220348297664483, + 657877410752869, + 157451572512238, + ]), + xy2d: FieldElement51([ + 1029287186166717, + 65860128430192, + 525298368814832, + 1491902500801986, + 1461064796385400, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2660016802414475, + 2121095722306988, + 913562102267595, + 1879708920318308, + 2492861262121979, + ]), + y_minus_x: FieldElement51([ + 1185483484383269, + 1356339572588553, + 584932367316448, + 102132779946470, + 1792922621116791, + ]), + xy2d: FieldElement51([ + 1966196870701923, + 2230044620318636, + 1425982460745905, + 261167817826569, + 46517743394330, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2358877405280588, + 3136759755857592, + 2279106683482647, + 2224911448949389, + 3216151871930471, + ]), + y_minus_x: FieldElement51([ + 1730194207717538, + 431790042319772, + 1831515233279467, + 1372080552768581, + 1074513929381760, + ]), + xy2d: FieldElement51([ + 1450880638731607, + 1019861580989005, + 1229729455116861, + 1174945729836143, + 826083146840706, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1899935429242705, + 1602068751520477, + 940583196550370, + 2334230882739107, + 1540863155745695, + ]), + y_minus_x: FieldElement51([ + 2136688454840028, + 2099509000964294, + 1690800495246475, + 1217643678575476, + 828720645084218, + ]), + xy2d: FieldElement51([ + 765548025667841, + 462473984016099, + 998061409979798, + 546353034089527, + 2212508972466858, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2298375097456408, + 3144370785258318, + 1281983193144089, + 1491520128287375, + 75847005908304, + ]), + y_minus_x: FieldElement51([ + 1801436127943107, + 1734436817907890, + 1268728090345068, + 167003097070711, + 2233597765834956, + ]), + xy2d: FieldElement51([ + 1997562060465113, + 1048700225534011, + 7615603985628, + 1855310849546841, + 2242557647635213, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1161017320376250, + 2744424393854291, + 2169815802355236, + 3228296595417790, + 1770879511019628, + ]), + y_minus_x: FieldElement51([ + 1357044908364776, + 729130645262438, + 1762469072918979, + 1365633616878458, + 181282906404941, + ]), + xy2d: FieldElement51([ + 1080413443139865, + 1155205815510486, + 1848782073549786, + 622566975152580, + 124965574467971, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1184526762066993, + 247622751762817, + 2943928830891604, + 3071818503097743, + 2188697339828084, + ]), + y_minus_x: FieldElement51([ + 2020536369003019, + 202261491735136, + 1053169669150884, + 2056531979272544, + 778165514694311, + ]), + xy2d: FieldElement51([ + 237404399610207, + 1308324858405118, + 1229680749538400, + 720131409105291, + 1958958863624906, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2767383321724075, + 2269456792542436, + 1717918437373988, + 1568052070792483, + 2298775616809171, + ]), + y_minus_x: FieldElement51([ + 281527309158085, + 36970532401524, + 866906920877543, + 2222282602952734, + 1289598729589882, + ]), + xy2d: FieldElement51([ + 1278207464902042, + 494742455008756, + 1262082121427081, + 1577236621659884, + 1888786707293291, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 353042527954210, + 1830056151907359, + 1111731275799225, + 2426760769524072, + 404312815582674, + ]), + y_minus_x: FieldElement51([ + 2064251142068628, + 1666421603389706, + 1419271365315441, + 468767774902855, + 191535130366583, + ]), + xy2d: FieldElement51([ + 1716987058588002, + 1859366439773457, + 1767194234188234, + 64476199777924, + 1117233614485261, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3236091949205521, + 2386938060636506, + 2220652137473166, + 1722843421165029, + 2442282371698157, + ]), + y_minus_x: FieldElement51([ + 298845952651262, + 1166086588952562, + 1179896526238434, + 1347812759398693, + 1412945390096208, + ]), + xy2d: FieldElement51([ + 1143239552672925, + 906436640714209, + 2177000572812152, + 2075299936108548, + 325186347798433, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2972824668060020, + 2936287674948563, + 3625238557779406, + 2193186935276994, + 1387043709851261, + ]), + y_minus_x: FieldElement51([ + 418098668140962, + 715065997721283, + 1471916138376055, + 2168570337288357, + 937812682637044, + ]), + xy2d: FieldElement51([ + 1043584187226485, + 2143395746619356, + 2209558562919611, + 482427979307092, + 847556718384018, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1248731221520740, + 1465200936117687, + 2792603306395388, + 2304778448366139, + 2513234303861356, + ]), + y_minus_x: FieldElement51([ + 1057329623869501, + 620334067429122, + 461700859268034, + 2012481616501857, + 297268569108938, + ]), + xy2d: FieldElement51([ + 1055352180870759, + 1553151421852298, + 1510903185371259, + 1470458349428097, + 1226259419062731, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3744788603986897, + 3042126439258578, + 3441906842094992, + 3641194565844440, + 3872208010289441, + ]), + y_minus_x: FieldElement51([ + 47000654413729, + 1004754424173864, + 1868044813557703, + 173236934059409, + 588771199737015, + ]), + xy2d: FieldElement51([ + 30498470091663, + 1082245510489825, + 576771653181956, + 806509986132686, + 1317634017056939, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2672107869436803, + 3745154677001249, + 2417006535213335, + 4136645508605033, + 2065456951573058, + ]), + y_minus_x: FieldElement51([ + 1115636332012334, + 1854340990964155, + 83792697369514, + 1972177451994021, + 457455116057587, + ]), + xy2d: FieldElement51([ + 1698968457310898, + 1435137169051090, + 1083661677032510, + 938363267483709, + 340103887207182, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1995325341336555, + 911500251774648, + 2415810569088940, + 855378419194761, + 3825401211214090, + ]), + y_minus_x: FieldElement51([ + 241719380661528, + 310028521317150, + 1215881323380194, + 1408214976493624, + 2141142156467363, + ]), + xy2d: FieldElement51([ + 1315157046163473, + 727368447885818, + 1363466668108618, + 1668921439990361, + 1398483384337907, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2326829491984875, + 3267188020145720, + 1849729037055211, + 4191614430138232, + 2696204044080201, + ]), + y_minus_x: FieldElement51([ + 2053597130993710, + 2024431685856332, + 2233550957004860, + 2012407275509545, + 872546993104440, + ]), + xy2d: FieldElement51([ + 1217269667678610, + 599909351968693, + 1390077048548598, + 1471879360694802, + 739586172317596, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3970118453066023, + 1560510726633957, + 3156262694845170, + 1418028351780051, + 2346204163137185, + ]), + y_minus_x: FieldElement51([ + 2132502667405250, + 214379346175414, + 1502748313768060, + 1960071701057800, + 1353971822643138, + ]), + xy2d: FieldElement51([ + 319394212043702, + 2127459436033571, + 717646691535162, + 663366796076914, + 318459064945314, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2657789238608841, + 1960452633787082, + 2919148848086913, + 3744474074452359, + 1451061489880786, + ]), + y_minus_x: FieldElement51([ + 947085906234007, + 323284730494107, + 1485778563977200, + 728576821512394, + 901584347702286, + ]), + xy2d: FieldElement51([ + 1575783124125742, + 2126210792434375, + 1569430791264065, + 1402582372904727, + 1891780248341114, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3090232019245924, + 4249503325136911, + 3270591693593114, + 1662001808174330, + 2330127946643001, + ]), + y_minus_x: FieldElement51([ + 739152638255629, + 2074935399403557, + 505483666745895, + 1611883356514088, + 628654635394878, + ]), + xy2d: FieldElement51([ + 1822054032121349, + 643057948186973, + 7306757352712, + 577249257962099, + 284735863382083, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3618358370049178, + 1448606567552085, + 3730680834630016, + 2417602993041145, + 1115718458123497, + ]), + y_minus_x: FieldElement51([ + 204146226972102, + 1630511199034723, + 2215235214174763, + 174665910283542, + 956127674017216, + ]), + xy2d: FieldElement51([ + 1562934578796716, + 1070893489712745, + 11324610642270, + 958989751581897, + 2172552325473805, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1770564423056008, + 2987323445349813, + 1326060113795288, + 1509650369341127, + 2317692235267932, + ]), + y_minus_x: FieldElement51([ + 623682558650637, + 1337866509471512, + 990313350206649, + 1314236615762469, + 1164772974270275, + ]), + xy2d: FieldElement51([ + 223256821462517, + 723690150104139, + 1000261663630601, + 933280913953265, + 254872671543046, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1969087237026022, + 2876595539132372, + 1335555107635968, + 2069986355593023, + 3963899963027150, + ]), + y_minus_x: FieldElement51([ + 1236103475266979, + 1837885883267218, + 1026072585230455, + 1025865513954973, + 1801964901432134, + ]), + xy2d: FieldElement51([ + 1115241013365517, + 1712251818829143, + 2148864332502771, + 2096001471438138, + 2235017246626125, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3551068012286861, + 2047148477845620, + 2165648650132450, + 1612539282026145, + 2765997725314138, + ]), + y_minus_x: FieldElement51([ + 118352772338543, + 1067608711804704, + 1434796676193498, + 1683240170548391, + 230866769907437, + ]), + xy2d: FieldElement51([ + 1850689576796636, + 1601590730430274, + 1139674615958142, + 1954384401440257, + 76039205311, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1723387471374172, + 3249101280723658, + 2785727448808904, + 2272728458379212, + 1756575222802512, + ]), + y_minus_x: FieldElement51([ + 2146711623855116, + 503278928021499, + 625853062251406, + 1109121378393107, + 1033853809911861, + ]), + xy2d: FieldElement51([ + 571005965509422, + 2005213373292546, + 1016697270349626, + 56607856974274, + 914438579435146, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1346698876211176, + 2076651707527589, + 3336561384795453, + 2517134292513653, + 1068954492309670, + ]), + y_minus_x: FieldElement51([ + 1769967932677654, + 1695893319756416, + 1151863389675920, + 1781042784397689, + 400287774418285, + ]), + xy2d: FieldElement51([ + 1851867764003121, + 403841933237558, + 820549523771987, + 761292590207581, + 1743735048551143, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 410915148140008, + 2107072311871739, + 3256167275561751, + 2351484709082008, + 1180818713503223, + ]), + y_minus_x: FieldElement51([ + 285945406881439, + 648174397347453, + 1098403762631981, + 1366547441102991, + 1505876883139217, + ]), + xy2d: FieldElement51([ + 672095903120153, + 1675918957959872, + 636236529315028, + 1569297300327696, + 2164144194785875, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1902708175321798, + 3287143344600686, + 1178560808893262, + 2552895497743394, + 1280977479761117, + ]), + y_minus_x: FieldElement51([ + 1615357281742403, + 404257611616381, + 2160201349780978, + 1160947379188955, + 1578038619549541, + ]), + xy2d: FieldElement51([ + 2013087639791217, + 822734930507457, + 1785668418619014, + 1668650702946164, + 389450875221715, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2705718263383616, + 2358206633614248, + 2072540975937134, + 308588860670238, + 1304394580755385, + ]), + y_minus_x: FieldElement51([ + 1295082798350326, + 2091844511495996, + 1851348972587817, + 3375039684596, + 789440738712837, + ]), + xy2d: FieldElement51([ + 2083069137186154, + 848523102004566, + 993982213589257, + 1405313299916317, + 1532824818698468, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3747761112537659, + 1397203457344778, + 4026750030752190, + 2391102557240943, + 2318403398028034, + ]), + y_minus_x: FieldElement51([ + 1782411379088302, + 1096724939964781, + 27593390721418, + 542241850291353, + 1540337798439873, + ]), + xy2d: FieldElement51([ + 693543956581437, + 171507720360750, + 1557908942697227, + 1074697073443438, + 1104093109037196, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 345288228393400, + 3351443383432420, + 2386681722088990, + 1740551994106739, + 2500011992985018, + ]), + y_minus_x: FieldElement51([ + 231429562203065, + 1526290236421172, + 2021375064026423, + 1520954495658041, + 806337791525116, + ]), + xy2d: FieldElement51([ + 1079623667189886, + 872403650198613, + 766894200588288, + 2163700860774109, + 2023464507911816, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 854645372543796, + 1936406001954827, + 2403260476226501, + 3077125552956802, + 1554306377287555, + ]), + y_minus_x: FieldElement51([ + 1497138821904622, + 1044820250515590, + 1742593886423484, + 1237204112746837, + 849047450816987, + ]), + xy2d: FieldElement51([ + 667962773375330, + 1897271816877105, + 1399712621683474, + 1143302161683099, + 2081798441209593, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2378947665252234, + 1936114012888109, + 1704424366552046, + 3108474694401560, + 2968403435020606, + ]), + y_minus_x: FieldElement51([ + 1072409664800960, + 2146937497077528, + 1508780108920651, + 935767602384853, + 1112800433544068, + ]), + xy2d: FieldElement51([ + 333549023751292, + 280219272863308, + 2104176666454852, + 1036466864875785, + 536135186520207, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2625466093568366, + 2398257055215356, + 2555916080813104, + 2667888562832962, + 3510376944868638, + ]), + y_minus_x: FieldElement51([ + 1186115062588401, + 2251609796968486, + 1098944457878953, + 1153112761201374, + 1791625503417267, + ]), + xy2d: FieldElement51([ + 1870078460219737, + 2129630962183380, + 852283639691142, + 292865602592851, + 401904317342226, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1361070124828016, + 815664541425524, + 3278598711049919, + 1951790935390646, + 2807674705520038, + ]), + y_minus_x: FieldElement51([ + 1546301003424277, + 459094500062839, + 1097668518375311, + 1780297770129643, + 720763293687608, + ]), + xy2d: FieldElement51([ + 1212405311403990, + 1536693382542438, + 61028431067459, + 1863929423417129, + 1223219538638038, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1294303766540260, + 3435357279640341, + 3134071170918340, + 2315654383110622, + 2213283684565086, + ]), + y_minus_x: FieldElement51([ + 339050984211414, + 601386726509773, + 413735232134068, + 966191255137228, + 1839475899458159, + ]), + xy2d: FieldElement51([ + 235605972169408, + 2174055643032978, + 1538335001838863, + 1281866796917192, + 1815940222628465, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1632352921721536, + 1833328609514701, + 2092779091951987, + 4175756015558474, + 2210068022482918, + ]), + y_minus_x: FieldElement51([ + 35271216625062, + 1712350667021807, + 983664255668860, + 98571260373038, + 1232645608559836, + ]), + xy2d: FieldElement51([ + 1998172393429622, + 1798947921427073, + 784387737563581, + 1589352214827263, + 1589861734168180, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1733739258725305, + 2283515530744786, + 2453769758904107, + 3243892858242237, + 1194308773174555, + ]), + y_minus_x: FieldElement51([ + 846415389605137, + 746163495539180, + 829658752826080, + 592067705956946, + 957242537821393, + ]), + xy2d: FieldElement51([ + 1758148849754419, + 619249044817679, + 168089007997045, + 1371497636330523, + 1867101418880350, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2578433797894864, + 2513559319756263, + 1700682323676192, + 1577907266349064, + 3469447477068264, + ]), + y_minus_x: FieldElement51([ + 1714182387328607, + 1477856482074168, + 574895689942184, + 2159118410227270, + 1555532449716575, + ]), + xy2d: FieldElement51([ + 853828206885131, + 998498946036955, + 1835887550391235, + 207627336608048, + 258363815956050, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2392941288336925, + 3488528558590503, + 2894901233585134, + 1646615130509172, + 1208239602291765, + ]), + y_minus_x: FieldElement51([ + 1501663228068911, + 1354879465566912, + 1444432675498247, + 897812463852601, + 855062598754348, + ]), + xy2d: FieldElement51([ + 714380763546606, + 1032824444965790, + 1774073483745338, + 1063840874947367, + 1738680636537158, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1640635546696233, + 2884968766877360, + 2212651044092395, + 2282390772269100, + 2620315074574625, + ]), + y_minus_x: FieldElement51([ + 1171650314802029, + 1567085444565577, + 1453660792008405, + 757914533009261, + 1619511342778196, + ]), + xy2d: FieldElement51([ + 420958967093237, + 971103481109486, + 2169549185607107, + 1301191633558497, + 1661514101014240, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3158923465503550, + 1332556122804145, + 4075855067109735, + 3619414031128206, + 1982558335973171, + ]), + y_minus_x: FieldElement51([ + 1121533090144639, + 1021251337022187, + 110469995947421, + 1511059774758394, + 2110035908131662, + ]), + xy2d: FieldElement51([ + 303213233384524, + 2061932261128138, + 352862124777736, + 40828818670255, + 249879468482660, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 856559257852200, + 2760317478634258, + 3629993581580163, + 3975258940632376, + 1962275756614520, + ]), + y_minus_x: FieldElement51([ + 1445691340537320, + 40614383122127, + 402104303144865, + 485134269878232, + 1659439323587426, + ]), + xy2d: FieldElement51([ + 20057458979482, + 1183363722525800, + 2140003847237215, + 2053873950687614, + 2112017736174909, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2228654250927986, + 3735391177100515, + 1368661293910955, + 3328311098862539, + 526650682059607, + ]), + y_minus_x: FieldElement51([ + 709481497028540, + 531682216165724, + 316963769431931, + 1814315888453765, + 258560242424104, + ]), + xy2d: FieldElement51([ + 1053447823660455, + 1955135194248683, + 1010900954918985, + 1182614026976701, + 1240051576966610, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1957943897155478, + 1788667368028035, + 2389492723714354, + 2252839333292309, + 3078204576998275, + ]), + y_minus_x: FieldElement51([ + 1848942433095597, + 1582009882530495, + 1849292741020143, + 1068498323302788, + 2001402229799484, + ]), + xy2d: FieldElement51([ + 1528282417624269, + 2142492439828191, + 2179662545816034, + 362568973150328, + 1591374675250271, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2411826493119617, + 2484141002903963, + 2149181472355544, + 598041771119831, + 2435658815595421, + ]), + y_minus_x: FieldElement51([ + 2013278155187349, + 662660471354454, + 793981225706267, + 411706605985744, + 804490933124791, + ]), + xy2d: FieldElement51([ + 2051892037280204, + 488391251096321, + 2230187337030708, + 930221970662692, + 679002758255210, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1530723630438670, + 875873929577927, + 2593359947955236, + 2701702933216000, + 1055551308214178, + ]), + y_minus_x: FieldElement51([ + 1461835919309432, + 1955256480136428, + 180866187813063, + 1551979252664528, + 557743861963950, + ]), + xy2d: FieldElement51([ + 359179641731115, + 1324915145732949, + 902828372691474, + 294254275669987, + 1887036027752957, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4295071423139571, + 2038225437857463, + 1317528426475850, + 1398989128982787, + 2027639881006861, + ]), + y_minus_x: FieldElement51([ + 2072902725256516, + 312132452743412, + 309930885642209, + 996244312618453, + 1590501300352303, + ]), + xy2d: FieldElement51([ + 1397254305160710, + 695734355138021, + 2233992044438756, + 1776180593969996, + 1085588199351115, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2692366865016258, + 2506694600041928, + 2745669038615469, + 1556322069683365, + 3819256354004466, + ]), + y_minus_x: FieldElement51([ + 1950722461391320, + 1907845598854797, + 1822757481635527, + 2121567704750244, + 73811931471221, + ]), + xy2d: FieldElement51([ + 387139307395758, + 2058036430315676, + 1220915649965325, + 1794832055328951, + 1230009312169328, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1765973779329498, + 2911143873132225, + 2271621715291913, + 3553728154996461, + 3368065817761132, + ]), + y_minus_x: FieldElement51([ + 1127572801181483, + 1224743760571696, + 1276219889847274, + 1529738721702581, + 1589819666871853, + ]), + xy2d: FieldElement51([ + 2181229378964934, + 2190885205260020, + 1511536077659137, + 1246504208580490, + 668883326494241, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2689666469258543, + 2920826224880015, + 2333696811665585, + 523874406393177, + 2496851874620484, + ]), + y_minus_x: FieldElement51([ + 1975438052228868, + 1071801519999806, + 594652299224319, + 1877697652668809, + 1489635366987285, + ]), + xy2d: FieldElement51([ + 958592545673770, + 233048016518599, + 851568750216589, + 567703851596087, + 1740300006094761, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2014540178270324, + 192672779514432, + 2465676996326778, + 2194819933853410, + 1716422829364835, + ]), + y_minus_x: FieldElement51([ + 1540769606609725, + 2148289943846077, + 1597804156127445, + 1230603716683868, + 815423458809453, + ]), + xy2d: FieldElement51([ + 1738560251245018, + 1779576754536888, + 1783765347671392, + 1880170990446751, + 1088225159617541, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2911103727614740, + 1956447718227572, + 1830568515922666, + 3092868863429656, + 1669607124206367, + ]), + y_minus_x: FieldElement51([ + 1143465490433355, + 1532194726196059, + 1093276745494697, + 481041706116088, + 2121405433561163, + ]), + xy2d: FieldElement51([ + 1686424298744462, + 1451806974487153, + 266296068846582, + 1834686947542675, + 1720762336132256, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3141016840074207, + 3295090436969907, + 3107924901237156, + 1669272323124635, + 1603340330827879, + ]), + y_minus_x: FieldElement51([ + 1206396181488998, + 333158148435054, + 1402633492821422, + 1120091191722026, + 1945474114550509, + ]), + xy2d: FieldElement51([ + 766720088232571, + 1512222781191002, + 1189719893490790, + 2091302129467914, + 2141418006894941, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2671463460991841, + 1998875112167986, + 3678399683938955, + 3406728169064757, + 2738338345823434, + ]), + y_minus_x: FieldElement51([ + 938160078005954, + 1421776319053174, + 1941643234741774, + 180002183320818, + 1414380336750546, + ]), + xy2d: FieldElement51([ + 398001940109652, + 1577721237663248, + 1012748649830402, + 1540516006905144, + 1011684812884559, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1653276489969611, + 2257881638852872, + 1921777941170835, + 1604139841794531, + 3113010867325889, + ]), + y_minus_x: FieldElement51([ + 996661541407379, + 1455877387952927, + 744312806857277, + 139213896196746, + 1000282908547789, + ]), + xy2d: FieldElement51([ + 1450817495603008, + 1476865707053229, + 1030490562252053, + 620966950353376, + 1744760161539058, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2811528223687828, + 2288856475326432, + 2038622963352005, + 1637244893271723, + 3278365165924196, + ]), + y_minus_x: FieldElement51([ + 962165956135846, + 1116599660248791, + 182090178006815, + 1455605467021751, + 196053588803284, + ]), + xy2d: FieldElement51([ + 796863823080135, + 1897365583584155, + 420466939481601, + 2165972651724672, + 932177357788289, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 877047233620613, + 1375632631944375, + 2895573425567369, + 2911822552533124, + 2271153746017078, + ]), + y_minus_x: FieldElement51([ + 2216943882299338, + 394841323190322, + 2222656898319671, + 558186553950529, + 1077236877025190, + ]), + xy2d: FieldElement51([ + 801118384953213, + 1914330175515892, + 574541023311511, + 1471123787903705, + 1526158900256288, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3201417702772463, + 2207116611267330, + 3164719852826535, + 2752958352884036, + 2314162374456719, + ]), + y_minus_x: FieldElement51([ + 1474518386765335, + 1760793622169197, + 1157399790472736, + 1622864308058898, + 165428294422792, + ]), + xy2d: FieldElement51([ + 1961673048027128, + 102619413083113, + 1051982726768458, + 1603657989805485, + 1941613251499678, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1401939116319247, + 2587106153588320, + 2323846009771033, + 862423201496005, + 3102318568216632, + ]), + y_minus_x: FieldElement51([ + 1234706593321979, + 1083343891215917, + 898273974314935, + 1640859118399498, + 157578398571149, + ]), + xy2d: FieldElement51([ + 1143483057726416, + 1992614991758919, + 674268662140796, + 1773370048077526, + 674318359920189, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1835401379538542, + 173900035308392, + 818247630716732, + 4013900225838034, + 1021506399448290, + ]), + y_minus_x: FieldElement51([ + 1506632088156630, + 2127481795522179, + 513812919490255, + 140643715928370, + 442476620300318, + ]), + xy2d: FieldElement51([ + 2056683376856736, + 219094741662735, + 2193541883188309, + 1841182310235800, + 556477468664293, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3566819241596075, + 1049075855992602, + 4318372866671791, + 2518704280870781, + 2040482348591519, + ]), + y_minus_x: FieldElement51([ + 94096246544434, + 922482381166992, + 24517828745563, + 2139430508542503, + 2097139044231004, + ]), + xy2d: FieldElement51([ + 537697207950515, + 1399352016347350, + 1563663552106345, + 2148749520888918, + 549922092988516, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1747985413252415, + 680511052635695, + 1809559829982725, + 2846074064615302, + 2453472984431229, + ]), + y_minus_x: FieldElement51([ + 323583936109569, + 1973572998577657, + 1192219029966558, + 79354804385273, + 1374043025560347, + ]), + xy2d: FieldElement51([ + 213277331329947, + 416202017849623, + 1950535221091783, + 1313441578103244, + 2171386783823658, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2440888617915079, + 993969372859109, + 3147669935222235, + 3799101348983503, + 1477373024911349, + ]), + y_minus_x: FieldElement51([ + 1620578418245010, + 541035331188469, + 2235785724453865, + 2154865809088198, + 1974627268751826, + ]), + xy2d: FieldElement51([ + 1346805451740245, + 1350981335690626, + 942744349501813, + 2155094562545502, + 1012483751693409, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2107080134091762, + 1132567062788208, + 1824935377687210, + 769194804343737, + 1857941799971888, + ]), + y_minus_x: FieldElement51([ + 1074666112436467, + 249279386739593, + 1174337926625354, + 1559013532006480, + 1472287775519121, + ]), + xy2d: FieldElement51([ + 1872620123779532, + 1892932666768992, + 1921559078394978, + 1270573311796160, + 1438913646755037, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3089190001333428, + 3264053113908846, + 989780015893986, + 1351393287739814, + 2580427560230798, + ]), + y_minus_x: FieldElement51([ + 1028328827183114, + 1711043289969857, + 1350832470374933, + 1923164689604327, + 1495656368846911, + ]), + xy2d: FieldElement51([ + 1900828492104143, + 430212361082163, + 687437570852799, + 832514536673512, + 1685641495940794, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3094432661621646, + 605670026766215, + 290836444839585, + 2415010588577604, + 2213815011799644, + ]), + y_minus_x: FieldElement51([ + 1176336383453996, + 1725477294339771, + 12700622672454, + 678015708818208, + 162724078519879, + ]), + xy2d: FieldElement51([ + 1448049969043497, + 1789411762943521, + 385587766217753, + 90201620913498, + 832999441066823, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2767886146978542, + 2240508292484615, + 3603469341851756, + 3475055379001735, + 3002035638112385, + ]), + y_minus_x: FieldElement51([ + 1263624896582495, + 1102602401673328, + 526302183714372, + 2152015839128799, + 1483839308490010, + ]), + xy2d: FieldElement51([ + 442991718646863, + 1599275157036458, + 1925389027579192, + 899514691371390, + 350263251085160, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1689713572022124, + 2845654372939621, + 3229894858477217, + 1985127338729498, + 3927868934032873, + ]), + y_minus_x: FieldElement51([ + 1557207018622683, + 340631692799603, + 1477725909476187, + 614735951619419, + 2033237123746766, + ]), + xy2d: FieldElement51([ + 968764929340557, + 1225534776710944, + 662967304013036, + 1155521416178595, + 791142883466590, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1487081286167458, + 3244839255500182, + 1792378982844639, + 2950452258685122, + 2153908693179753, + ]), + y_minus_x: FieldElement51([ + 1123181311102823, + 685575944875442, + 507605465509927, + 1412590462117473, + 568017325228626, + ]), + xy2d: FieldElement51([ + 560258797465417, + 2193971151466401, + 1824086900849026, + 579056363542056, + 1690063960036441, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1918407319222397, + 2605567366745211, + 1930426334528098, + 1564816146005724, + 4113142195393344, + ]), + y_minus_x: FieldElement51([ + 2131325168777276, + 1176636658428908, + 1756922641512981, + 1390243617176012, + 1966325177038383, + ]), + xy2d: FieldElement51([ + 2063958120364491, + 2140267332393533, + 699896251574968, + 273268351312140, + 375580724713232, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2024297515263178, + 2668759143407935, + 3330814048702549, + 2423412039258430, + 1031677520051052, + ]), + y_minus_x: FieldElement51([ + 2033900009388450, + 1744902869870788, + 2190580087917640, + 1949474984254121, + 231049754293748, + ]), + xy2d: FieldElement51([ + 343868674606581, + 550155864008088, + 1450580864229630, + 481603765195050, + 896972360018042, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2151139328380127, + 2566545695770176, + 2311556639460451, + 1676664391494650, + 2048348075599360, + ]), + y_minus_x: FieldElement51([ + 1528930066340597, + 1605003907059576, + 1055061081337675, + 1458319101947665, + 1234195845213142, + ]), + xy2d: FieldElement51([ + 830430507734812, + 1780282976102377, + 1425386760709037, + 362399353095425, + 2168861579799910, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3407562046415562, + 980662895504005, + 2053766700883521, + 2742766027762854, + 2762205690726604, + ]), + y_minus_x: FieldElement51([ + 1683750316716132, + 652278688286128, + 1221798761193539, + 1897360681476669, + 319658166027343, + ]), + xy2d: FieldElement51([ + 618808732869972, + 72755186759744, + 2060379135624181, + 1730731526741822, + 48862757828238, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3714971784278753, + 3394840525452699, + 614590986558882, + 1409210575145591, + 1882816996436803, + ]), + y_minus_x: FieldElement51([ + 2230133264691131, + 563950955091024, + 2042915975426398, + 827314356293472, + 672028980152815, + ]), + xy2d: FieldElement51([ + 264204366029760, + 1654686424479449, + 2185050199932931, + 2207056159091748, + 506015669043634, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1784446333136550, + 1973746527984364, + 334856327359575, + 3408569589569858, + 3275749938360725, + ]), + y_minus_x: FieldElement51([ + 2065270940578383, + 31477096270353, + 306421879113491, + 181958643936686, + 1907105536686083, + ]), + xy2d: FieldElement51([ + 1496516440779464, + 1748485652986458, + 872778352227340, + 818358834654919, + 97932669284220, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2723435829455580, + 2924255216478824, + 1804995246884102, + 1842309243470804, + 3753662318666930, + ]), + y_minus_x: FieldElement51([ + 1013216974933691, + 538921919682598, + 1915776722521558, + 1742822441583877, + 1886550687916656, + ]), + xy2d: FieldElement51([ + 2094270000643336, + 303971879192276, + 40801275554748, + 649448917027930, + 1818544418535447, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2241737709499146, + 549397817447461, + 838180519319392, + 1725686958520781, + 3957438894582995, + ]), + y_minus_x: FieldElement51([ + 1216074541925116, + 50120933933509, + 1565829004133810, + 721728156134580, + 349206064666188, + ]), + xy2d: FieldElement51([ + 948617110470858, + 346222547451945, + 1126511960599975, + 1759386906004538, + 493053284802266, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1454933046815146, + 3126495827951610, + 1467170975468587, + 1432316382418897, + 2111710746366763, + ]), + y_minus_x: FieldElement51([ + 2105387117364450, + 1996463405126433, + 1303008614294500, + 851908115948209, + 1353742049788635, + ]), + xy2d: FieldElement51([ + 750300956351719, + 1487736556065813, + 15158817002104, + 1511998221598392, + 971739901354129, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1874648163531674, + 2124487685930551, + 1810030029384882, + 918400043048335, + 2838148440985898, + ]), + y_minus_x: FieldElement51([ + 1235084464747900, + 1166111146432082, + 1745394857881591, + 1405516473883040, + 4463504151617, + ]), + xy2d: FieldElement51([ + 1663810156463827, + 327797390285791, + 1341846161759410, + 1964121122800605, + 1747470312055380, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 660005247548214, + 2071860029952887, + 3610548013635355, + 911703252219106, + 3266179736709079, + ]), + y_minus_x: FieldElement51([ + 2206641276178231, + 1690587809721504, + 1600173622825126, + 2156096097634421, + 1106822408548216, + ]), + xy2d: FieldElement51([ + 1344788193552206, + 1949552134239140, + 1735915881729557, + 675891104100469, + 1834220014427292, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1920949492387945, + 2410685102072778, + 2322108077349280, + 2877838278583064, + 3719881539786256, + ]), + y_minus_x: FieldElement51([ + 622221042073383, + 1210146474039168, + 1742246422343683, + 1403839361379025, + 417189490895736, + ]), + xy2d: FieldElement51([ + 22727256592983, + 168471543384997, + 1324340989803650, + 1839310709638189, + 504999476432775, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3565040332441556, + 1721896294296941, + 2304063388272514, + 2065069734239231, + 3056710287109878, + ]), + y_minus_x: FieldElement51([ + 1337466662091884, + 1287645354669772, + 2018019646776184, + 652181229374245, + 898011753211715, + ]), + xy2d: FieldElement51([ + 1969792547910734, + 779969968247557, + 2011350094423418, + 1823964252907487, + 1058949448296945, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2459143550747250, + 1118176942430252, + 3010694408233412, + 806764629546265, + 1157700123092949, + ]), + y_minus_x: FieldElement51([ + 1273565321399022, + 1638509681964574, + 759235866488935, + 666015124346707, + 897983460943405, + ]), + xy2d: FieldElement51([ + 1717263794012298, + 1059601762860786, + 1837819172257618, + 1054130665797229, + 680893204263559, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2237039662793603, + 2249022333361206, + 2058613546633703, + 2401253908530527, + 2215176649164581, + ]), + y_minus_x: FieldElement51([ + 79472182719605, + 1851130257050174, + 1825744808933107, + 821667333481068, + 781795293511946, + ]), + xy2d: FieldElement51([ + 755822026485370, + 152464789723500, + 1178207602290608, + 410307889503239, + 156581253571278, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3669985309815545, + 2736319981413860, + 3898537095128197, + 3653287498355512, + 1349185550126960, + ]), + y_minus_x: FieldElement51([ + 1495380034400429, + 325049476417173, + 46346894893933, + 1553408840354856, + 828980101835683, + ]), + xy2d: FieldElement51([ + 1280337889310282, + 2070832742866672, + 1640940617225222, + 2098284908289951, + 450929509534434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2659503167684029, + 2378371955168899, + 2537839641198868, + 1999255076709337, + 2030511179441770, + ]), + y_minus_x: FieldElement51([ + 1254958221100483, + 1153235960999843, + 942907704968834, + 637105404087392, + 1149293270147267, + ]), + xy2d: FieldElement51([ + 894249020470196, + 400291701616810, + 406878712230981, + 1599128793487393, + 1145868722604026, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3749755063888563, + 2361916158338507, + 1128535642171975, + 1900106496009660, + 2381592531146157, + ]), + y_minus_x: FieldElement51([ + 452487513298665, + 1352120549024569, + 1173495883910956, + 1999111705922009, + 367328130454226, + ]), + xy2d: FieldElement51([ + 1717539401269642, + 1475188995688487, + 891921989653942, + 836824441505699, + 1885988485608364, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3493583935107776, + 2439136865632830, + 3370281625921440, + 2680547565621609, + 2282158712612572, + ]), + y_minus_x: FieldElement51([ + 2022432361201842, + 1088816090685051, + 1977843398539868, + 1854834215890724, + 564238862029357, + ]), + xy2d: FieldElement51([ + 938868489100585, + 1100285072929025, + 1017806255688848, + 1957262154788833, + 152787950560442, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3119119231364171, + 2872271776627789, + 2477832016990963, + 2593801257642876, + 1761675818237335, + ]), + y_minus_x: FieldElement51([ + 1295072362439987, + 931227904689414, + 1355731432641687, + 922235735834035, + 892227229410209, + ]), + xy2d: FieldElement51([ + 1680989767906154, + 535362787031440, + 2136691276706570, + 1942228485381244, + 1267350086882274, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2617818047455756, + 2684460443440843, + 2378209521329782, + 1973842949591661, + 2897427157127624, + ]), + y_minus_x: FieldElement51([ + 535509430575217, + 546885533737322, + 1524675609547799, + 2138095752851703, + 1260738089896827, + ]), + xy2d: FieldElement51([ + 1159906385590467, + 2198530004321610, + 714559485023225, + 81880727882151, + 1484020820037082, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1377485731340769, + 2046328105512000, + 1802058637158797, + 2313945950453421, + 1356993908853900, + ]), + y_minus_x: FieldElement51([ + 2013612215646735, + 1830770575920375, + 536135310219832, + 609272325580394, + 270684344495013, + ]), + xy2d: FieldElement51([ + 1237542585982777, + 2228682050256790, + 1385281931622824, + 593183794882890, + 493654978552689, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2299141301692989, + 1891414891220256, + 983894663308928, + 2427961581972066, + 3378060928864955, + ]), + y_minus_x: FieldElement51([ + 1694030170963455, + 502038567066200, + 1691160065225467, + 949628319562187, + 275110186693066, + ]), + xy2d: FieldElement51([ + 1124515748676336, + 1661673816593408, + 1499640319059718, + 1584929449166988, + 558148594103306, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1784525599998356, + 1619698033617383, + 2097300287550715, + 2510065271789004, + 1905684794832757, + ]), + y_minus_x: FieldElement51([ + 1288941072872766, + 931787902039402, + 190731008859042, + 2006859954667190, + 1005931482221702, + ]), + xy2d: FieldElement51([ + 1465551264822703, + 152905080555927, + 680334307368453, + 173227184634745, + 666407097159852, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2111017076203943, + 3630560299479595, + 1248583954016455, + 3604089008549670, + 1895180776543895, + ]), + y_minus_x: FieldElement51([ + 171348223915638, + 662766099800389, + 462338943760497, + 466917763340314, + 656911292869115, + ]), + xy2d: FieldElement51([ + 488623681976577, + 866497561541722, + 1708105560937768, + 1673781214218839, + 1506146329818807, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2412225278142205, + 950394373239688, + 2682296937026182, + 711676555398831, + 320964687779005, + ]), + y_minus_x: FieldElement51([ + 988979367990485, + 1359729327576302, + 1301834257246029, + 294141160829308, + 29348272277475, + ]), + xy2d: FieldElement51([ + 1434382743317910, + 100082049942065, + 221102347892623, + 186982837860588, + 1305765053501834, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2205916462268190, + 2751663643476068, + 961960554686615, + 2409862576442233, + 1841471168298304, + ]), + y_minus_x: FieldElement51([ + 1191737341426592, + 1847042034978363, + 1382213545049056, + 1039952395710448, + 788812858896859, + ]), + xy2d: FieldElement51([ + 1346965964571152, + 1291881610839830, + 2142916164336056, + 786821641205979, + 1571709146321039, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 787164375951248, + 2454669019058437, + 3608390234717387, + 1431233331032509, + 786341368775957, + ]), + y_minus_x: FieldElement51([ + 492448143532951, + 304105152670757, + 1761767168301056, + 233782684697790, + 1981295323106089, + ]), + xy2d: FieldElement51([ + 665807507761866, + 1343384868355425, + 895831046139653, + 439338948736892, + 1986828765695105, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3007896024559801, + 1721699973539148, + 2510565115413133, + 1390588532210644, + 1212530909934781, + ]), + y_minus_x: FieldElement51([ + 852891097972275, + 1816988871354562, + 1543772755726524, + 1174710635522444, + 202129090724628, + ]), + xy2d: FieldElement51([ + 1205281565824323, + 22430498399418, + 992947814485516, + 1392458699738672, + 688441466734558, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3302427242100220, + 1955849529137134, + 2171162376368357, + 2343545681983462, + 447733118757825, + ]), + y_minus_x: FieldElement51([ + 1287181461435438, + 622722465530711, + 880952150571872, + 741035693459198, + 311565274989772, + ]), + xy2d: FieldElement51([ + 1003649078149734, + 545233927396469, + 1849786171789880, + 1318943684880434, + 280345687170552, + ]), + }, + ]), + ]); + +/// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = + NafLookupTable8([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3540182452943730, + 2497478415033846, + 2521227595762870, + 1462984067271729, + 2389212253076811, + ]), + y_minus_x: FieldElement51([ + 62697248952638, + 204681361388450, + 631292143396476, + 338455783676468, + 1213667448819585, + ]), + xy2d: FieldElement51([ + 301289933810280, + 1259582250014073, + 1422107436869536, + 796239922652654, + 1953934009299142, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1601611775252272, + 1720807796594148, + 1132070835939856, + 3512254832574799, + 2147779492816910, + ]), + y_minus_x: FieldElement51([ + 316559037616741, + 2177824224946892, + 1459442586438991, + 1461528397712656, + 751590696113597, + ]), + xy2d: FieldElement51([ + 1850748884277385, + 1200145853858453, + 1068094770532492, + 672251375690438, + 1586055907191707, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 769950342298400, + 2384754244604994, + 3095885746880802, + 3225892188161580, + 2977876099231263, + ]), + y_minus_x: FieldElement51([ + 425251763115706, + 608463272472562, + 442562545713235, + 837766094556764, + 374555092627893, + ]), + xy2d: FieldElement51([ + 1086255230780037, + 274979815921559, + 1960002765731872, + 929474102396301, + 1190409889297339, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2916800678241215, + 2065379846933858, + 2622030924071124, + 2602788184473875, + 1233371373142984, + ]), + y_minus_x: FieldElement51([ + 2019367628972465, + 676711900706637, + 110710997811333, + 1108646842542025, + 517791959672113, + ]), + xy2d: FieldElement51([ + 965130719900578, + 247011430587952, + 526356006571389, + 91986625355052, + 2157223321444601, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1802695059464988, + 1664899123557221, + 2845359304426105, + 2160434469266658, + 3179370264440279, + ]), + y_minus_x: FieldElement51([ + 1725674970513508, + 1933645953859181, + 1542344539275782, + 1767788773573747, + 1297447965928905, + ]), + xy2d: FieldElement51([ + 1381809363726107, + 1430341051343062, + 2061843536018959, + 1551778050872521, + 2036394857967624, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4222693909998302, + 2779866139518454, + 1619374932191226, + 2207306624415883, + 1169170329061080, + ]), + y_minus_x: FieldElement51([ + 2070390218572616, + 1458919061857835, + 624171843017421, + 1055332792707765, + 433987520732508, + ]), + xy2d: FieldElement51([ + 893653801273833, + 1168026499324677, + 1242553501121234, + 1306366254304474, + 1086752658510815, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2465253816303469, + 3191571337672685, + 1159882208056013, + 2569188183312765, + 621213314200686, + ]), + y_minus_x: FieldElement51([ + 1971678598905747, + 338026507889165, + 762398079972271, + 655096486107477, + 42299032696322, + ]), + xy2d: FieldElement51([ + 177130678690680, + 1754759263300204, + 1864311296286618, + 1180675631479880, + 1292726903152791, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1913163449625248, + 2712579013977241, + 2193883288642313, + 1008900146920800, + 1721983679009502, + ]), + y_minus_x: FieldElement51([ + 1070401523076875, + 1272492007800961, + 1910153608563310, + 2075579521696771, + 1191169788841221, + ]), + xy2d: FieldElement51([ + 692896803108118, + 500174642072499, + 2068223309439677, + 1162190621851337, + 1426986007309901, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1819621230288238, + 2735700366193240, + 1755134670739586, + 3080648199451191, + 4172807995775876, + ]), + y_minus_x: FieldElement51([ + 992069868904071, + 799011518185730, + 1777586403832768, + 1134820506145684, + 1999461475558530, + ]), + xy2d: FieldElement51([ + 425204543703124, + 2040469794090382, + 1651690622153809, + 1500530168597569, + 1253908377065966, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2105824306960939, + 1387520302709358, + 3633176580451016, + 2211816663841753, + 1629085891776489, + ]), + y_minus_x: FieldElement51([ + 1485201376284999, + 1022406647424656, + 504181009209019, + 962621520820995, + 590876713147230, + ]), + xy2d: FieldElement51([ + 265873406365287, + 1192742653492898, + 88553098803050, + 525037770869640, + 1266933811251234, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3552316659826612, + 1254279525791875, + 1609927932077699, + 3578654071679972, + 3750681296069893, + ]), + y_minus_x: FieldElement51([ + 37186803519861, + 1404297334376301, + 578519728836650, + 1740727951192592, + 2095534282477028, + ]), + xy2d: FieldElement51([ + 833234263154399, + 2023862470013762, + 1854137933982069, + 853924318090959, + 1589812702805850, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3679150557957763, + 1319179453661745, + 497496853611112, + 2665464286942351, + 1208137952365560, + ]), + y_minus_x: FieldElement51([ + 1654513078530905, + 907489875842908, + 126098711296368, + 1726320004173677, + 28269495058173, + ]), + xy2d: FieldElement51([ + 114436686957443, + 532739313025996, + 115428841215897, + 2191499400074366, + 370280402676434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1111146849833253, + 2016430049079759, + 1860522747477948, + 3537164738290194, + 4137142824844184, + ]), + y_minus_x: FieldElement51([ + 429069864577128, + 975327637149449, + 237881983565075, + 1654761232378630, + 2122527599091807, + ]), + xy2d: FieldElement51([ + 2093793463548278, + 754827233241879, + 1420389751719629, + 1829952782588138, + 2011865756773717, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 676293365438898, + 2850296017886344, + 1205350322490195, + 2763699392265669, + 2133931188538142, + ]), + y_minus_x: FieldElement51([ + 48340340349120, + 1299261101494832, + 1137329686775218, + 1534848106674340, + 1351662218216799, + ]), + xy2d: FieldElement51([ + 1904520614137939, + 1590301001714014, + 215781420985270, + 2043534301034629, + 1970888949300424, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2365217962409710, + 2061307169694064, + 1887478590157603, + 2169639621284316, + 2373810867477200, + ]), + y_minus_x: FieldElement51([ + 1020052624656948, + 1260412094216707, + 366721640607121, + 585331442306596, + 345876457758061, + ]), + xy2d: FieldElement51([ + 975390299880933, + 1066555195234642, + 12651997758352, + 1184252205433068, + 1058378155074223, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1431537716602643, + 2024827957433813, + 3746434518400495, + 1087794891033550, + 2156817571680455, + ]), + y_minus_x: FieldElement51([ + 929288033346881, + 255179964546973, + 711057989588035, + 208899572612840, + 185348357387383, + ]), + xy2d: FieldElement51([ + 823689746424808, + 47266130989546, + 209403309368097, + 1100966895202707, + 710792075292719, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2311213117823762, + 3296668540922318, + 2004276520649823, + 1861500579441125, + 3148029033359833, + ]), + y_minus_x: FieldElement51([ + 1563693677475261, + 1843782073741194, + 1950700654453170, + 911540858113949, + 2085151496302359, + ]), + xy2d: FieldElement51([ + 1427880892005482, + 106216431121745, + 42608394782284, + 1217295886989793, + 1514235272796882, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3544335535746750, + 2367994491347456, + 2567261456502612, + 1854058085060971, + 2263545563461076, + ]), + y_minus_x: FieldElement51([ + 787426011300053, + 2105981035769060, + 1130476291127206, + 1748659348100075, + 53470983013756, + ]), + xy2d: FieldElement51([ + 553548273865386, + 5927805718390, + 65184587381926, + 633576679686953, + 576048559439973, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 993787326657446, + 3868807161609258, + 1615796046728943, + 2514644292681953, + 2059021068660907, + ]), + y_minus_x: FieldElement51([ + 251010270518880, + 1681684095763484, + 1521949356387564, + 431593457045116, + 1855308922422910, + ]), + xy2d: FieldElement51([ + 618490909691959, + 1257497595618257, + 202952467594088, + 35577762721238, + 1494883566841973, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1673474571932262, + 2409784519770613, + 2636095316260487, + 2761112584601925, + 3333713288149876, + ]), + y_minus_x: FieldElement51([ + 1600640202645197, + 1019569075331823, + 1041916487915822, + 1680448171313267, + 2126903137527901, + ]), + xy2d: FieldElement51([ + 894964745143659, + 106116880092678, + 1009869382959477, + 317866368542032, + 1986983122763912, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1765281781276487, + 2863247187455184, + 2589075472439062, + 1386435905543054, + 2182338478845320, + ]), + y_minus_x: FieldElement51([ + 1144730936996693, + 2213315231278180, + 1489676672185125, + 665039429138074, + 1131283313040268, + ]), + xy2d: FieldElement51([ + 2004734176670602, + 1738311085075235, + 418866995976618, + 1050782508034394, + 577747313404652, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2185209688340293, + 1309276076461009, + 2514740038571278, + 3994889904012999, + 3018098826231021, + ]), + y_minus_x: FieldElement51([ + 1405936970888515, + 1754621155316654, + 1211862168554999, + 1813045702919083, + 997853418197172, + ]), + xy2d: FieldElement51([ + 82037622045021, + 1646398333621944, + 613095452763466, + 1312329542583705, + 81014679202721, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2389287991277873, + 403851022333257, + 1597473361477193, + 2953351602509212, + 2135174663049062, + ]), + y_minus_x: FieldElement51([ + 1826548187201150, + 302299893734126, + 1475477168615781, + 842617616347376, + 1438600873676130, + ]), + xy2d: FieldElement51([ + 663049852468609, + 1649295727846569, + 1048009692742781, + 628866177992421, + 1914360327429204, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1795645928096646, + 306878154408959, + 2924901319092394, + 2801261341654799, + 1653782432983523, + ]), + y_minus_x: FieldElement51([ + 2077597317438627, + 212642017882064, + 674844477518888, + 875487498687554, + 2060550250171182, + ]), + xy2d: FieldElement51([ + 1420448018683809, + 1032663994771382, + 1341927003385267, + 1340360916546159, + 1988547473895228, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1082660122598844, + 2545055705583789, + 3888919679589007, + 1670283344995811, + 3403239134794618, + ]), + y_minus_x: FieldElement51([ + 90430593339788, + 1838338032241275, + 571293238480915, + 1639938867416883, + 257378872001111, + ]), + xy2d: FieldElement51([ + 1528535658865034, + 1516636853043960, + 787000569996728, + 1464531394704506, + 1684822625133795, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 811329918113934, + 2783463529007378, + 1769095754634835, + 2970819621866866, + 881037178164325, + ]), + y_minus_x: FieldElement51([ + 1784566501964517, + 433890943689325, + 1186055625589419, + 1496077405487512, + 1731807117886548, + ]), + xy2d: FieldElement51([ + 424909811816304, + 1355993963741797, + 409606483251841, + 455665350637068, + 1617009023642808, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2478728492077816, + 2780289048655501, + 2328687177473769, + 4107341333582032, + 1316147724308250, + ]), + y_minus_x: FieldElement51([ + 1617420574301156, + 1741273341070467, + 667135503486508, + 2100436564640123, + 1032223920000865, + ]), + xy2d: FieldElement51([ + 1753947659404033, + 247279202390193, + 1819288880178945, + 737334285670249, + 1037873664856104, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1762568490530034, + 673742465299012, + 2054571050635888, + 2040165159255111, + 3040123733327257, + ]), + y_minus_x: FieldElement51([ + 1627187989987422, + 1686331580821752, + 1309895873498183, + 719718719104086, + 300063199808722, + ]), + xy2d: FieldElement51([ + 238176707016164, + 1440454788877048, + 203336037573144, + 1437789888677072, + 101522256664211, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1895216760098480, + 1934324337975022, + 3677350688973167, + 2536415965456176, + 714678003308640, + ]), + y_minus_x: FieldElement51([ + 508185358728815, + 1691320535341855, + 2168887448239256, + 1035124393070661, + 1936603999698584, + ]), + xy2d: FieldElement51([ + 390562831571647, + 1390223890708972, + 1383183990676371, + 435998174196410, + 1882086414390730, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3747620842612921, + 2081794785291195, + 3284594056262745, + 2090090346797895, + 2581692978935809, + ]), + y_minus_x: FieldElement51([ + 244144781251265, + 1290834426417077, + 1888701171101942, + 1233922456644870, + 241117402207491, + ]), + xy2d: FieldElement51([ + 1266169390045455, + 1148042013187970, + 878921907853942, + 1815738019658093, + 908920199341621, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2521768507305118, + 953557056811112, + 2015863732865770, + 1358382511861315, + 2835421647899992, + ]), + y_minus_x: FieldElement51([ + 2239837206240498, + 330928973149665, + 422268062913642, + 1481280019493032, + 619879520439841, + ]), + xy2d: FieldElement51([ + 1360166735366017, + 1770556573948510, + 1395061284191031, + 1814003148068126, + 522781147076884, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2611794802645686, + 707234844948070, + 1314059396506491, + 2919250341703934, + 2161831667832785, + ]), + y_minus_x: FieldElement51([ + 934831784182383, + 433734253968318, + 1660867106725771, + 1968393082772831, + 873946300968490, + ]), + xy2d: FieldElement51([ + 26306827827554, + 430884999378685, + 1504310424376419, + 1761358720837522, + 542195685418530, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1762131062631725, + 3123952634417535, + 3619918390837537, + 2909990877347294, + 1411594230004385, + ]), + y_minus_x: FieldElement51([ + 538272372224622, + 1425714779586199, + 588313661410172, + 1497062084392578, + 1602174047128512, + ]), + xy2d: FieldElement51([ + 907490361939255, + 1963620338391363, + 626927432296975, + 1250748516081414, + 959901171882527, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1335066153744413, + 2887804660779657, + 2653073855954038, + 2765226981667422, + 938831784476763, + ]), + y_minus_x: FieldElement51([ + 296699434737224, + 2047543711075683, + 2076451038937139, + 227783599906901, + 1602062110967627, + ]), + xy2d: FieldElement51([ + 1574834773194203, + 1384279952062839, + 393652417255803, + 2166968242848859, + 1552890441390820, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1619646774410947, + 1576090644023562, + 3035228391320965, + 1735328519940543, + 2355324535937066, + ]), + y_minus_x: FieldElement51([ + 1024074573633446, + 957088456885874, + 1690425531356997, + 2102187380180052, + 1082544623222033, + ]), + xy2d: FieldElement51([ + 1871906170635853, + 1719383891167200, + 1584032250247862, + 823764804192117, + 2244048510084261, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 642147846489775, + 3334304977145699, + 305205716788147, + 2589176626729533, + 2224680511484174, + ]), + y_minus_x: FieldElement51([ + 1734162377166545, + 260713621840346, + 157174591942595, + 952544272517991, + 222818702471733, + ]), + xy2d: FieldElement51([ + 1213115494182947, + 286778704335711, + 2130189536016490, + 308349182281342, + 1217623948685491, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3360052266973635, + 1843486583624091, + 1561693837124349, + 1084041964025479, + 1866270922024009, + ]), + y_minus_x: FieldElement51([ + 460705465481210, + 1968151453817859, + 497005926994844, + 625618055866751, + 2176893440866887, + ]), + xy2d: FieldElement51([ + 1655800250476757, + 2036588542300609, + 666447448675243, + 1615721995750683, + 1508669225186765, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2245948203759141, + 1058306669699396, + 1452898014240582, + 3961024141962768, + 1633235287338608, + ]), + y_minus_x: FieldElement51([ + 986647273684279, + 1507266907811370, + 1260572633649005, + 2071672342077446, + 695976026010857, + ]), + xy2d: FieldElement51([ + 1312356620823495, + 1635278548098567, + 901946076841033, + 585120475533168, + 1240667113237384, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2313723935779695, + 1506054666773895, + 996040223525031, + 636592914999692, + 1497801917020297, + ]), + y_minus_x: FieldElement51([ + 292042016419794, + 1158932298133044, + 2062611870323738, + 1946058478962569, + 1749165808126286, + ]), + xy2d: FieldElement51([ + 654683942212830, + 1526897351349087, + 2006818439922838, + 2194919327350361, + 1451960776874416, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3015041017808905, + 2951823141773809, + 2584865668253675, + 2508192032998563, + 2582137700042019, + ]), + y_minus_x: FieldElement51([ + 1628123495344283, + 2072923641214546, + 1647225812023982, + 855655925244679, + 1758126430071140, + ]), + xy2d: FieldElement51([ + 1615895096489599, + 275295258643784, + 937665541219916, + 1313496726746346, + 1186468946422626, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1603070202850694, + 2072127623773242, + 1692648737212158, + 2493373404187852, + 1248948672117105, + ]), + y_minus_x: FieldElement51([ + 11167836031898, + 596565174397990, + 2196351068723859, + 314744641791907, + 1102014997250781, + ]), + xy2d: FieldElement51([ + 1409047922401191, + 69960384467966, + 688103515547600, + 1309746102488044, + 150292892873778, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1986083055103168, + 691715819340300, + 1361811659746933, + 3459052030333434, + 1063594696046061, + ]), + y_minus_x: FieldElement51([ + 1201987338414749, + 2198784582460616, + 1203335513981498, + 489243077045066, + 2205278143582433, + ]), + xy2d: FieldElement51([ + 2034744376624534, + 2077387101466387, + 148448542974969, + 1502697574577258, + 473186584705655, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 472016956315960, + 720786972252993, + 2840633661190043, + 3150798753357827, + 2816563335499153, + ]), + y_minus_x: FieldElement51([ + 253464247569755, + 168314237403057, + 511780806170295, + 1058862316549135, + 1646858476817137, + ]), + xy2d: FieldElement51([ + 595092995922219, + 1491311840717691, + 291581784452778, + 1569186646367854, + 1031385061400544, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3483137021572755, + 1526955102024322, + 2778006642704458, + 457549634924205, + 1097420237736736, + ]), + y_minus_x: FieldElement51([ + 1246991699537710, + 81367319519439, + 530844036072196, + 163656863755855, + 1950742455979290, + ]), + xy2d: FieldElement51([ + 191532664076407, + 539378506082089, + 1021612562876554, + 1026603384732632, + 1773368780410653, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4144620731387879, + 590179521333342, + 4034023318016108, + 2255745030335426, + 2699746851701250, + ]), + y_minus_x: FieldElement51([ + 2206599697359952, + 553895797384417, + 181689161933786, + 1153123447919104, + 778568064152659, + ]), + xy2d: FieldElement51([ + 1706307000059211, + 1885601289314487, + 889758608505788, + 550131729999853, + 1006862664714268, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3210197754285058, + 2048500453422630, + 3403309827888207, + 927154428508963, + 4199813798872019, + ]), + y_minus_x: FieldElement51([ + 992058915374933, + 476120535358775, + 1973648780784340, + 2025282643598818, + 2182318983793230, + ]), + xy2d: FieldElement51([ + 1343440812005821, + 1316045839091795, + 1884951299078063, + 1765919609219175, + 2197567554627988, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3129247779382818, + 4415026969054274, + 1900265885969643, + 1528796215447059, + 2172730393748688, + ]), + y_minus_x: FieldElement51([ + 1773355092297603, + 64654329538271, + 1332124041660957, + 748492100858001, + 895500006200535, + ]), + xy2d: FieldElement51([ + 2000840647851980, + 546565968824914, + 420633283457524, + 195470736374507, + 1958689297569520, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 743138980705446, + 3411117504637167, + 2591389959690621, + 2380042066577202, + 3022267940115114, + ]), + y_minus_x: FieldElement51([ + 165947002229363, + 115186103724967, + 1068573292121517, + 1842565776920938, + 1969395681111987, + ]), + xy2d: FieldElement51([ + 553322266190633, + 234265665613185, + 484544650202821, + 1238773526575826, + 2017991917953668, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2581954631514051, + 1245093644265357, + 3537016673825374, + 1834216551713857, + 923978372152807, + ]), + y_minus_x: FieldElement51([ + 1855378315339552, + 890045579230758, + 1764718173975590, + 197904186055854, + 1718129022310327, + ]), + xy2d: FieldElement51([ + 1278162928734862, + 1894118254109862, + 987503995465517, + 177406744098996, + 781538103127693, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1996603431230215, + 1191888797552937, + 1207440075928499, + 2765853449051137, + 2525314961343288, + ]), + y_minus_x: FieldElement51([ + 808903879370889, + 990820108751280, + 1084429472258867, + 1078562781312589, + 254514692695625, + ]), + xy2d: FieldElement51([ + 615855140068469, + 586046731175395, + 693470779212674, + 1964537100203868, + 1350330550265229, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3344544372023708, + 720386671449874, + 2480841360702110, + 2036034126860286, + 2015744690201389, + ]), + y_minus_x: FieldElement51([ + 1337446193390478, + 1984110761311871, + 746489405020285, + 407347127604128, + 1740475330360596, + ]), + xy2d: FieldElement51([ + 140840424783613, + 1063284623568331, + 1136446106453878, + 372042229029799, + 442607248430694, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2330781679120937, + 376801425148230, + 2032603686676107, + 1488926293635130, + 1317278311532959, + ]), + y_minus_x: FieldElement51([ + 1290116731380016, + 2166899563471713, + 831997001838078, + 870954980505220, + 2108537278055823, + ]), + xy2d: FieldElement51([ + 1912719171026343, + 846194720551034, + 2043988124740726, + 993234269653961, + 421229796383281, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2651184584992902, + 2775702557638963, + 2539786009779572, + 2575974880015305, + 2122619079836732, + ]), + y_minus_x: FieldElement51([ + 1154054290132562, + 931753998725577, + 1647742001778052, + 865765466488226, + 1083816107290025, + ]), + xy2d: FieldElement51([ + 986341121095108, + 1522330369638573, + 1990880546211047, + 501525962272123, + 198539304862139, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1496414019192687, + 3991034436173951, + 3380311659062196, + 2854747485359158, + 3346958036643152, + ]), + y_minus_x: FieldElement51([ + 805612068303425, + 1891790027761335, + 1587008567571549, + 722120737390201, + 378156757163816, + ]), + xy2d: FieldElement51([ + 1588994517921951, + 977362751042302, + 1329302387067714, + 2069348224564088, + 1586007159625211, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2490539421551682, + 1985699850375015, + 2331762317128172, + 4145097393776678, + 2521049460190674, + ]), + y_minus_x: FieldElement51([ + 615817553313996, + 2245962768078178, + 482564324326173, + 2101336843140780, + 1240914880829407, + ]), + xy2d: FieldElement51([ + 1438242482238189, + 874267817785463, + 1620810389770625, + 866155221338671, + 1040426546798301, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2403083624110300, + 2548561409802975, + 2492699136535911, + 2358289519456539, + 3203964320363148, + ]), + y_minus_x: FieldElement51([ + 1913986535403097, + 1977163223054199, + 1972905914623196, + 1650122133472502, + 1905849310819035, + ]), + xy2d: FieldElement51([ + 858174816360838, + 614595356564037, + 1099584959044836, + 636998087084906, + 1070393269058348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3666695924830668, + 3585640662737501, + 2372994528684236, + 2628565977288995, + 3482812783469694, + ]), + y_minus_x: FieldElement51([ + 1994161359147952, + 2198039369802658, + 62790022842537, + 1522306785848169, + 951223194802833, + ]), + xy2d: FieldElement51([ + 852296621440717, + 431889737774209, + 370755457746189, + 437604073958073, + 627857326892757, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1794955764684156, + 2586904290013612, + 1322647643615887, + 856117964085888, + 2652432778663153, + ]), + y_minus_x: FieldElement51([ + 933592377399646, + 78031722952813, + 926049890685253, + 1471649501316246, + 33789909190376, + ]), + xy2d: FieldElement51([ + 1479319468832059, + 203906207621608, + 659828362330083, + 44358398435755, + 1273573524210803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1592342143350813, + 3227219208247713, + 2345240352078765, + 2577750109932929, + 2933512841197243, + ]), + y_minus_x: FieldElement51([ + 2184946892642995, + 1517382324576002, + 1557940277419806, + 2170635134813213, + 747314658627002, + ]), + xy2d: FieldElement51([ + 1823193620577742, + 1135817878516419, + 1731253819308581, + 1031652967267804, + 2123506616999453, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1346190246005805, + 2052692552023851, + 1718128041785940, + 2491557332978474, + 3474370880388305, + ]), + y_minus_x: FieldElement51([ + 424776012994573, + 281050757243423, + 626466040846420, + 990194703866532, + 38571969885982, + ]), + xy2d: FieldElement51([ + 192408346595466, + 1054889725292349, + 584097975693004, + 1447909807397749, + 2134645004369136, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3169895788615063, + 3503097743181446, + 601598510029975, + 1422812237223371, + 2121009661378329, + ]), + y_minus_x: FieldElement51([ + 1603348391996783, + 2066143816131699, + 1789627290363958, + 2145705961178118, + 1985578641438222, + ]), + xy2d: FieldElement51([ + 352633958653380, + 856927627345554, + 793925083122702, + 93551575767286, + 1222010153634215, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1756866499986349, + 911731956999969, + 2707505543214075, + 4006920335263786, + 822501008147910, + ]), + y_minus_x: FieldElement51([ + 1094036422864347, + 1897208881572508, + 1503607738246960, + 1901060196071406, + 294068411105729, + ]), + xy2d: FieldElement51([ + 587776484399576, + 1116861711228807, + 343398777436088, + 936544065763093, + 1643746750211060, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3477749685790410, + 267997399528836, + 2953780922004404, + 3252368924080907, + 3787792887348381, + ]), + y_minus_x: FieldElement51([ + 2042368155872443, + 41662387210459, + 1676313264498480, + 1333968523426810, + 1765708383352310, + ]), + xy2d: FieldElement51([ + 1453394896690938, + 1585795827439909, + 1469309456804303, + 1294645324464404, + 2042954198665899, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1810069207599881, + 1358344669503239, + 1989371257548167, + 2316270051121225, + 3019675451276507, + ]), + y_minus_x: FieldElement51([ + 1866114438287676, + 1663420339568364, + 1437691317033088, + 538298302628038, + 1212711449614363, + ]), + xy2d: FieldElement51([ + 1769235035677897, + 1562012115317882, + 31277513664750, + 536198657928416, + 1976134212537183, + ]), + }, + ]); diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/field.rs new file mode 100644 index 0000000..1cb7778 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/field.rs @@ -0,0 +1,563 @@ +// -*- mode: rust; coding: utf-8; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit +//! limbs with \\(128\\)-bit products. + +use core::fmt::Debug; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Sub, SubAssign}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use zeroize::Zeroize; + +/// A `FieldElement51` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// In the 64-bit implementation, a `FieldElement` is represented in +/// radix \\(2\^{51}\\) as five `u64`s; the coefficients are allowed to +/// grow up to \\(2\^{54}\\) between reductions modulo \\(p\\). +/// +/// # Note +/// +/// The `curve25519_dalek::field` module provides a type alias +/// `curve25519_dalek::field::FieldElement` to either `FieldElement51` +/// or `FieldElement2625`. +/// +/// The backend-specific type `FieldElement51` should not be used +/// outside of the `curve25519_dalek::field` module. +#[derive(Copy, Clone)] +pub struct FieldElement51(pub (crate) [u64; 5]); + +impl Debug for FieldElement51 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "FieldElement51({:?})", &self.0[..]) + } +} + +impl Zeroize for FieldElement51 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl<'b> AddAssign<&'b FieldElement51> for FieldElement51 { + fn add_assign(&mut self, _rhs: &'b FieldElement51) { + for i in 0..5 { + self.0[i] += _rhs.0[i]; + } + } +} + +impl<'a, 'b> Add<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn add(self, _rhs: &'b FieldElement51) -> FieldElement51 { + let mut output = *self; + output += _rhs; + output + } +} + +impl<'b> SubAssign<&'b FieldElement51> for FieldElement51 { + fn sub_assign(&mut self, _rhs: &'b FieldElement51) { + let result = (self as &FieldElement51) - _rhs; + self.0 = result.0; + } +} + +impl<'a, 'b> Sub<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn sub(self, _rhs: &'b FieldElement51) -> FieldElement51 { + // To avoid underflow, first add a multiple of p. + // Choose 16*p = p << 4 to be larger than 54-bit _rhs. + // + // If we could statically track the bitlengths of the limbs + // of every FieldElement51, we could choose a multiple of p + // just bigger than _rhs and avoid having to do a reduction. + // + // Since we don't yet have type-level integers to do this, we + // have to add an explicit reduction call here. + FieldElement51::reduce([ + (self.0[0] + 36028797018963664u64) - _rhs.0[0], + (self.0[1] + 36028797018963952u64) - _rhs.0[1], + (self.0[2] + 36028797018963952u64) - _rhs.0[2], + (self.0[3] + 36028797018963952u64) - _rhs.0[3], + (self.0[4] + 36028797018963952u64) - _rhs.0[4], + ]) + } +} + +impl<'b> MulAssign<&'b FieldElement51> for FieldElement51 { + fn mul_assign(&mut self, _rhs: &'b FieldElement51) { + let result = (self as &FieldElement51) * _rhs; + self.0 = result.0; + } +} + +impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn mul(self, _rhs: &'b FieldElement51) -> FieldElement51 { + /// Helper function to multiply two 64-bit integers with 128 + /// bits of output. + #[inline(always)] + fn m(x: u64, y: u64) -> u128 { (x as u128) * (y as u128) } + + // Alias self, _rhs for more readable formulas + let a: &[u64; 5] = &self.0; + let b: &[u64; 5] = &_rhs.0; + + // Precondition: assume input limbs a[i], b[i] are bounded as + // + // a[i], b[i] < 2^(51 + b) + // + // where b is a real parameter measuring the "bit excess" of the limbs. + + // 64-bit precomputations to avoid 128-bit multiplications. + // + // This fits into a u64 whenever 51 + b + lg(19) < 64. + // + // Since 51 + b + lg(19) < 51 + 4.25 + b + // = 55.25 + b, + // this fits if b < 8.75. + let b1_19 = b[1] * 19; + let b2_19 = b[2] * 19; + let b3_19 = b[3] * 19; + let b4_19 = b[4] * 19; + + // Multiply to get 128-bit coefficients of output + let c0: u128 = m(a[0],b[0]) + m(a[4],b1_19) + m(a[3],b2_19) + m(a[2],b3_19) + m(a[1],b4_19); + let mut c1: u128 = m(a[1],b[0]) + m(a[0],b[1]) + m(a[4],b2_19) + m(a[3],b3_19) + m(a[2],b4_19); + let mut c2: u128 = m(a[2],b[0]) + m(a[1],b[1]) + m(a[0],b[2]) + m(a[4],b3_19) + m(a[3],b4_19); + let mut c3: u128 = m(a[3],b[0]) + m(a[2],b[1]) + m(a[1],b[2]) + m(a[0],b[3]) + m(a[4],b4_19); + let mut c4: u128 = m(a[4],b[0]) + m(a[3],b[1]) + m(a[2],b[2]) + m(a[1],b[3]) + m(a[0],b[4]); + + // How big are the c[i]? We have + // + // c[i] < 2^(102 + 2*b) * (1+i + (4-i)*19) + // < 2^(102 + lg(1 + 4*19) + 2*b) + // < 2^(108.27 + 2*b) + // + // The carry (c[i] >> 51) fits into a u64 when + // 108.27 + 2*b - 51 < 64 + // 2*b < 6.73 + // b < 3.365. + // + // So we require b < 3 to ensure this fits. + debug_assert!(a[0] < (1 << 54)); debug_assert!(b[0] < (1 << 54)); + debug_assert!(a[1] < (1 << 54)); debug_assert!(b[1] < (1 << 54)); + debug_assert!(a[2] < (1 << 54)); debug_assert!(b[2] < (1 << 54)); + debug_assert!(a[3] < (1 << 54)); debug_assert!(b[3] < (1 << 54)); + debug_assert!(a[4] < (1 << 54)); debug_assert!(b[4] < (1 << 54)); + + // Casting to u64 and back tells the compiler that the carry is + // bounded by 2^64, so that the addition is a u128 + u64 rather + // than u128 + u128. + + const LOW_51_BIT_MASK: u64 = (1u64 << 51) - 1; + let mut out = [0u64; 5]; + + c1 += ((c0 >> 51) as u64) as u128; + out[0] = (c0 as u64) & LOW_51_BIT_MASK; + + c2 += ((c1 >> 51) as u64) as u128; + out[1] = (c1 as u64) & LOW_51_BIT_MASK; + + c3 += ((c2 >> 51) as u64) as u128; + out[2] = (c2 as u64) & LOW_51_BIT_MASK; + + c4 += ((c3 >> 51) as u64) as u128; + out[3] = (c3 as u64) & LOW_51_BIT_MASK; + + let carry: u64 = (c4 >> 51) as u64; + out[4] = (c4 as u64) & LOW_51_BIT_MASK; + + // To see that this does not overflow, we need out[0] + carry * 19 < 2^64. + // + // c4 < a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0 + (carry from c3) + // < 5*(2^(51 + b) * 2^(51 + b)) + (carry from c3) + // < 2^(102 + 2*b + lg(5)) + 2^64. + // + // When b < 3 we get + // + // c4 < 2^110.33 so that carry < 2^59.33 + // + // so that + // + // out[0] + carry * 19 < 2^51 + 19 * 2^59.33 < 2^63.58 + // + // and there is no overflow. + out[0] = out[0] + carry * 19; + + // Now out[1] < 2^51 + 2^(64 -51) = 2^51 + 2^13 < 2^(51 + epsilon). + out[1] += out[0] >> 51; + out[0] &= LOW_51_BIT_MASK; + + // Now out[i] < 2^(51 + epsilon) for all i. + FieldElement51(out) + } +} + +impl<'a> Neg for &'a FieldElement51 { + type Output = FieldElement51; + fn neg(self) -> FieldElement51 { + let mut output = *self; + output.negate(); + output + } +} + +impl ConditionallySelectable for FieldElement51 { + fn conditional_select( + a: &FieldElement51, + b: &FieldElement51, + choice: Choice, + ) -> FieldElement51 { + FieldElement51([ + u64::conditional_select(&a.0[0], &b.0[0], choice), + u64::conditional_select(&a.0[1], &b.0[1], choice), + u64::conditional_select(&a.0[2], &b.0[2], choice), + u64::conditional_select(&a.0[3], &b.0[3], choice), + u64::conditional_select(&a.0[4], &b.0[4], choice), + ]) + } + + fn conditional_swap(a: &mut FieldElement51, b: &mut FieldElement51, choice: Choice) { + u64::conditional_swap(&mut a.0[0], &mut b.0[0], choice); + u64::conditional_swap(&mut a.0[1], &mut b.0[1], choice); + u64::conditional_swap(&mut a.0[2], &mut b.0[2], choice); + u64::conditional_swap(&mut a.0[3], &mut b.0[3], choice); + u64::conditional_swap(&mut a.0[4], &mut b.0[4], choice); + } + + fn conditional_assign(&mut self, other: &FieldElement51, choice: Choice) { + self.0[0].conditional_assign(&other.0[0], choice); + self.0[1].conditional_assign(&other.0[1], choice); + self.0[2].conditional_assign(&other.0[2], choice); + self.0[3].conditional_assign(&other.0[3], choice); + self.0[4].conditional_assign(&other.0[4], choice); + } +} + +impl FieldElement51 { + /// Invert the sign of this field element + pub fn negate(&mut self) { + // See commentary in the Sub impl + let neg = FieldElement51::reduce([ + 36028797018963664u64 - self.0[0], + 36028797018963952u64 - self.0[1], + 36028797018963952u64 - self.0[2], + 36028797018963952u64 - self.0[3], + 36028797018963952u64 - self.0[4], + ]); + self.0 = neg.0; + } + + /// Construct zero. + pub fn zero() -> FieldElement51 { + FieldElement51([ 0, 0, 0, 0, 0 ]) + } + + /// Construct one. + pub fn one() -> FieldElement51 { + FieldElement51([ 1, 0, 0, 0, 0 ]) + } + + /// Construct -1. + pub fn minus_one() -> FieldElement51 { + FieldElement51([2251799813685228, 2251799813685247, 2251799813685247, 2251799813685247, 2251799813685247]) + } + + /// Given 64-bit input limbs, reduce to enforce the bound 2^(51 + epsilon). + #[inline(always)] + fn reduce(mut limbs: [u64; 5]) -> FieldElement51 { + const LOW_51_BIT_MASK: u64 = (1u64 << 51) - 1; + + // Since the input limbs are bounded by 2^64, the biggest + // carry-out is bounded by 2^13. + // + // The biggest carry-in is c4 * 19, resulting in + // + // 2^51 + 19*2^13 < 2^51.0000000001 + // + // Because we don't need to canonicalize, only to reduce the + // limb sizes, it's OK to do a "weak reduction", where we + // compute the carry-outs in parallel. + + let c0 = limbs[0] >> 51; + let c1 = limbs[1] >> 51; + let c2 = limbs[2] >> 51; + let c3 = limbs[3] >> 51; + let c4 = limbs[4] >> 51; + + limbs[0] &= LOW_51_BIT_MASK; + limbs[1] &= LOW_51_BIT_MASK; + limbs[2] &= LOW_51_BIT_MASK; + limbs[3] &= LOW_51_BIT_MASK; + limbs[4] &= LOW_51_BIT_MASK; + + limbs[0] += c4 * 19; + limbs[1] += c0; + limbs[2] += c1; + limbs[3] += c2; + limbs[4] += c3; + + FieldElement51(limbs) + } + + /// Load a `FieldElement51` from the low 255 bits of a 256-bit + /// input. + /// + /// # Warning + /// + /// This function does not check that the input used the canonical + /// representative. It masks the high bit, but it will happily + /// decode 2^255 - 18 to 1. Applications that require a canonical + /// encoding of every field element should decode, re-encode to + /// the canonical encoding, and check that the input was + /// canonical. + /// + pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement51 { + let load8 = |input: &[u8]| -> u64 { + (input[0] as u64) + | ((input[1] as u64) << 8) + | ((input[2] as u64) << 16) + | ((input[3] as u64) << 24) + | ((input[4] as u64) << 32) + | ((input[5] as u64) << 40) + | ((input[6] as u64) << 48) + | ((input[7] as u64) << 56) + }; + + let low_51_bit_mask = (1u64 << 51) - 1; + FieldElement51( + // load bits [ 0, 64), no shift + [ load8(&bytes[ 0..]) & low_51_bit_mask + // load bits [ 48,112), shift to [ 51,112) + , (load8(&bytes[ 6..]) >> 3) & low_51_bit_mask + // load bits [ 96,160), shift to [102,160) + , (load8(&bytes[12..]) >> 6) & low_51_bit_mask + // load bits [152,216), shift to [153,216) + , (load8(&bytes[19..]) >> 1) & low_51_bit_mask + // load bits [192,256), shift to [204,112) + , (load8(&bytes[24..]) >> 12) & low_51_bit_mask + ]) + } + + /// Serialize this `FieldElement51` to a 32-byte array. The + /// encoding is canonical. + pub fn to_bytes(&self) -> [u8; 32] { + // Let h = limbs[0] + limbs[1]*2^51 + ... + limbs[4]*2^204. + // + // Write h = pq + r with 0 <= r < p. + // + // We want to compute r = h mod p. + // + // If h < 2*p = 2^256 - 38, + // then q = 0 or 1, + // + // with q = 0 when h < p + // and q = 1 when h >= p. + // + // Notice that h >= p <==> h + 19 >= p + 19 <==> h + 19 >= 2^255. + // Therefore q can be computed as the carry bit of h + 19. + + // First, reduce the limbs to ensure h < 2*p. + let mut limbs = FieldElement51::reduce(self.0).0; + + let mut q = (limbs[0] + 19) >> 51; + q = (limbs[1] + q) >> 51; + q = (limbs[2] + q) >> 51; + q = (limbs[3] + q) >> 51; + q = (limbs[4] + q) >> 51; + + // Now we can compute r as r = h - pq = r - (2^255-19)q = r + 19q - 2^255q + + limbs[0] += 19*q; + + // Now carry the result to compute r + 19q ... + let low_51_bit_mask = (1u64 << 51) - 1; + limbs[1] += limbs[0] >> 51; + limbs[0] = limbs[0] & low_51_bit_mask; + limbs[2] += limbs[1] >> 51; + limbs[1] = limbs[1] & low_51_bit_mask; + limbs[3] += limbs[2] >> 51; + limbs[2] = limbs[2] & low_51_bit_mask; + limbs[4] += limbs[3] >> 51; + limbs[3] = limbs[3] & low_51_bit_mask; + // ... but instead of carrying (limbs[4] >> 51) = 2^255q + // into another limb, discard it, subtracting the value + limbs[4] = limbs[4] & low_51_bit_mask; + + // Now arrange the bits of the limbs. + let mut s = [0u8;32]; + s[ 0] = limbs[0] as u8; + s[ 1] = (limbs[0] >> 8) as u8; + s[ 2] = (limbs[0] >> 16) as u8; + s[ 3] = (limbs[0] >> 24) as u8; + s[ 4] = (limbs[0] >> 32) as u8; + s[ 5] = (limbs[0] >> 40) as u8; + s[ 6] = ((limbs[0] >> 48) | (limbs[1] << 3)) as u8; + s[ 7] = (limbs[1] >> 5) as u8; + s[ 8] = (limbs[1] >> 13) as u8; + s[ 9] = (limbs[1] >> 21) as u8; + s[10] = (limbs[1] >> 29) as u8; + s[11] = (limbs[1] >> 37) as u8; + s[12] = ((limbs[1] >> 45) | (limbs[2] << 6)) as u8; + s[13] = (limbs[2] >> 2) as u8; + s[14] = (limbs[2] >> 10) as u8; + s[15] = (limbs[2] >> 18) as u8; + s[16] = (limbs[2] >> 26) as u8; + s[17] = (limbs[2] >> 34) as u8; + s[18] = (limbs[2] >> 42) as u8; + s[19] = ((limbs[2] >> 50) | (limbs[3] << 1)) as u8; + s[20] = (limbs[3] >> 7) as u8; + s[21] = (limbs[3] >> 15) as u8; + s[22] = (limbs[3] >> 23) as u8; + s[23] = (limbs[3] >> 31) as u8; + s[24] = (limbs[3] >> 39) as u8; + s[25] = ((limbs[3] >> 47) | (limbs[4] << 4)) as u8; + s[26] = (limbs[4] >> 4) as u8; + s[27] = (limbs[4] >> 12) as u8; + s[28] = (limbs[4] >> 20) as u8; + s[29] = (limbs[4] >> 28) as u8; + s[30] = (limbs[4] >> 36) as u8; + s[31] = (limbs[4] >> 44) as u8; + + // High bit should be zero. + debug_assert!((s[31] & 0b1000_0000u8) == 0u8); + + s + } + + /// Given `k > 0`, return `self^(2^k)`. + pub fn pow2k(&self, mut k: u32) -> FieldElement51 { + + debug_assert!( k > 0 ); + + /// Multiply two 64-bit integers with 128 bits of output. + #[inline(always)] + fn m(x: u64, y: u64) -> u128 { (x as u128) * (y as u128) } + + let mut a: [u64; 5] = self.0; + + loop { + // Precondition: assume input limbs a[i] are bounded as + // + // a[i] < 2^(51 + b) + // + // where b is a real parameter measuring the "bit excess" of the limbs. + + // Precomputation: 64-bit multiply by 19. + // + // This fits into a u64 whenever 51 + b + lg(19) < 64. + // + // Since 51 + b + lg(19) < 51 + 4.25 + b + // = 55.25 + b, + // this fits if b < 8.75. + let a3_19 = 19 * a[3]; + let a4_19 = 19 * a[4]; + + // Multiply to get 128-bit coefficients of output. + // + // The 128-bit multiplications by 2 turn into 1 slr + 1 slrd each, + // which doesn't seem any better or worse than doing them as precomputations + // on the 64-bit inputs. + let c0: u128 = m(a[0], a[0]) + 2*( m(a[1], a4_19) + m(a[2], a3_19) ); + let mut c1: u128 = m(a[3], a3_19) + 2*( m(a[0], a[1]) + m(a[2], a4_19) ); + let mut c2: u128 = m(a[1], a[1]) + 2*( m(a[0], a[2]) + m(a[4], a3_19) ); + let mut c3: u128 = m(a[4], a4_19) + 2*( m(a[0], a[3]) + m(a[1], a[2]) ); + let mut c4: u128 = m(a[2], a[2]) + 2*( m(a[0], a[4]) + m(a[1], a[3]) ); + + // Same bound as in multiply: + // c[i] < 2^(102 + 2*b) * (1+i + (4-i)*19) + // < 2^(102 + lg(1 + 4*19) + 2*b) + // < 2^(108.27 + 2*b) + // + // The carry (c[i] >> 51) fits into a u64 when + // 108.27 + 2*b - 51 < 64 + // 2*b < 6.73 + // b < 3.365. + // + // So we require b < 3 to ensure this fits. + debug_assert!(a[0] < (1 << 54)); + debug_assert!(a[1] < (1 << 54)); + debug_assert!(a[2] < (1 << 54)); + debug_assert!(a[3] < (1 << 54)); + debug_assert!(a[4] < (1 << 54)); + + const LOW_51_BIT_MASK: u64 = (1u64 << 51) - 1; + + // Casting to u64 and back tells the compiler that the carry is bounded by 2^64, so + // that the addition is a u128 + u64 rather than u128 + u128. + c1 += ((c0 >> 51) as u64) as u128; + a[0] = (c0 as u64) & LOW_51_BIT_MASK; + + c2 += ((c1 >> 51) as u64) as u128; + a[1] = (c1 as u64) & LOW_51_BIT_MASK; + + c3 += ((c2 >> 51) as u64) as u128; + a[2] = (c2 as u64) & LOW_51_BIT_MASK; + + c4 += ((c3 >> 51) as u64) as u128; + a[3] = (c3 as u64) & LOW_51_BIT_MASK; + + let carry: u64 = (c4 >> 51) as u64; + a[4] = (c4 as u64) & LOW_51_BIT_MASK; + + // To see that this does not overflow, we need a[0] + carry * 19 < 2^64. + // + // c4 < a2^2 + 2*a0*a4 + 2*a1*a3 + (carry from c3) + // < 2^(102 + 2*b + lg(5)) + 2^64. + // + // When b < 3 we get + // + // c4 < 2^110.33 so that carry < 2^59.33 + // + // so that + // + // a[0] + carry * 19 < 2^51 + 19 * 2^59.33 < 2^63.58 + // + // and there is no overflow. + a[0] = a[0] + carry * 19; + + // Now a[1] < 2^51 + 2^(64 -51) = 2^51 + 2^13 < 2^(51 + epsilon). + a[1] += a[0] >> 51; + a[0] &= LOW_51_BIT_MASK; + + // Now all a[i] < 2^(51 + epsilon) and a = self^(2^k). + + k = k - 1; + if k == 0 { + break; + } + } + + FieldElement51(a) + } + + /// Returns the square of this field element. + pub fn square(&self) -> FieldElement51 { + self.pow2k(1) + } + + /// Returns 2 times the square of this field element. + pub fn square2(&self) -> FieldElement51 { + let mut square = self.pow2k(1); + for i in 0..5 { + square.0[i] *= 2; + } + + square + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/mod.rs new file mode 100644 index 0000000..d329a89 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/mod.rs @@ -0,0 +1,26 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! The `u64` backend uses `u64`s and a `(u64, u64) -> u128` multiplier. +//! +//! On x86_64, the idiom `(x as u128) * (y as u128)` lowers to `MUL` +//! instructions taking 64-bit inputs and producing 128-bit outputs. On +//! other platforms, this implementation is not recommended. +//! +//! On Haswell and newer, the BMI2 extension provides `MULX`, and on +//! Broadwell and newer, the ADX extension provides `ADCX` and `ADOX` +//! (allowing the CPU to compute two carry chains in parallel). These +//! will be used if available. + +pub mod field; + +pub mod scalar; + +pub mod constants; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/scalar.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/scalar.rs new file mode 100644 index 0000000..97069ad --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/serial/u64/scalar.rs @@ -0,0 +1,451 @@ +//! Arithmetic mod \\(2\^{252} + 27742317777372353535851937790883648493\\) +//! with five \\(52\\)-bit unsigned limbs. +//! +//! \\(51\\)-bit limbs would cover the desired bit range (\\(253\\) +//! bits), but isn't large enough to reduce a \\(512\\)-bit number with +//! Montgomery multiplication, so \\(52\\) bits is used instead. To see +//! that this is safe for intermediate results, note that the largest +//! limb in a \\(5\times 5\\) product of \\(52\\)-bit limbs will be +//! +//! ```text +//! (0xfffffffffffff^2) * 5 = 0x4ffffffffffff60000000000005 (107 bits). +//! ``` + +use core::fmt::Debug; +use core::ops::{Index, IndexMut}; + +use zeroize::Zeroize; + +use constants; + +/// The `Scalar52` struct represents an element in +/// \\(\mathbb Z / \ell \mathbb Z\\) as 5 \\(52\\)-bit limbs. +#[derive(Copy,Clone)] +pub struct Scalar52(pub [u64; 5]); + +impl Debug for Scalar52 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "Scalar52: {:?}", &self.0[..]) + } +} + +impl Zeroize for Scalar52 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl Index for Scalar52 { + type Output = u64; + fn index(&self, _index: usize) -> &u64 { + &(self.0[_index]) + } +} + +impl IndexMut for Scalar52 { + fn index_mut(&mut self, _index: usize) -> &mut u64 { + &mut (self.0[_index]) + } +} + +/// u64 * u64 = u128 multiply helper +#[inline(always)] +fn m(x: u64, y: u64) -> u128 { + (x as u128) * (y as u128) +} + +impl Scalar52 { + /// Return the zero scalar + pub fn zero() -> Scalar52 { + Scalar52([0,0,0,0,0]) + } + + /// Unpack a 32 byte / 256 bit scalar into 5 52-bit limbs. + pub fn from_bytes(bytes: &[u8; 32]) -> Scalar52 { + let mut words = [0u64; 4]; + for i in 0..4 { + for j in 0..8 { + words[i] |= (bytes[(i * 8) + j] as u64) << (j * 8); + } + } + + let mask = (1u64 << 52) - 1; + let top_mask = (1u64 << 48) - 1; + let mut s = Scalar52::zero(); + + s[ 0] = words[0] & mask; + s[ 1] = ((words[0] >> 52) | (words[1] << 12)) & mask; + s[ 2] = ((words[1] >> 40) | (words[2] << 24)) & mask; + s[ 3] = ((words[2] >> 28) | (words[3] << 36)) & mask; + s[ 4] = (words[3] >> 16) & top_mask; + + s + } + + /// Reduce a 64 byte / 512 bit scalar mod l + pub fn from_bytes_wide(bytes: &[u8; 64]) -> Scalar52 { + let mut words = [0u64; 8]; + for i in 0..8 { + for j in 0..8 { + words[i] |= (bytes[(i * 8) + j] as u64) << (j * 8); + } + } + + let mask = (1u64 << 52) - 1; + let mut lo = Scalar52::zero(); + let mut hi = Scalar52::zero(); + + lo[0] = words[ 0] & mask; + lo[1] = ((words[ 0] >> 52) | (words[ 1] << 12)) & mask; + lo[2] = ((words[ 1] >> 40) | (words[ 2] << 24)) & mask; + lo[3] = ((words[ 2] >> 28) | (words[ 3] << 36)) & mask; + lo[4] = ((words[ 3] >> 16) | (words[ 4] << 48)) & mask; + hi[0] = (words[ 4] >> 4) & mask; + hi[1] = ((words[ 4] >> 56) | (words[ 5] << 8)) & mask; + hi[2] = ((words[ 5] >> 44) | (words[ 6] << 20)) & mask; + hi[3] = ((words[ 6] >> 32) | (words[ 7] << 32)) & mask; + hi[4] = words[ 7] >> 20 ; + + lo = Scalar52::montgomery_mul(&lo, &constants::R); // (lo * R) / R = lo + hi = Scalar52::montgomery_mul(&hi, &constants::RR); // (hi * R^2) / R = hi * R + + Scalar52::add(&hi, &lo) + } + + /// Pack the limbs of this `Scalar52` into 32 bytes + pub fn to_bytes(&self) -> [u8; 32] { + let mut s = [0u8; 32]; + + s[0] = (self.0[ 0] >> 0) as u8; + s[1] = (self.0[ 0] >> 8) as u8; + s[2] = (self.0[ 0] >> 16) as u8; + s[3] = (self.0[ 0] >> 24) as u8; + s[4] = (self.0[ 0] >> 32) as u8; + s[5] = (self.0[ 0] >> 40) as u8; + s[6] = ((self.0[ 0] >> 48) | (self.0[ 1] << 4)) as u8; + s[7] = (self.0[ 1] >> 4) as u8; + s[8] = (self.0[ 1] >> 12) as u8; + s[9] = (self.0[ 1] >> 20) as u8; + s[10] = (self.0[ 1] >> 28) as u8; + s[11] = (self.0[ 1] >> 36) as u8; + s[12] = (self.0[ 1] >> 44) as u8; + s[13] = (self.0[ 2] >> 0) as u8; + s[14] = (self.0[ 2] >> 8) as u8; + s[15] = (self.0[ 2] >> 16) as u8; + s[16] = (self.0[ 2] >> 24) as u8; + s[17] = (self.0[ 2] >> 32) as u8; + s[18] = (self.0[ 2] >> 40) as u8; + s[19] = ((self.0[ 2] >> 48) | (self.0[ 3] << 4)) as u8; + s[20] = (self.0[ 3] >> 4) as u8; + s[21] = (self.0[ 3] >> 12) as u8; + s[22] = (self.0[ 3] >> 20) as u8; + s[23] = (self.0[ 3] >> 28) as u8; + s[24] = (self.0[ 3] >> 36) as u8; + s[25] = (self.0[ 3] >> 44) as u8; + s[26] = (self.0[ 4] >> 0) as u8; + s[27] = (self.0[ 4] >> 8) as u8; + s[28] = (self.0[ 4] >> 16) as u8; + s[29] = (self.0[ 4] >> 24) as u8; + s[30] = (self.0[ 4] >> 32) as u8; + s[31] = (self.0[ 4] >> 40) as u8; + + s + } + + /// Compute `a + b` (mod l) + pub fn add(a: &Scalar52, b: &Scalar52) -> Scalar52 { + let mut sum = Scalar52::zero(); + let mask = (1u64 << 52) - 1; + + // a + b + let mut carry: u64 = 0; + for i in 0..5 { + carry = a[i] + b[i] + (carry >> 52); + sum[i] = carry & mask; + } + + // subtract l if the sum is >= l + Scalar52::sub(&sum, &constants::L) + } + + /// Compute `a - b` (mod l) + pub fn sub(a: &Scalar52, b: &Scalar52) -> Scalar52 { + let mut difference = Scalar52::zero(); + let mask = (1u64 << 52) - 1; + + // a - b + let mut borrow: u64 = 0; + for i in 0..5 { + borrow = a[i].wrapping_sub(b[i] + (borrow >> 63)); + difference[i] = borrow & mask; + } + + // conditionally add l if the difference is negative + let underflow_mask = ((borrow >> 63) ^ 1).wrapping_sub(1); + let mut carry: u64 = 0; + for i in 0..5 { + carry = (carry >> 52) + difference[i] + (constants::L[i] & underflow_mask); + difference[i] = carry & mask; + } + + difference + } + + /// Compute `a * b` + #[inline(always)] + pub (crate) fn mul_internal(a: &Scalar52, b: &Scalar52) -> [u128; 9] { + let mut z = [0u128; 9]; + + z[0] = m(a[0],b[0]); + z[1] = m(a[0],b[1]) + m(a[1],b[0]); + z[2] = m(a[0],b[2]) + m(a[1],b[1]) + m(a[2],b[0]); + z[3] = m(a[0],b[3]) + m(a[1],b[2]) + m(a[2],b[1]) + m(a[3],b[0]); + z[4] = m(a[0],b[4]) + m(a[1],b[3]) + m(a[2],b[2]) + m(a[3],b[1]) + m(a[4],b[0]); + z[5] = m(a[1],b[4]) + m(a[2],b[3]) + m(a[3],b[2]) + m(a[4],b[1]); + z[6] = m(a[2],b[4]) + m(a[3],b[3]) + m(a[4],b[2]); + z[7] = m(a[3],b[4]) + m(a[4],b[3]); + z[8] = m(a[4],b[4]); + + z + } + + /// Compute `a^2` + #[inline(always)] + fn square_internal(a: &Scalar52) -> [u128; 9] { + let aa = [ + a[0]*2, + a[1]*2, + a[2]*2, + a[3]*2, + ]; + + [ + m( a[0],a[0]), + m(aa[0],a[1]), + m(aa[0],a[2]) + m( a[1],a[1]), + m(aa[0],a[3]) + m(aa[1],a[2]), + m(aa[0],a[4]) + m(aa[1],a[3]) + m( a[2],a[2]), + m(aa[1],a[4]) + m(aa[2],a[3]), + m(aa[2],a[4]) + m( a[3],a[3]), + m(aa[3],a[4]), + m(a[4],a[4]) + ] + } + + /// Compute `limbs/R` (mod l), where R is the Montgomery modulus 2^260 + #[inline(always)] + pub (crate) fn montgomery_reduce(limbs: &[u128; 9]) -> Scalar52 { + + #[inline(always)] + fn part1(sum: u128) -> (u128, u64) { + let p = (sum as u64).wrapping_mul(constants::LFACTOR) & ((1u64 << 52) - 1); + ((sum + m(p,constants::L[0])) >> 52, p) + } + + #[inline(always)] + fn part2(sum: u128) -> (u128, u64) { + let w = (sum as u64) & ((1u64 << 52) - 1); + (sum >> 52, w) + } + + // note: l[3] is zero, so its multiples can be skipped + let l = &constants::L; + + // the first half computes the Montgomery adjustment factor n, and begins adding n*l to make limbs divisible by R + let (carry, n0) = part1( limbs[0]); + let (carry, n1) = part1(carry + limbs[1] + m(n0,l[1])); + let (carry, n2) = part1(carry + limbs[2] + m(n0,l[2]) + m(n1,l[1])); + let (carry, n3) = part1(carry + limbs[3] + m(n1,l[2]) + m(n2,l[1])); + let (carry, n4) = part1(carry + limbs[4] + m(n0,l[4]) + m(n2,l[2]) + m(n3,l[1])); + + // limbs is divisible by R now, so we can divide by R by simply storing the upper half as the result + let (carry, r0) = part2(carry + limbs[5] + m(n1,l[4]) + m(n3,l[2]) + m(n4,l[1])); + let (carry, r1) = part2(carry + limbs[6] + m(n2,l[4]) + m(n4,l[2])); + let (carry, r2) = part2(carry + limbs[7] + m(n3,l[4]) ); + let (carry, r3) = part2(carry + limbs[8] + m(n4,l[4])); + let r4 = carry as u64; + + // result may be >= l, so attempt to subtract l + Scalar52::sub(&Scalar52([r0,r1,r2,r3,r4]), l) + } + + /// Compute `a * b` (mod l) + #[inline(never)] + pub fn mul(a: &Scalar52, b: &Scalar52) -> Scalar52 { + let ab = Scalar52::montgomery_reduce(&Scalar52::mul_internal(a, b)); + Scalar52::montgomery_reduce(&Scalar52::mul_internal(&ab, &constants::RR)) + } + + /// Compute `a^2` (mod l) + #[inline(never)] + #[allow(dead_code)] // XXX we don't expose square() via the Scalar API + pub fn square(&self) -> Scalar52 { + let aa = Scalar52::montgomery_reduce(&Scalar52::square_internal(self)); + Scalar52::montgomery_reduce(&Scalar52::mul_internal(&aa, &constants::RR)) + } + + /// Compute `(a * b) / R` (mod l), where R is the Montgomery modulus 2^260 + #[inline(never)] + pub fn montgomery_mul(a: &Scalar52, b: &Scalar52) -> Scalar52 { + Scalar52::montgomery_reduce(&Scalar52::mul_internal(a, b)) + } + + /// Compute `(a^2) / R` (mod l) in Montgomery form, where R is the Montgomery modulus 2^260 + #[inline(never)] + pub fn montgomery_square(&self) -> Scalar52 { + Scalar52::montgomery_reduce(&Scalar52::square_internal(self)) + } + + /// Puts a Scalar52 in to Montgomery form, i.e. computes `a*R (mod l)` + #[inline(never)] + pub fn to_montgomery(&self) -> Scalar52 { + Scalar52::montgomery_mul(self, &constants::RR) + } + + /// Takes a Scalar52 out of Montgomery form, i.e. computes `a/R (mod l)` + #[inline(never)] + pub fn from_montgomery(&self) -> Scalar52 { + let mut limbs = [0u128; 9]; + for i in 0..5 { + limbs[i] = self[i] as u128; + } + Scalar52::montgomery_reduce(&limbs) + } +} + + +#[cfg(test)] +mod test { + use super::*; + + /// Note: x is 2^253-1 which is slightly larger than the largest scalar produced by + /// this implementation (l-1), and should show there are no overflows for valid scalars + /// + /// x = 14474011154664524427946373126085988481658748083205070504932198000989141204991 + /// x = 7237005577332262213973186563042994240801631723825162898930247062703686954002 mod l + /// x = 3057150787695215392275360544382990118917283750546154083604586903220563173085*R mod l in Montgomery form + pub static X: Scalar52 = Scalar52( + [0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, + 0x00001fffffffffff]); + + /// x^2 = 3078544782642840487852506753550082162405942681916160040940637093560259278169 mod l + pub static XX: Scalar52 = Scalar52( + [0x0001668020217559, 0x000531640ffd0ec0, 0x00085fd6f9f38a31, 0x000c268f73bb1cf4, + 0x000006ce65046df0]); + + /// x^2 = 4413052134910308800482070043710297189082115023966588301924965890668401540959*R mod l in Montgomery form + pub static XX_MONT: Scalar52 = Scalar52( + [0x000c754eea569a5c, 0x00063b6ed36cb215, 0x0008ffa36bf25886, 0x000e9183614e7543, + 0x0000061db6c6f26f]); + + /// y = 6145104759870991071742105800796537629880401874866217824609283457819451087098 + pub static Y: Scalar52 = Scalar52( + [0x000b75071e1458fa, 0x000bf9d75e1ecdac, 0x000433d2baf0672b, 0x0005fffcc11fad13, + 0x00000d96018bb825]); + + /// x*y = 36752150652102274958925982391442301741 mod l + pub static XY: Scalar52 = Scalar52( + [0x000ee6d76ba7632d, 0x000ed50d71d84e02, 0x00000000001ba634, 0x0000000000000000, + 0x0000000000000000]); + + /// x*y = 658448296334113745583381664921721413881518248721417041768778176391714104386*R mod l in Montgomery form + pub static XY_MONT: Scalar52 = Scalar52( + [0x0006d52bf200cfd5, 0x00033fb1d7021570, 0x000f201bc07139d8, 0x0001267e3e49169e, + 0x000007b839c00268]); + + /// a = 2351415481556538453565687241199399922945659411799870114962672658845158063753 + pub static A: Scalar52 = Scalar52( + [0x0005236c07b3be89, 0x0001bc3d2a67c0c4, 0x000a4aa782aae3ee, 0x0006b3f6e4fec4c4, + 0x00000532da9fab8c]); + + /// b = 4885590095775723760407499321843594317911456947580037491039278279440296187236 + pub static B: Scalar52 = Scalar52( + [0x000d3fae55421564, 0x000c2df24f65a4bc, 0x0005b5587d69fb0b, 0x00094c091b013b3b, + 0x00000acd25605473]); + + /// a+b = 0 + /// a-b = 4702830963113076907131374482398799845891318823599740229925345317690316127506 + pub static AB: Scalar52 = Scalar52( + [0x000a46d80f677d12, 0x0003787a54cf8188, 0x0004954f0555c7dc, 0x000d67edc9fd8989, + 0x00000a65b53f5718]); + + // c = (2^512 - 1) % l = 1627715501170711445284395025044413883736156588369414752970002579683115011840 + pub static C: Scalar52 = Scalar52( + [0x000611e3449c0f00, 0x000a768859347a40, 0x0007f5be65d00e1b, 0x0009a3dceec73d21, + 0x00000399411b7c30]); + + #[test] + fn mul_max() { + let res = Scalar52::mul(&X, &X); + for i in 0..5 { + assert!(res[i] == XX[i]); + } + } + + #[test] + fn square_max() { + let res = X.square(); + for i in 0..5 { + assert!(res[i] == XX[i]); + } + } + + #[test] + fn montgomery_mul_max() { + let res = Scalar52::montgomery_mul(&X, &X); + for i in 0..5 { + assert!(res[i] == XX_MONT[i]); + } + } + + #[test] + fn montgomery_square_max() { + let res = X.montgomery_square(); + for i in 0..5 { + assert!(res[i] == XX_MONT[i]); + } + } + + #[test] + fn mul() { + let res = Scalar52::mul(&X, &Y); + for i in 0..5 { + assert!(res[i] == XY[i]); + } + } + + #[test] + fn montgomery_mul() { + let res = Scalar52::montgomery_mul(&X, &Y); + for i in 0..5 { + assert!(res[i] == XY_MONT[i]); + } + } + + #[test] + fn add() { + let res = Scalar52::add(&A, &B); + let zero = Scalar52::zero(); + for i in 0..5 { + assert!(res[i] == zero[i]); + } + } + + #[test] + fn sub() { + let res = Scalar52::sub(&A, &B); + for i in 0..5 { + assert!(res[i] == AB[i]); + } + } + + #[test] + fn from_bytes_wide() { + let bignum = [255u8; 64]; // 2^512 - 1 + let reduced = Scalar52::from_bytes_wide(&bignum); + println!("{:?}", reduced); + for i in 0..5 { + assert!(reduced[i] == C[i]); + } + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/constants.rs new file mode 100644 index 0000000..73e5ba3 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/constants.rs @@ -0,0 +1,3427 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! This module contains constants used by the AVX2 backend. + +use packed_simd::u32x8; + +use backend::vector::avx2::edwards::{CachedPoint, ExtendedPoint}; +use backend::vector::avx2::field::FieldElement2625x4; +use window::NafLookupTable8; + +/// The identity element as an `ExtendedPoint`. +pub(crate) static EXTENDEDPOINT_IDENTITY: ExtendedPoint = ExtendedPoint(FieldElement2625x4([ + u32x8::new(0, 1, 0, 0, 1, 0, 0, 0), + u32x8::splat(0), + u32x8::splat(0), + u32x8::splat(0), + u32x8::splat(0), +])); + +/// The identity element as a `CachedPoint`. +pub(crate) static CACHEDPOINT_IDENTITY: CachedPoint = CachedPoint(FieldElement2625x4([ + u32x8::new(121647, 121666, 0, 0, 243332, 67108845, 0, 33554431), + u32x8::new(67108864, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), +])); + +/// The low limbs of (2p, 2p, 2p, 2p), so that +/// ```ascii,no_run +/// (2p, 2p, 2p, 2p) = [P_TIMES_2_LO, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI] +/// ``` +pub(crate) static P_TIMES_2_LO: u32x8 = u32x8::new( + 67108845 << 1, + 67108845 << 1, + 33554431 << 1, + 33554431 << 1, + 67108845 << 1, + 67108845 << 1, + 33554431 << 1, + 33554431 << 1, +); + +/// The high limbs of (2p, 2p, 2p, 2p), so that +/// ```ascii,no_run +/// (2p, 2p, 2p, 2p) = [P_TIMES_2_LO, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI] +/// ``` +pub(crate) static P_TIMES_2_HI: u32x8 = u32x8::new( + 67108863 << 1, + 67108863 << 1, + 33554431 << 1, + 33554431 << 1, + 67108863 << 1, + 67108863 << 1, + 33554431 << 1, + 33554431 << 1, +); + +/// The low limbs of (16p, 16p, 16p, 16p), so that +/// ```ascii,no_run +/// (16p, 16p, 16p, 16p) = [P_TIMES_16_LO, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI] +/// ``` +pub(crate) static P_TIMES_16_LO: u32x8 = u32x8::new( + 67108845 << 4, + 67108845 << 4, + 33554431 << 4, + 33554431 << 4, + 67108845 << 4, + 67108845 << 4, + 33554431 << 4, + 33554431 << 4, +); + +/// The high limbs of (16p, 16p, 16p, 16p), so that +/// ```ascii,no_run +/// (16p, 16p, 16p, 16p) = [P_TIMES_16_LO, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI] +/// ``` +pub(crate) static P_TIMES_16_HI: u32x8 = u32x8::new( + 67108863 << 4, + 67108863 << 4, + 33554431 << 4, + 33554431 << 4, + 67108863 << 4, + 67108863 << 4, + 33554431 << 4, + 33554431 << 4, +); + +/// Odd multiples of the Ed25519 basepoint: +pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = NafLookupTable8([ + CachedPoint(FieldElement2625x4([ + u32x8::new( + 3571425, + 10045002, + 19036563, + 1096096, + 243332, + 65897020, + 0, + 28963681, + ), + u32x8::new( + 30896895, + 63055514, + 1614915, + 5095970, + 0, + 53791688, + 0, + 31258312, + ), + u32x8::new( + 13347627, + 40339464, + 2236269, + 11185503, + 0, + 22520087, + 0, + 8659512, + ), + u32x8::new( + 11125413, + 29139905, + 32037254, + 28360723, + 0, + 64556417, + 0, + 9635759, + ), + u32x8::new( + 33268144, + 47262491, + 4336918, + 15795740, + 0, + 22027545, + 0, + 4846528, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 47099681, + 31447946, + 29365447, + 24740513, + 42991046, + 18317844, + 16051644, + 21404226, + ), + u32x8::new( + 31708133, + 28909527, + 2366091, + 13703791, + 469246, + 54159622, + 2601402, + 32988002, + ), + u32x8::new( + 63432457, + 30251794, + 15163516, + 18491340, + 28144087, + 35605455, + 13682295, + 18474872, + ), + u32x8::new( + 12221607, + 4967598, + 26061980, + 26008006, + 20226147, + 9726961, + 17410, + 18051083, + ), + u32x8::new( + 60569645, + 62487085, + 11911242, + 21920922, + 4092105, + 38186967, + 22431483, + 31366585, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 18147205, + 62587998, + 2554617, + 536692, + 11924528, + 26674131, + 17645433, + 24341419, + ), + u32x8::new( + 11573357, + 27579485, + 31491870, + 29000885, + 10800976, + 51902791, + 28076395, + 20464029, + ), + u32x8::new( + 56031649, + 10856669, + 11791193, + 26769430, + 25306956, + 5922200, + 6630685, + 9385098, + ), + u32x8::new( + 31319348, + 23906711, + 16290213, + 32142166, + 61106354, + 17181823, + 3548308, + 12022566, + ), + u32x8::new( + 5904298, + 50218605, + 11826440, + 5492249, + 10379071, + 3472255, + 172742, + 31948344, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 10625852, + 15193821, + 22918394, + 23676410, + 53695416, + 54987793, + 10067515, + 11747680, + ), + u32x8::new( + 65013325, + 1309652, + 29616320, + 28922974, + 60360891, + 19621771, + 9938982, + 30406429, + ), + u32x8::new( + 54967954, + 65931918, + 5595602, + 25719523, + 64909864, + 30566415, + 15945272, + 8495317, + ), + u32x8::new( + 1167157, + 55265018, + 11507029, + 31641054, + 43497904, + 2367338, + 12937761, + 27517066, + ), + u32x8::new( + 656704, + 2544994, + 13006713, + 480979, + 38471594, + 62541240, + 25353597, + 11531760, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 22176662, + 3984313, + 27495285, + 4110608, + 2909584, + 30594106, + 15677919, + 2549183, + ), + u32x8::new( + 33979105, + 62269905, + 2071511, + 6894756, + 53189950, + 47232857, + 6408191, + 6123225, + ), + u32x8::new( + 32553873, + 63948030, + 12612401, + 3633166, + 24054373, + 37626618, + 14481327, + 8520484, + ), + u32x8::new( + 56552486, + 10749438, + 12034813, + 28811946, + 1445640, + 36755601, + 12104575, + 10257833, + ), + u32x8::new( + 22795808, + 48761311, + 1136056, + 9380768, + 1411523, + 5341811, + 27318329, + 9686767, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 21157200, + 39156966, + 20473176, + 4934657, + 61478183, + 45121537, + 5429856, + 13035023, + ), + u32x8::new( + 7954529, + 58789246, + 31440083, + 7054221, + 38438565, + 36856107, + 1364112, + 14548122, + ), + u32x8::new( + 26120083, + 36321360, + 4919997, + 31687496, + 33757765, + 36237559, + 15243054, + 32163861, + ), + u32x8::new( + 25878307, + 46544824, + 19455951, + 2414935, + 16844726, + 56521560, + 32680554, + 26660660, + ), + u32x8::new( + 48360220, + 43407178, + 12187042, + 24925816, + 7423722, + 25746484, + 12814654, + 17395963, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 63153652, + 32195955, + 4087908, + 8431689, + 30392384, + 47203165, + 8986649, + 9053039, + ), + u32x8::new( + 63659241, + 47988767, + 2931872, + 19953600, + 11747107, + 51610101, + 20952181, + 13364887, + ), + u32x8::new( + 3659197, + 58790649, + 5930099, + 2605312, + 28477896, + 580728, + 20579735, + 2610622, + ), + u32x8::new( + 41781607, + 17161358, + 10690531, + 24368015, + 47027031, + 36742339, + 5414694, + 13156365, + ), + u32x8::new( + 13237853, + 51182423, + 8954802, + 29006542, + 22643989, + 56896541, + 22830593, + 10289708, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 1401265, + 58846825, + 30911620, + 32239180, + 15391552, + 15200821, + 6339309, + 16403588, + ), + u32x8::new( + 55913797, + 29541724, + 1664461, + 21709410, + 38470488, + 47097092, + 17674945, + 32666066, + ), + u32x8::new( + 22844482, + 10797709, + 27548106, + 31638735, + 34500968, + 26611503, + 19727211, + 13160873, + ), + u32x8::new( + 31485204, + 14496164, + 13981208, + 10276888, + 5748808, + 35024436, + 2740987, + 7479021, + ), + u32x8::new( + 58541207, + 14866135, + 32344041, + 545930, + 62661488, + 6941250, + 27940205, + 11976112, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 39849808, + 44781685, + 15697329, + 24387845, + 12501486, + 50260092, + 23199481, + 31929024, + ), + u32x8::new( + 24823070, + 27956017, + 27034296, + 10316465, + 47664045, + 11152446, + 15719183, + 30181617, + ), + u32x8::new( + 20771189, + 19969144, + 31433937, + 19185213, + 27565920, + 10384445, + 2893359, + 9255362, + ), + u32x8::new( + 42894974, + 11925545, + 32134441, + 32738810, + 55916336, + 32479272, + 19563550, + 5511385, + ), + u32x8::new( + 17857161, + 47809169, + 14564114, + 27997751, + 33024640, + 38669671, + 31956536, + 27313245, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 58237774, + 15917425, + 18872208, + 19394230, + 17374297, + 6101419, + 4839741, + 6596900, + ), + u32x8::new( + 66947393, + 15744215, + 18368993, + 17750160, + 41006525, + 9205497, + 2629667, + 32170865, + ), + u32x8::new( + 66481381, + 1919414, + 28338762, + 7372967, + 33819153, + 4156199, + 27126309, + 12739816, + ), + u32x8::new( + 44117158, + 58545296, + 22521371, + 11809712, + 28998792, + 50731010, + 30215699, + 25748377, + ), + u32x8::new( + 23561284, + 4160244, + 9035405, + 24895184, + 39761639, + 59253416, + 8684759, + 22487864, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 12671134, + 56419053, + 16092401, + 30038207, + 4002647, + 47822606, + 7151311, + 28430768, + ), + u32x8::new( + 61041684, + 35765374, + 30598048, + 19666539, + 44150175, + 40140037, + 290469, + 28442674, + ), + u32x8::new( + 18847796, + 1371617, + 33316881, + 13199936, + 43646578, + 17068881, + 12074900, + 1537415, + ), + u32x8::new( + 10052225, + 38316070, + 27469797, + 5297537, + 50725570, + 20435349, + 10339121, + 2779737, + ), + u32x8::new( + 18372189, + 15466385, + 24762130, + 22217964, + 23503887, + 47844464, + 10415034, + 2606889, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 55082775, + 45300503, + 16032654, + 5964396, + 17743504, + 24634761, + 19493066, + 5184611, + ), + u32x8::new( + 50172633, + 35093294, + 10040575, + 23616256, + 4543900, + 61852191, + 4049821, + 7423669, + ), + u32x8::new( + 20295398, + 40009376, + 10487190, + 15670429, + 51972856, + 58649552, + 20436392, + 3432497, + ), + u32x8::new( + 35189420, + 54117751, + 12825868, + 6283038, + 27540739, + 30648758, + 22658912, + 9466689, + ), + u32x8::new( + 51737549, + 40725785, + 17409814, + 25201086, + 21156239, + 34176168, + 26814520, + 5956424, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 8211442, + 8014184, + 6260823, + 22108096, + 32182620, + 51844847, + 2466270, + 28582231, + ), + u32x8::new( + 27199739, + 3848333, + 31738017, + 10892045, + 4963982, + 65391770, + 32551997, + 28906469, + ), + u32x8::new( + 16606846, + 32207068, + 26404535, + 7614129, + 45416902, + 65584718, + 13821785, + 2646060, + ), + u32x8::new( + 36090634, + 57981287, + 32247670, + 22837502, + 31003861, + 55448117, + 6062915, + 20369975, + ), + u32x8::new( + 27381403, + 50578107, + 522631, + 29521058, + 31137497, + 40220737, + 27628049, + 1824195, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 59402443, + 17056879, + 29262689, + 6131785, + 52551472, + 43367471, + 29423199, + 18899208, + ), + u32x8::new( + 5749414, + 43514612, + 11365899, + 21514624, + 65591890, + 60945892, + 19841732, + 5628567, + ), + u32x8::new( + 19334369, + 52500268, + 12307673, + 5267367, + 3212103, + 9035822, + 29142161, + 30520954, + ), + u32x8::new( + 57261330, + 6819646, + 22089161, + 9800373, + 55155453, + 62250856, + 13766735, + 25244545, + ), + u32x8::new( + 54370226, + 61888301, + 24496089, + 2540581, + 65637506, + 60274355, + 18154273, + 11687259, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 12521903, + 26014045, + 13995625, + 33360175, + 23605474, + 7376434, + 27229267, + 17195036, + ), + u32x8::new( + 59482891, + 10074423, + 574357, + 3857753, + 61377787, + 50306685, + 5241065, + 20234396, + ), + u32x8::new( + 23674717, + 6997172, + 20771841, + 16858511, + 40565304, + 29973136, + 7049812, + 14585010, + ), + u32x8::new( + 1427477, + 13295732, + 31762066, + 31499740, + 60419925, + 54666164, + 22009424, + 8089609, + ), + u32x8::new( + 58154031, + 41593020, + 15342328, + 957047, + 38937260, + 37037498, + 24871992, + 32973409, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 30654745, + 51286025, + 21206982, + 2433562, + 12780105, + 31732574, + 33087964, + 33081189, + ), + u32x8::new( + 66640017, + 42720009, + 16567620, + 15300745, + 1530367, + 33001123, + 20930247, + 21042661, + ), + u32x8::new( + 15003356, + 5294119, + 22985605, + 18928772, + 32628461, + 18230172, + 14773298, + 27193722, + ), + u32x8::new( + 27555, + 65346287, + 17017174, + 7837720, + 21499787, + 42855613, + 22474984, + 13675085, + ), + u32x8::new( + 24164369, + 50130116, + 5973149, + 24152073, + 1577334, + 25400030, + 18648484, + 32228854, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 49518649, + 59119280, + 31670678, + 20396561, + 61728330, + 651402, + 176032, + 9529498, + ), + u32x8::new( + 61765532, + 9082232, + 32794568, + 15526956, + 48543100, + 32614212, + 19001206, + 25680229, + ), + u32x8::new( + 32086091, + 10373081, + 8996131, + 31822823, + 35788988, + 49973190, + 30542040, + 17858455, + ), + u32x8::new( + 48130197, + 58121889, + 27753291, + 29923268, + 54448075, + 43300790, + 9336565, + 15770022, + ), + u32x8::new( + 57725546, + 20557498, + 9366233, + 16023566, + 16189031, + 2837363, + 24315301, + 27003505, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 28286608, + 10767548, + 18220739, + 5413236, + 48253387, + 58255702, + 11864864, + 28527159, + ), + u32x8::new( + 45038176, + 58655197, + 25648758, + 10951484, + 42564382, + 34542843, + 23146954, + 22234334, + ), + u32x8::new( + 14858710, + 24978793, + 15040559, + 4379220, + 47621477, + 40271440, + 15650420, + 1998736, + ), + u32x8::new( + 24106391, + 9626149, + 344505, + 25253814, + 34579800, + 59687089, + 25718289, + 25904133, + ), + u32x8::new( + 1981195, + 37751302, + 26132048, + 1764722, + 13288231, + 28808622, + 12531301, + 18292949, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 13869851, + 31448904, + 14963539, + 7581293, + 20536485, + 35021083, + 21257574, + 33356609, + ), + u32x8::new( + 36903364, + 18429241, + 11097857, + 5943856, + 60583077, + 40015815, + 30509523, + 31915271, + ), + u32x8::new( + 49161801, + 40681915, + 67892, + 25454357, + 22779677, + 25798439, + 15964829, + 5863227, + ), + u32x8::new( + 60810637, + 4496471, + 5217137, + 14095116, + 50942411, + 50712663, + 2507380, + 26844507, + ), + u32x8::new( + 34579752, + 53519385, + 10859797, + 18816024, + 42552864, + 39478521, + 6783896, + 17277037, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 43287109, + 27900723, + 33182187, + 2766754, + 17041989, + 1018260, + 33392790, + 4830032, + ), + u32x8::new( + 60194178, + 30788903, + 24728888, + 14513195, + 20897010, + 28843233, + 20111980, + 17475240, + ), + u32x8::new( + 46042274, + 19257042, + 4628173, + 31649727, + 27388316, + 66631493, + 11541886, + 6408028, + ), + u32x8::new( + 57024680, + 49536568, + 32050358, + 31321917, + 17437691, + 49672356, + 2884755, + 20493991, + ), + u32x8::new( + 59553007, + 46782643, + 29001173, + 1814088, + 21930692, + 51319706, + 14965872, + 30748046, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 16441817, + 36111849, + 6900424, + 602234, + 46522199, + 16441484, + 8135070, + 21726541, + ), + u32x8::new( + 37711225, + 32701959, + 11679112, + 13125533, + 32154135, + 9407918, + 26554289, + 620848, + ), + u32x8::new( + 19233407, + 30086864, + 14679568, + 2797374, + 4892806, + 7993077, + 247658, + 5632804, + ), + u32x8::new( + 37427262, + 26675495, + 27125659, + 13496131, + 50718473, + 40115609, + 28505351, + 27837393, + ), + u32x8::new( + 196819, + 18410429, + 7070012, + 21691388, + 29763371, + 24754123, + 9727048, + 10930179, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 28319289, + 40734650, + 16225680, + 24739184, + 64272368, + 35356897, + 7866648, + 13635853, + ), + u32x8::new( + 34165295, + 48328447, + 27041670, + 23643655, + 48949950, + 52963288, + 30411133, + 6045174, + ), + u32x8::new( + 18583559, + 41649834, + 9813585, + 26098520, + 25682734, + 26733526, + 19276490, + 10654728, + ), + u32x8::new( + 34867476, + 52715968, + 5694571, + 13380978, + 15134994, + 1831255, + 8608001, + 17266401, + ), + u32x8::new( + 59925903, + 44282172, + 27802465, + 1855069, + 14234749, + 36635487, + 11302294, + 10938429, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 8373273, + 49064494, + 4932071, + 32997499, + 38472880, + 29335908, + 14504412, + 22460029, + ), + u32x8::new( + 31795930, + 50785923, + 25835990, + 25790073, + 65669841, + 11360450, + 9969157, + 9008164, + ), + u32x8::new( + 50262498, + 45869261, + 16124434, + 15336007, + 882762, + 42522623, + 11277198, + 26296377, + ), + u32x8::new( + 42332732, + 59129236, + 14452816, + 567985, + 208061, + 34722729, + 32008143, + 14828749, + ), + u32x8::new( + 17937794, + 36846032, + 32102665, + 4442466, + 19745435, + 31633451, + 7146411, + 15812027, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 30741269, + 38648744, + 12562645, + 30092623, + 25073992, + 28730659, + 27911745, + 30000958, + ), + u32x8::new( + 2859794, + 25991700, + 17776078, + 27091930, + 2328322, + 60061146, + 18581824, + 18039008, + ), + u32x8::new( + 58206333, + 17917354, + 1972306, + 11853766, + 2655376, + 60543390, + 18416710, + 13287440, + ), + u32x8::new( + 62746330, + 61423885, + 21246577, + 2266675, + 60099139, + 14804707, + 14772234, + 20679434, + ), + u32x8::new( + 26987698, + 15488817, + 715616, + 2339565, + 51980752, + 17333865, + 21965103, + 10839820, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 18672548, + 57660959, + 16042910, + 19519287, + 62865851, + 17580961, + 26628347, + 23774759, + ), + u32x8::new( + 368070, + 3464471, + 25888304, + 30370559, + 52396053, + 45426828, + 28745251, + 9246829, + ), + u32x8::new( + 29090099, + 57950037, + 23104657, + 4903923, + 10987778, + 56163684, + 23621539, + 10332760, + ), + u32x8::new( + 53338235, + 44851161, + 21606845, + 31069622, + 4243630, + 34464392, + 11286454, + 5802022, + ), + u32x8::new( + 46710757, + 63389067, + 11642865, + 1980986, + 12967337, + 28162061, + 3854192, + 30432268, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 12179834, + 41005450, + 12809619, + 33525228, + 4624405, + 46957889, + 16968743, + 11827816, + ), + u32x8::new( + 51521162, + 12466775, + 31791271, + 15303651, + 49798465, + 62714504, + 6509600, + 12918560, + ), + u32x8::new( + 20445559, + 1756449, + 28848701, + 7920171, + 9835040, + 5900071, + 28757409, + 12376688, + ), + u32x8::new( + 18259496, + 14281012, + 21767026, + 10232236, + 20000226, + 12400540, + 4104902, + 23570543, + ), + u32x8::new( + 3687440, + 26546648, + 13328821, + 26841081, + 49822734, + 22334054, + 244496, + 24862543, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 59523541, + 62195428, + 3853227, + 13954801, + 12387708, + 47627615, + 27221350, + 17899572, + ), + u32x8::new( + 63193587, + 36343307, + 14595132, + 6880795, + 1364792, + 37648434, + 3259017, + 20536046, + ), + u32x8::new( + 30362834, + 10440372, + 9574624, + 11729232, + 63861613, + 21748389, + 5530846, + 2721586, + ), + u32x8::new( + 18339760, + 1550632, + 17170271, + 25732971, + 28459263, + 63142237, + 21642345, + 31557672, + ), + u32x8::new( + 10611282, + 5204623, + 18049257, + 214175, + 19432723, + 49809070, + 26010406, + 27449522, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 19770733, + 26478685, + 9464541, + 29158041, + 28604307, + 45196604, + 7586524, + 6641859, + ), + u32x8::new( + 65654484, + 52230498, + 30886612, + 19112823, + 47271809, + 38942611, + 16020035, + 10773481, + ), + u32x8::new( + 27464323, + 54451016, + 20646645, + 17732915, + 23008717, + 53626684, + 3253189, + 15614410, + ), + u32x8::new( + 52381752, + 40693008, + 7063024, + 28469981, + 51159478, + 44543211, + 19941777, + 5985451, + ), + u32x8::new( + 13553668, + 35524849, + 14788737, + 1883845, + 12385775, + 47958835, + 29135466, + 1776722, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 36719806, + 20827965, + 23175373, + 32996806, + 42041892, + 65708790, + 5467143, + 20884008, + ), + u32x8::new( + 43256281, + 40770646, + 17244063, + 31959819, + 64366384, + 43544617, + 25057754, + 12628720, + ), + u32x8::new( + 17337782, + 58472057, + 27906934, + 15305274, + 30292418, + 39284317, + 16946773, + 24806712, + ), + u32x8::new( + 6485126, + 32447403, + 16261486, + 13561940, + 49439635, + 10738368, + 16419889, + 8897231, + ), + u32x8::new( + 44812203, + 40122262, + 25496058, + 2759794, + 25295304, + 52178368, + 24154195, + 29334408, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 42307254, + 57217102, + 1088936, + 3832827, + 33905401, + 23130334, + 6958056, + 12622851, + ), + u32x8::new( + 3881189, + 14870059, + 19712830, + 6071598, + 38147944, + 60776394, + 3427938, + 13765703, + ), + u32x8::new( + 7666911, + 24227591, + 17077136, + 22967588, + 6874639, + 30915523, + 11451695, + 24292224, + ), + u32x8::new( + 13659529, + 31984463, + 28764736, + 20506164, + 64729627, + 49321636, + 28284636, + 25472371, + ), + u32x8::new( + 39360308, + 42281399, + 9446504, + 868960, + 49227724, + 21351115, + 30561851, + 11292096, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 7071115, + 46444090, + 5387916, + 15432877, + 27226682, + 41506862, + 2398278, + 3978240, + ), + u32x8::new( + 51009614, + 54216973, + 24368938, + 31392616, + 38456150, + 62313644, + 6729154, + 99724, + ), + u32x8::new( + 17474332, + 62857913, + 2619930, + 30659308, + 18268181, + 32809239, + 22826292, + 24561895, + ), + u32x8::new( + 38187020, + 67003092, + 14118280, + 16500577, + 18808560, + 64983716, + 25712929, + 32518261, + ), + u32x8::new( + 25735813, + 62284262, + 10824872, + 20558596, + 48149681, + 31162667, + 22608274, + 26285185, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 963440, + 63742255, + 10230323, + 25515008, + 32506414, + 6105697, + 25980317, + 24645129, + ), + u32x8::new( + 7162189, + 8101249, + 14679265, + 33443386, + 2002396, + 8541405, + 19442276, + 4795881, + ), + u32x8::new( + 8116694, + 51463069, + 4415528, + 25599140, + 55805721, + 39582709, + 6719436, + 30033839, + ), + u32x8::new( + 14468202, + 42181869, + 25188826, + 9639755, + 47546189, + 62711146, + 32762447, + 18338064, + ), + u32x8::new( + 33880058, + 32810909, + 8969931, + 13095238, + 38360605, + 40138517, + 9246134, + 4928058, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 63655588, + 17883670, + 9410246, + 26162761, + 5000571, + 7349225, + 23785252, + 32751089, + ), + u32x8::new( + 28568737, + 10733123, + 9342397, + 21570673, + 54096560, + 32467591, + 20494687, + 21511513, + ), + u32x8::new( + 47675157, + 47932807, + 29250946, + 15672208, + 59760469, + 9945465, + 14939287, + 18437405, + ), + u32x8::new( + 37985267, + 8609815, + 31573002, + 3373596, + 47828883, + 20834216, + 13248616, + 24154292, + ), + u32x8::new( + 5543543, + 29553242, + 3386453, + 30501150, + 25058089, + 15236571, + 8814395, + 32462955, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 39158670, + 15322548, + 20495103, + 3312736, + 14557171, + 12985179, + 8044741, + 3176899, + ), + u32x8::new( + 24673290, + 29693310, + 21412266, + 18324699, + 2154518, + 40329021, + 17500543, + 3954277, + ), + u32x8::new( + 36758685, + 38738957, + 165513, + 14691866, + 3070475, + 10424235, + 17096536, + 16896898, + ), + u32x8::new( + 59790459, + 43094586, + 8720681, + 10423589, + 1122030, + 31545615, + 4463786, + 31811293, + ), + u32x8::new( + 49778992, + 60881044, + 20509974, + 5832494, + 64155961, + 31483358, + 4511231, + 20307815, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 2863373, + 40876242, + 26865913, + 24067353, + 15726407, + 40919070, + 12953902, + 9931535, + ), + u32x8::new( + 60934877, + 42512204, + 21649141, + 21945190, + 52211954, + 60984193, + 7046207, + 5363493, + ), + u32x8::new( + 4205971, + 64068464, + 18197273, + 7327176, + 51527794, + 21166920, + 20669933, + 11828242, + ), + u32x8::new( + 59782815, + 49617225, + 15379924, + 457923, + 9320508, + 21498914, + 3242540, + 31563182, + ), + u32x8::new( + 27714753, + 8664670, + 3366162, + 26338598, + 56775518, + 25796006, + 13129151, + 21388876, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 59276548, + 49972346, + 16795002, + 33455915, + 48430097, + 53857205, + 18627071, + 32474471, + ), + u32x8::new( + 42160315, + 50705892, + 13530540, + 28012698, + 19833221, + 55886870, + 20191784, + 9644313, + ), + u32x8::new( + 20372416, + 28414713, + 24084234, + 31804096, + 33815377, + 36131001, + 17251241, + 18291088, + ), + u32x8::new( + 56234667, + 14920441, + 2033267, + 29572003, + 1724043, + 45519699, + 17873735, + 501988, + ), + u32x8::new( + 50031659, + 31517850, + 15697583, + 1016845, + 43104661, + 54769582, + 8008601, + 27257051, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 52951491, + 66542164, + 14853573, + 30444631, + 12045973, + 24321813, + 16545674, + 18160646, + ), + u32x8::new( + 60107911, + 1126003, + 5947677, + 19486116, + 41119984, + 30860440, + 7935395, + 13354438, + ), + u32x8::new( + 17841328, + 11063269, + 1664538, + 26687568, + 6268968, + 22280371, + 17275484, + 4523163, + ), + u32x8::new( + 15886041, + 56799482, + 15446552, + 21712778, + 1005290, + 17827215, + 4978741, + 6854882, + ), + u32x8::new( + 34319277, + 47731002, + 20321804, + 28544575, + 29591814, + 63376351, + 24754545, + 26001714, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 66783087, + 5234346, + 46102, + 8566476, + 19947339, + 20180418, + 25398238, + 3726678, + ), + u32x8::new( + 63890180, + 46380965, + 20674069, + 5366544, + 59661487, + 48406612, + 31533614, + 7071217, + ), + u32x8::new( + 13104676, + 1406631, + 24326736, + 19854367, + 61039528, + 11019904, + 31967425, + 19219275, + ), + u32x8::new( + 39003597, + 30143957, + 15351834, + 8639435, + 57309582, + 61436794, + 15830475, + 10090318, + ), + u32x8::new( + 45923044, + 6700175, + 99413, + 21263025, + 23762647, + 53905481, + 6063914, + 10065424, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 42822326, + 57678669, + 4052879, + 25452667, + 54049411, + 2373092, + 22337016, + 7701046, + ), + u32x8::new( + 44382355, + 43307377, + 16761537, + 30373573, + 49790216, + 23230748, + 25655306, + 10519391, + ), + u32x8::new( + 919475, + 59371245, + 1273450, + 25558666, + 9724711, + 8556709, + 25755845, + 10887647, + ), + u32x8::new( + 25465699, + 44651158, + 17658392, + 11257418, + 29735193, + 22885150, + 7094716, + 26828565, + ), + u32x8::new( + 48237389, + 47661599, + 27054393, + 7328070, + 27280193, + 65616691, + 23062005, + 4170709, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 26535281, + 60238317, + 30343788, + 25790743, + 37993933, + 24614372, + 9523840, + 10401918, + ), + u32x8::new( + 2783987, + 29468958, + 4697011, + 19804475, + 37246678, + 46797720, + 10261254, + 18942252, + ), + u32x8::new( + 58135580, + 60247753, + 25301938, + 6844561, + 20949454, + 39844754, + 4552026, + 919057, + ), + u32x8::new( + 6694071, + 44126261, + 32285330, + 31370180, + 24603698, + 53328179, + 13971149, + 5325636, + ), + u32x8::new( + 64879487, + 582094, + 17982081, + 19190425, + 24951286, + 26923842, + 29077174, + 33286062, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 54863941, + 67016431, + 1224043, + 23371240, + 62940074, + 52101083, + 13523637, + 30366406, + ), + u32x8::new( + 36324581, + 25407485, + 18258623, + 4698602, + 50300544, + 2658516, + 26300935, + 2611030, + ), + u32x8::new( + 27183975, + 21791014, + 18105064, + 9875199, + 58118912, + 54198635, + 6400311, + 14767984, + ), + u32x8::new( + 33918318, + 42937962, + 14809334, + 22136592, + 10636588, + 29082337, + 29829692, + 28549776, + ), + u32x8::new( + 61080905, + 854212, + 12202487, + 20004503, + 9256495, + 6903981, + 20567109, + 347423, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 41391822, + 34336880, + 22362564, + 14247996, + 12115604, + 41583344, + 7639288, + 28910945, + ), + u32x8::new( + 62066617, + 59758859, + 26665947, + 11614812, + 65737664, + 45704543, + 30324810, + 12868376, + ), + u32x8::new( + 17491771, + 43589814, + 9454919, + 26047850, + 52629282, + 39304244, + 3868968, + 19296062, + ), + u32x8::new( + 17826638, + 30413590, + 32534225, + 32741469, + 15012391, + 14365713, + 33039233, + 14791399, + ), + u32x8::new( + 64115596, + 59197067, + 32739005, + 23275744, + 32954320, + 22241406, + 20788442, + 4942942, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 31956192, + 59570132, + 2784352, + 4237732, + 47222312, + 4860927, + 18658867, + 15279314, + ), + u32x8::new( + 63240583, + 28160478, + 23524941, + 13390861, + 66437406, + 57718120, + 33345312, + 28896298, + ), + u32x8::new( + 39026193, + 46239965, + 21440243, + 25070488, + 64012383, + 60999016, + 16517060, + 29565907, + ), + u32x8::new( + 18118181, + 60161496, + 4212092, + 23976240, + 36277753, + 62363144, + 5816868, + 16964362, + ), + u32x8::new( + 18196138, + 62490693, + 281468, + 7934713, + 56027312, + 62015725, + 4837237, + 32932252, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 29885826, + 51028067, + 30418143, + 33438769, + 62542283, + 39442528, + 31535876, + 143299, + ), + u32x8::new( + 17143063, + 56709783, + 14451852, + 15782104, + 32762665, + 14047066, + 26295037, + 5432487, + ), + u32x8::new( + 75151, + 533606, + 7539077, + 30926189, + 38410914, + 23771680, + 4872443, + 29199566, + ), + u32x8::new( + 61522396, + 48934708, + 16223126, + 207380, + 11171993, + 47975147, + 14164574, + 352966, + ), + u32x8::new( + 15449006, + 56530757, + 26796528, + 12045834, + 63738697, + 40667227, + 33001582, + 9101885, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 43331297, + 18431341, + 25801195, + 17267698, + 19365485, + 57295202, + 22218985, + 21284590, + ), + u32x8::new( + 2429849, + 19152559, + 10762172, + 22564684, + 21880390, + 66866426, + 20357935, + 22641906, + ), + u32x8::new( + 19771185, + 31652693, + 3666117, + 28136958, + 23624283, + 55101502, + 6313920, + 6783662, + ), + u32x8::new( + 3487137, + 7092443, + 11001876, + 26196524, + 47319246, + 44542068, + 17594073, + 15027760, + ), + u32x8::new( + 49563607, + 32191113, + 4991283, + 25400512, + 46539152, + 4155103, + 32368171, + 201203, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 20548943, + 14334571, + 4073874, + 6368588, + 53208883, + 56484515, + 15970071, + 25561889, + ), + u32x8::new( + 49915097, + 44030795, + 11202344, + 29284344, + 60258023, + 66225712, + 8075764, + 12383512, + ), + u32x8::new( + 45248912, + 4933668, + 9592153, + 5819559, + 31030983, + 38174071, + 32435814, + 7442522, + ), + u32x8::new( + 62688129, + 48218381, + 22089545, + 12897361, + 21050881, + 34278889, + 7569163, + 3225449, + ), + u32x8::new( + 19050183, + 51089071, + 32935757, + 22640195, + 66122318, + 47144608, + 18743677, + 25177079, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 41186817, + 46681702, + 31819867, + 32997133, + 38559207, + 27147015, + 30293819, + 16762988, + ), + u32x8::new( + 24154689, + 51762873, + 23883879, + 13510519, + 55338250, + 61224161, + 11663149, + 30803960, + ), + u32x8::new( + 18104238, + 14117824, + 11724021, + 21362053, + 65704761, + 35530242, + 13498058, + 33522849, + ), + u32x8::new( + 63812888, + 23995539, + 28920539, + 24005193, + 26412223, + 36582218, + 4251418, + 26160309, + ), + u32x8::new( + 16822053, + 66064082, + 3482145, + 31979593, + 45937188, + 54475379, + 612917, + 7976478, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 46509314, + 55327128, + 8944536, + 274914, + 26432930, + 53829300, + 21192572, + 3569894, + ), + u32x8::new( + 20919764, + 64356651, + 30642344, + 17215170, + 20335124, + 11203745, + 18663316, + 19024174, + ), + u32x8::new( + 59297055, + 53842463, + 3680204, + 9806710, + 54004169, + 51484914, + 29807998, + 20134199, + ), + u32x8::new( + 14781592, + 22628010, + 26877930, + 25880359, + 30434803, + 190607, + 30184292, + 8991040, + ), + u32x8::new( + 64400983, + 64591751, + 854562, + 28216111, + 20010398, + 50414793, + 9803872, + 22687008, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 15091184, + 32550863, + 8818643, + 4244752, + 43123513, + 64565526, + 408838, + 13206998, + ), + u32x8::new( + 16405061, + 60379639, + 31489017, + 20949281, + 27568751, + 38734986, + 8364264, + 12451020, + ), + u32x8::new( + 16005217, + 58008076, + 1406778, + 26546927, + 39571784, + 56365493, + 31274296, + 8918790, + ), + u32x8::new( + 23271122, + 19453469, + 27718201, + 32742670, + 234332, + 36785342, + 22601675, + 14331046, + ), + u32x8::new( + 40636025, + 22442705, + 22115403, + 23745859, + 41164945, + 61012, + 12499614, + 542137, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 62776018, + 32835413, + 17373246, + 17187309, + 54469193, + 21770290, + 15923753, + 28996575, + ), + u32x8::new( + 59385210, + 63082298, + 12568449, + 8509004, + 9483342, + 16105238, + 5756054, + 26890758, + ), + u32x8::new( + 53987996, + 38201748, + 5521661, + 19060159, + 18663191, + 9093637, + 27786835, + 31189196, + ), + u32x8::new( + 65872678, + 43635130, + 27903055, + 25020300, + 65772737, + 38110437, + 5213502, + 21909342, + ), + u32x8::new( + 4438979, + 9680838, + 10212446, + 4764184, + 13235684, + 58245995, + 20264570, + 21024049, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 60835961, + 48209103, + 31049052, + 4688268, + 12426713, + 59829045, + 22302488, + 29008521, + ), + u32x8::new( + 50401667, + 29716596, + 23531224, + 7581281, + 49071895, + 6952617, + 14934683, + 8218256, + ), + u32x8::new( + 1601446, + 36631413, + 31774811, + 29625330, + 56786114, + 8331539, + 23129509, + 19783344, + ), + u32x8::new( + 59514327, + 64513110, + 1772300, + 5701338, + 5737511, + 16147555, + 9461515, + 5703271, + ), + u32x8::new( + 33072974, + 54300426, + 11940114, + 1308663, + 15627555, + 4931627, + 28443714, + 20924342, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 18135013, + 20358426, + 4922557, + 10015355, + 65729669, + 34786528, + 26248549, + 29194359, + ), + u32x8::new( + 797666, + 34997544, + 24316856, + 25107230, + 24612576, + 4761401, + 15307321, + 32404252, + ), + u32x8::new( + 16501152, + 60565831, + 9487105, + 9316022, + 24986054, + 31917592, + 3962024, + 2501883, + ), + u32x8::new( + 63356796, + 50432342, + 18044926, + 30566881, + 42032028, + 31415202, + 13524600, + 16119907, + ), + u32x8::new( + 3927286, + 57022374, + 9265437, + 21620772, + 19481940, + 3806938, + 24836192, + 14572399, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 10785787, + 46564798, + 368445, + 33181384, + 5319843, + 52687136, + 30347110, + 29837357, + ), + u32x8::new( + 56436732, + 47859251, + 24141084, + 22250712, + 59046084, + 4963427, + 33463413, + 17168859, + ), + u32x8::new( + 15512044, + 6366740, + 4737504, + 27644548, + 30307977, + 25037929, + 14593903, + 12836490, + ), + u32x8::new( + 63878897, + 34013023, + 5860752, + 7244096, + 3689461, + 57012135, + 18389096, + 11589351, + ), + u32x8::new( + 4682110, + 36302830, + 653422, + 22316819, + 14081831, + 5657024, + 11088376, + 24110612, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 39907267, + 45940262, + 24887471, + 18342609, + 878445, + 40456159, + 12019082, + 345107, + ), + u32x8::new( + 12794982, + 28893944, + 9447505, + 11387200, + 16961963, + 13916996, + 10893728, + 25898006, + ), + u32x8::new( + 44934162, + 53465865, + 3583620, + 1102334, + 53917811, + 63478576, + 2426066, + 10389549, + ), + u32x8::new( + 45096036, + 37595344, + 19367718, + 20257175, + 10280866, + 41653449, + 27665642, + 375926, + ), + u32x8::new( + 45847901, + 24064074, + 32494820, + 32204556, + 10720704, + 51079060, + 1297436, + 29853825, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 66303987, + 36060363, + 16494578, + 24962147, + 11971403, + 49538586, + 25060560, + 1964341, + ), + u32x8::new( + 25988481, + 27641502, + 24909517, + 27237087, + 66646363, + 52777626, + 16360849, + 10459972, + ), + u32x8::new( + 43930529, + 34374176, + 31225968, + 8807030, + 10394758, + 35904854, + 25325589, + 19335583, + ), + u32x8::new( + 25094697, + 34380951, + 20051185, + 32287161, + 11739332, + 53887441, + 30517319, + 26601892, + ), + u32x8::new( + 8868546, + 35635502, + 32513071, + 28248087, + 51946989, + 14222744, + 19198839, + 23261841, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 51218008, + 5070126, + 11046681, + 5320810, + 61212079, + 34104447, + 23895089, + 6460727, + ), + u32x8::new( + 39843528, + 46278671, + 10426120, + 25624792, + 66658766, + 37140083, + 28933107, + 12969597, + ), + u32x8::new( + 59635793, + 40220191, + 5751421, + 173680, + 58321825, + 740337, + 1412847, + 7682623, + ), + u32x8::new( + 975962, + 56440763, + 20812276, + 22631115, + 49095824, + 19883130, + 2419746, + 31043648, + ), + u32x8::new( + 66208703, + 39669328, + 22525915, + 3748897, + 65994776, + 34533552, + 8126286, + 18326047, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 64176557, + 3912400, + 19351673, + 30068471, + 31190055, + 24221683, + 33142424, + 28698542, + ), + u32x8::new( + 34784792, + 4109933, + 3867193, + 19557314, + 2112512, + 32715890, + 24550117, + 16595976, + ), + u32x8::new( + 35542761, + 48024875, + 10925431, + 31526577, + 66577735, + 23189821, + 13375709, + 1735095, + ), + u32x8::new( + 59699254, + 43854093, + 29783239, + 24777271, + 19600372, + 39924461, + 2896720, + 1472185, + ), + u32x8::new( + 56389656, + 35980854, + 33172342, + 1370336, + 23707480, + 57654949, + 7850973, + 12655016, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 38372660, + 57101970, + 7044964, + 12732710, + 57535705, + 6043201, + 30858914, + 10946592, + ), + u32x8::new( + 21023468, + 6946992, + 26403324, + 23901823, + 35695559, + 23440687, + 4763891, + 6514074, + ), + u32x8::new( + 28662273, + 30933699, + 9352242, + 26354829, + 37402243, + 3145176, + 8770289, + 525937, + ), + u32x8::new( + 54933102, + 36695832, + 3281859, + 4755022, + 23043294, + 32794379, + 15618886, + 23602412, + ), + u32x8::new( + 9931565, + 29897140, + 2480737, + 24193701, + 7833615, + 2284939, + 893926, + 13421882, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 22917795, + 22088359, + 28978099, + 19794863, + 60542318, + 29878494, + 31053731, + 9080720, + ), + u32x8::new( + 23679072, + 52547035, + 28424916, + 20647332, + 4008761, + 28267029, + 12961289, + 1589095, + ), + u32x8::new( + 55616194, + 26678929, + 14998265, + 23274397, + 54625466, + 46244264, + 28627706, + 33030665, + ), + u32x8::new( + 11527330, + 6449415, + 26531607, + 3472938, + 41541592, + 62607682, + 19862690, + 20564723, + ), + u32x8::new( + 32843805, + 49066843, + 28425824, + 19521495, + 48792073, + 48242878, + 27392443, + 13175986, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 16185025, + 61537525, + 2961305, + 1492442, + 25123147, + 3095034, + 31896958, + 33089615, + ), + u32x8::new( + 64748157, + 18336595, + 16522231, + 25426312, + 65718949, + 35485695, + 30554083, + 10205918, + ), + u32x8::new( + 39626934, + 39271045, + 16420458, + 9826240, + 56483981, + 27128085, + 3783403, + 13360006, + ), + u32x8::new( + 30793778, + 66771960, + 17241420, + 6564573, + 61102581, + 29974476, + 32385512, + 9011754, + ), + u32x8::new( + 28068166, + 11862220, + 14323567, + 12380617, + 52090465, + 16029056, + 24495309, + 21409233, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 59411973, + 57437124, + 11695483, + 17586857, + 16108987, + 43449109, + 31098002, + 6248476, + ), + u32x8::new( + 42258047, + 61595931, + 29308533, + 11742653, + 43042345, + 27373650, + 30165249, + 21929989, + ), + u32x8::new( + 49907221, + 9620337, + 21888081, + 20981082, + 56288861, + 61562203, + 33223566, + 3582446, + ), + u32x8::new( + 57535017, + 41003416, + 22080416, + 14463796, + 65518565, + 18127889, + 24370863, + 33332664, + ), + u32x8::new( + 66655380, + 6430175, + 471782, + 11947673, + 30596400, + 18898659, + 15930721, + 4211851, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 6757410, + 65455566, + 13584784, + 11362173, + 10797127, + 24451471, + 19541370, + 29309435, + ), + u32x8::new( + 40360156, + 17685025, + 18326181, + 3846903, + 13693365, + 63049479, + 31900359, + 23385063, + ), + u32x8::new( + 52455038, + 57513503, + 22163311, + 27095042, + 48610726, + 66454160, + 12085341, + 26357004, + ), + u32x8::new( + 22097042, + 14063840, + 6705778, + 14342902, + 66139825, + 20702105, + 31279090, + 7495745, + ), + u32x8::new( + 27360710, + 49314837, + 18774847, + 7146436, + 37066216, + 42004961, + 22409916, + 10524446, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 1497507, + 33054449, + 11839906, + 2960428, + 40538463, + 18884538, + 25018820, + 4073970, + ), + u32x8::new( + 54484385, + 43640735, + 2808257, + 20710708, + 39840730, + 27222424, + 21783544, + 11848522, + ), + u32x8::new( + 45765237, + 48200555, + 9299019, + 9393151, + 34818188, + 56098995, + 13575233, + 21012731, + ), + u32x8::new( + 4265428, + 49627650, + 24960282, + 9425650, + 47883651, + 2797524, + 11853190, + 22877329, + ), + u32x8::new( + 25008173, + 64199503, + 380047, + 12107343, + 12329448, + 11914399, + 764281, + 29687002, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 35889734, + 23047226, + 4022841, + 7017445, + 7274086, + 53316179, + 25100176, + 15310676, + ), + u32x8::new( + 42409427, + 30270106, + 6823853, + 31551384, + 40645017, + 66489807, + 18021817, + 32669351, + ), + u32x8::new( + 39827134, + 43680850, + 28297996, + 20258133, + 26058742, + 52643238, + 22238331, + 21690533, + ), + u32x8::new( + 60808002, + 17499995, + 30042246, + 29310584, + 48219954, + 29389518, + 8680514, + 17844709, + ), + u32x8::new( + 6452896, + 50116553, + 9532047, + 26821214, + 44524351, + 50428429, + 21904953, + 12608048, + ), + ])), +]); diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/edwards.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/edwards.rs new file mode 100644 index 0000000..8465720 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/edwards.rs @@ -0,0 +1,524 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Parallel Edwards Arithmetic for Curve25519. +//! +//! This module currently has two point types: +//! +//! * `ExtendedPoint`: a point stored in vector-friendly format, with +//! vectorized doubling and addition; +//! +//! * `CachedPoint`: used for readdition. +//! +//! Details on the formulas can be found in the documentation for the +//! parent `avx2` module. +//! +//! This API is designed to be safe: vectorized points can only be +//! created from serial points (which do validation on decompression), +//! and operations on valid points return valid points, so invalid +//! point states should be unrepresentable. +//! +//! This design goal is met, with one exception: the `Neg` +//! implementation for the `CachedPoint` performs a lazy negation, so +//! that subtraction can be efficiently implemented as a negation and +//! an addition. Repeatedly negating a `CachedPoint` will cause its +//! coefficients to grow and eventually overflow. Repeatedly negating +//! a point should not be necessary anyways. + +#![allow(non_snake_case)] + +use core::convert::From; +use core::ops::{Add, Neg, Sub}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use edwards; +use window::{LookupTable, NafLookupTable5, NafLookupTable8}; + +use traits::Identity; + +use super::constants; +use super::field::{FieldElement2625x4, Lanes, Shuffle}; + +/// A point on Curve25519, using parallel Edwards formulas for curve +/// operations. +/// +/// # Invariant +/// +/// The coefficients of an `ExtendedPoint` are bounded with +/// \\( b < 0.007 \\). +#[derive(Copy, Clone, Debug)] +pub struct ExtendedPoint(pub(super) FieldElement2625x4); + +impl From for ExtendedPoint { + fn from(P: edwards::EdwardsPoint) -> ExtendedPoint { + ExtendedPoint(FieldElement2625x4::new(&P.X, &P.Y, &P.Z, &P.T)) + } +} + +impl From for edwards::EdwardsPoint { + fn from(P: ExtendedPoint) -> edwards::EdwardsPoint { + let tmp = P.0.split(); + edwards::EdwardsPoint { + X: tmp[0], + Y: tmp[1], + Z: tmp[2], + T: tmp[3], + } + } +} + +impl ConditionallySelectable for ExtendedPoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + ExtendedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice)) + } + + fn conditional_assign(&mut self, other: &Self, choice: Choice) { + self.0.conditional_assign(&other.0, choice); + } +} + +impl Default for ExtendedPoint { + fn default() -> ExtendedPoint { + ExtendedPoint::identity() + } +} + +impl Identity for ExtendedPoint { + fn identity() -> ExtendedPoint { + constants::EXTENDEDPOINT_IDENTITY + } +} + +impl ExtendedPoint { + /// Compute the double of this point. + pub fn double(&self) -> ExtendedPoint { + // Want to compute (X1 Y1 Z1 X1+Y1). + // Not sure how to do this less expensively than computing + // (X1 Y1 Z1 T1) --(256bit shuffle)--> (X1 Y1 X1 Y1) + // (X1 Y1 X1 Y1) --(2x128b shuffle)--> (Y1 X1 Y1 X1) + // and then adding. + + // Set tmp0 = (X1 Y1 X1 Y1) + let mut tmp0 = self.0.shuffle(Shuffle::ABAB); + + // Set tmp1 = (Y1 X1 Y1 X1) + let mut tmp1 = tmp0.shuffle(Shuffle::BADC); + + // Set tmp0 = (X1 Y1 Z1 X1+Y1) + tmp0 = self.0.blend(tmp0 + tmp1, Lanes::D); + + // Set tmp1 = tmp0^2, negating the D values + tmp1 = tmp0.square_and_negate_D(); + // Now tmp1 = (S1 S2 S3 -S4) with b < 0.007 + + // See discussion of bounds in the module-level documentation. + // We want to compute + // + // + | S1 | S1 | S1 | S1 | + // + | S2 | | | S2 | + // + | | | S3 | | + // + | | | S3 | | + // + | | | |-S4 | + // + | | 2p | 2p | | + // - | | S2 | S2 | | + // ======================= + // S5 S6 S8 S9 + + let zero = FieldElement2625x4::zero(); + let S_1 = tmp1.shuffle(Shuffle::AAAA); + let S_2 = tmp1.shuffle(Shuffle::BBBB); + + tmp0 = zero.blend(tmp1 + tmp1, Lanes::C); + // tmp0 = (0, 0, 2S_3, 0) + tmp0 = tmp0.blend(tmp1, Lanes::D); + // tmp0 = (0, 0, 2S_3, -S_4) + tmp0 = tmp0 + S_1; + // tmp0 = ( S_1, S_1, S_1 + 2S_3, S_1 - S_4) + tmp0 = tmp0 + zero.blend(S_2, Lanes::AD); + // tmp0 = (S_1 + S_2, S_1, S_1 + 2S_3, S_1 + S_2 - S_4) + tmp0 = tmp0 + zero.blend(S_2.negate_lazy(), Lanes::BC); + // tmp0 = (S_1 + S_2, S_1 - S_2, S_1 - S_2 + 2S_3, S_1 + S_2 - S_4) + // b < ( 1.01, 1.6, 2.33, 1.6) + // Now tmp0 = (S_5, S_6, S_8, S_9) + + // Set tmp1 = ( S_9, S_6, S_6, S_9) + // b < ( 1.6, 1.6, 1.6, 1.6) + tmp1 = tmp0.shuffle(Shuffle::DBBD); + // Set tmp1 = ( S_8, S_5, S_8, S_5) + // b < (2.33, 1.01, 2.33, 1.01) + tmp0 = tmp0.shuffle(Shuffle::CACA); + + // Bounds on (tmp0, tmp1) are (2.33, 1.6) < (2.5, 1.75). + ExtendedPoint(&tmp0 * &tmp1) + } + + pub fn mul_by_pow_2(&self, k: u32) -> ExtendedPoint { + let mut tmp: ExtendedPoint = *self; + for _ in 0..k { + tmp = tmp.double(); + } + tmp + } +} + +/// A cached point with some precomputed variables used for readdition. +/// +/// # Warning +/// +/// It is not safe to negate this point more than once. +/// +/// # Invariant +/// +/// As long as the `CachedPoint` is not repeatedly negated, its +/// coefficients will be bounded with \\( b < 1.0 \\). +#[derive(Copy, Clone, Debug)] +pub struct CachedPoint(pub(super) FieldElement2625x4); + +impl From for CachedPoint { + fn from(P: ExtendedPoint) -> CachedPoint { + let mut x = P.0; + + x = x.blend(x.diff_sum(), Lanes::AB); + // x = (X1 - Y1, X2 + Y2, Z2, T2) = (S2 S3 Z2 T2) + + x = x * (121666, 121666, 2 * 121666, 2 * 121665); + // x = (121666*S2 121666*S3 2*121666*Z2 2*121665*T2) + + x = x.blend(-x, Lanes::D); + // x = (121666*S2 121666*S3 2*121666*Z2 -2*121665*T2) + + // The coefficients of the output are bounded with b < 0.007. + CachedPoint(x) + } +} + +impl Default for CachedPoint { + fn default() -> CachedPoint { + CachedPoint::identity() + } +} + +impl Identity for CachedPoint { + fn identity() -> CachedPoint { + constants::CACHEDPOINT_IDENTITY + } +} + +impl ConditionallySelectable for CachedPoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + CachedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice)) + } + + fn conditional_assign(&mut self, other: &Self, choice: Choice) { + self.0.conditional_assign(&other.0, choice); + } +} + +impl<'a> Neg for &'a CachedPoint { + type Output = CachedPoint; + /// Lazily negate the point. + /// + /// # Warning + /// + /// Because this method does not perform a reduction, it is not + /// safe to repeatedly negate a point. + fn neg(self) -> CachedPoint { + let swapped = self.0.shuffle(Shuffle::BACD); + CachedPoint(swapped.blend(swapped.negate_lazy(), Lanes::D)) + } +} + +impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { + type Output = ExtendedPoint; + + /// Add an `ExtendedPoint` and a `CachedPoint`. + fn add(self, other: &'b CachedPoint) -> ExtendedPoint { + // The coefficients of an `ExtendedPoint` are reduced after + // every operation. If the `CachedPoint` was negated, its + // coefficients grow by one bit. So on input, `self` is + // bounded with `b < 0.007` and `other` is bounded with + // `b < 1.0`. + + let mut tmp = self.0; + + tmp = tmp.blend(tmp.diff_sum(), Lanes::AB); + // tmp = (Y1-X1 Y1+X1 Z1 T1) = (S0 S1 Z1 T1) with b < 1.6 + + // (tmp, other) bounded with b < (1.6, 1.0) < (2.5, 1.75). + tmp = &tmp * &other.0; + // tmp = (S0*S2' S1*S3' Z1*Z2' T1*T2') = (S8 S9 S10 S11) + + tmp = tmp.shuffle(Shuffle::ABDC); + // tmp = (S8 S9 S11 S10) + + tmp = tmp.diff_sum(); + // tmp = (S9-S8 S9+S8 S10-S11 S10+S11) = (S12 S13 S14 S15) + + let t0 = tmp.shuffle(Shuffle::ADDA); + // t0 = (S12 S15 S15 S12) + let t1 = tmp.shuffle(Shuffle::CBCB); + // t1 = (S14 S13 S14 S13) + + // All coefficients of t0, t1 are bounded with b < 1.6. + // Return (S12*S14 S15*S13 S15*S14 S12*S13) = (X3 Y3 Z3 T3) + ExtendedPoint(&t0 * &t1) + } +} + +impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { + type Output = ExtendedPoint; + + /// Implement subtraction by negating the point and adding. + /// + /// Empirically, this seems about the same cost as a custom + /// subtraction impl (maybe because the benefit is cancelled by + /// increased code size?) + fn sub(self, other: &'b CachedPoint) -> ExtendedPoint { + self + &(-other) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let P = ExtendedPoint::from(*point); + let mut points = [CachedPoint::from(P); 8]; + for i in 0..7 { + points[i + 1] = (&P + &points[i]).into(); + } + LookupTable(points) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let A = ExtendedPoint::from(*point); + let mut Ai = [CachedPoint::from(A); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).into(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + NafLookupTable5(Ai) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let A = ExtendedPoint::from(*point); + let mut Ai = [CachedPoint::from(A); 64]; + let A2 = A.double(); + for i in 0..63 { + Ai[i + 1] = (&A2 + &Ai[i]).into(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] + NafLookupTable8(Ai) + } +} + +#[cfg(test)] +mod test { + use super::*; + + fn serial_add(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) -> edwards::EdwardsPoint { + use backend::serial::u64::field::FieldElement51; + + let (X1, Y1, Z1, T1) = (P.X, P.Y, P.Z, P.T); + let (X2, Y2, Z2, T2) = (Q.X, Q.Y, Q.Z, Q.T); + + macro_rules! print_var { + ($x:ident) => { + println!("{} = {:?}", stringify!($x), $x.to_bytes()); + }; + } + + let S0 = &Y1 - &X1; // R1 + let S1 = &Y1 + &X1; // R3 + let S2 = &Y2 - &X2; // R2 + let S3 = &Y2 + &X2; // R4 + print_var!(S0); + print_var!(S1); + print_var!(S2); + print_var!(S3); + println!(""); + + let S4 = &S0 * &S2; // R5 = R1 * R2 + let S5 = &S1 * &S3; // R6 = R3 * R4 + let S6 = &Z1 * &Z2; // R8 + let S7 = &T1 * &T2; // R7 + print_var!(S4); + print_var!(S5); + print_var!(S6); + print_var!(S7); + println!(""); + + let S8 = &S4 * &FieldElement51([ 121666,0,0,0,0]); // R5 + let S9 = &S5 * &FieldElement51([ 121666,0,0,0,0]); // R6 + let S10 = &S6 * &FieldElement51([2*121666,0,0,0,0]); // R8 + let S11 = &S7 * &(-&FieldElement51([2*121665,0,0,0,0])); // R7 + print_var!(S8); + print_var!(S9); + print_var!(S10); + print_var!(S11); + println!(""); + + let S12 = &S9 - &S8; // R1 + let S13 = &S9 + &S8; // R4 + let S14 = &S10 - &S11; // R2 + let S15 = &S10 + &S11; // R3 + print_var!(S12); + print_var!(S13); + print_var!(S14); + print_var!(S15); + println!(""); + + let X3 = &S12 * &S14; // R1 * R2 + let Y3 = &S15 * &S13; // R3 * R4 + let Z3 = &S15 * &S14; // R2 * R3 + let T3 = &S12 * &S13; // R1 * R4 + + edwards::EdwardsPoint { + X: X3, + Y: Y3, + Z: Z3, + T: T3, + } + } + + fn addition_test_helper(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) { + // Test the serial implementation of the parallel addition formulas + let R_serial: edwards::EdwardsPoint = serial_add(P.into(), Q.into()).into(); + + // Test the vector implementation of the parallel readdition formulas + let cached_Q = CachedPoint::from(ExtendedPoint::from(Q)); + let R_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) + &cached_Q).into(); + let S_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) - &cached_Q).into(); + + println!("Testing point addition:"); + println!("P = {:?}", P); + println!("Q = {:?}", Q); + println!("cached Q = {:?}", cached_Q); + println!("R = P + Q = {:?}", &P + &Q); + println!("R_serial = {:?}", R_serial); + println!("R_vector = {:?}", R_vector); + println!("S = P - Q = {:?}", &P - &Q); + println!("S_vector = {:?}", S_vector); + assert_eq!(R_serial.compress(), (&P + &Q).compress()); + assert_eq!(R_vector.compress(), (&P + &Q).compress()); + assert_eq!(S_vector.compress(), (&P - &Q).compress()); + println!("OK!\n"); + } + + #[test] + fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() { + use constants; + use scalar::Scalar; + + println!("Testing id +- id"); + let P = edwards::EdwardsPoint::identity(); + let Q = edwards::EdwardsPoint::identity(); + addition_test_helper(P, Q); + + println!("Testing id +- B"); + let P = edwards::EdwardsPoint::identity(); + let Q = constants::ED25519_BASEPOINT_POINT; + addition_test_helper(P, Q); + + println!("Testing B +- B"); + let P = constants::ED25519_BASEPOINT_POINT; + let Q = constants::ED25519_BASEPOINT_POINT; + addition_test_helper(P, Q); + + println!("Testing B +- kB"); + let P = constants::ED25519_BASEPOINT_POINT; + let Q = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + addition_test_helper(P, Q); + } + + fn serial_double(P: edwards::EdwardsPoint) -> edwards::EdwardsPoint { + let (X1, Y1, Z1, _T1) = (P.X, P.Y, P.Z, P.T); + + macro_rules! print_var { + ($x:ident) => { + println!("{} = {:?}", stringify!($x), $x.to_bytes()); + }; + } + + let S0 = &X1 + &Y1; // R1 + print_var!(S0); + println!(""); + + let S1 = X1.square(); + let S2 = Y1.square(); + let S3 = Z1.square(); + let S4 = S0.square(); + print_var!(S1); + print_var!(S2); + print_var!(S3); + print_var!(S4); + println!(""); + + let S5 = &S1 + &S2; + let S6 = &S1 - &S2; + let S7 = &S3 + &S3; + let S8 = &S7 + &S6; + let S9 = &S5 - &S4; + print_var!(S5); + print_var!(S6); + print_var!(S7); + print_var!(S8); + print_var!(S9); + println!(""); + + let X3 = &S8 * &S9; + let Y3 = &S5 * &S6; + let Z3 = &S8 * &S6; + let T3 = &S5 * &S9; + + edwards::EdwardsPoint { + X: X3, + Y: Y3, + Z: Z3, + T: T3, + } + } + + fn doubling_test_helper(P: edwards::EdwardsPoint) { + let R1: edwards::EdwardsPoint = serial_double(P.into()).into(); + let R2: edwards::EdwardsPoint = ExtendedPoint::from(P).double().into(); + println!("Testing point doubling:"); + println!("P = {:?}", P); + println!("(serial) R1 = {:?}", R1); + println!("(vector) R2 = {:?}", R2); + println!("P + P = {:?}", &P + &P); + assert_eq!(R1.compress(), (&P + &P).compress()); + assert_eq!(R2.compress(), (&P + &P).compress()); + println!("OK!\n"); + } + + #[test] + fn vector_doubling_vs_serial_doubling_vs_edwards_extendedpoint() { + use constants; + use scalar::Scalar; + + println!("Testing [2]id"); + let P = edwards::EdwardsPoint::identity(); + doubling_test_helper(P); + + println!("Testing [2]B"); + let P = constants::ED25519_BASEPOINT_POINT; + doubling_test_helper(P); + + println!("Testing [2]([k]B)"); + let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + doubling_test_helper(P); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/field.rs new file mode 100644 index 0000000..edd1fa6 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/field.rs @@ -0,0 +1,985 @@ +// -*- mode: rust; coding: utf-8; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! An implementation of 4-way vectorized 32bit field arithmetic using +//! AVX2. +//! +//! The `FieldElement2625x4` struct provides a vector of four field +//! elements, implemented using AVX2 operations. Its API is designed +//! to abstract away the platform-dependent details, so that point +//! arithmetic can be implemented only in terms of a vector of field +//! elements. +//! +//! At this level, the API is optimized for speed and not safety. The +//! `FieldElement2625x4` does not always perform reductions. The pre- +//! and post-conditions on the bounds of the coefficients are +//! documented for each method, but it is the caller's responsibility +//! to ensure that there are no overflows. + +#![allow(non_snake_case)] + +const A_LANES: u8 = 0b0000_0101; +const B_LANES: u8 = 0b0000_1010; +const C_LANES: u8 = 0b0101_0000; +const D_LANES: u8 = 0b1010_0000; + +#[allow(unused)] +const A_LANES64: u8 = 0b00_00_00_11; +#[allow(unused)] +const B_LANES64: u8 = 0b00_00_11_00; +#[allow(unused)] +const C_LANES64: u8 = 0b00_11_00_00; +#[allow(unused)] +const D_LANES64: u8 = 0b11_00_00_00; + +use core::ops::{Add, Mul, Neg}; +use packed_simd::{i32x8, u32x8, u64x4, IntoBits}; + +use backend::vector::avx2::constants::{P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO}; +use backend::serial::u64::field::FieldElement51; + +/// Unpack 32-bit lanes into 64-bit lanes: +/// ```ascii,no_run +/// (a0, b0, a1, b1, c0, d0, c1, d1) +/// ``` +/// into +/// ```ascii,no_run +/// (a0, 0, b0, 0, c0, 0, d0, 0) +/// (a1, 0, b1, 0, c1, 0, d1, 0) +/// ``` +#[inline(always)] +fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { + let a: u32x8; + let b: u32x8; + let zero = i32x8::new(0, 0, 0, 0, 0, 0, 0, 0); + unsafe { + use core::arch::x86_64::_mm256_unpackhi_epi32; + use core::arch::x86_64::_mm256_unpacklo_epi32; + a = _mm256_unpacklo_epi32(src.into_bits(), zero.into_bits()).into_bits(); + b = _mm256_unpackhi_epi32(src.into_bits(), zero.into_bits()).into_bits(); + } + (a, b) +} + +/// Repack 64-bit lanes into 32-bit lanes: +/// ```ascii,no_run +/// (a0, 0, b0, 0, c0, 0, d0, 0) +/// (a1, 0, b1, 0, c1, 0, d1, 0) +/// ``` +/// into +/// ```ascii,no_run +/// (a0, b0, a1, b1, c0, d0, c1, d1) +/// ``` +#[inline(always)] +fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { + unsafe { + use core::arch::x86_64::_mm256_blend_epi32; + use core::arch::x86_64::_mm256_shuffle_epi32; + + // Input: x = (a0, 0, b0, 0, c0, 0, d0, 0) + // Input: y = (a1, 0, b1, 0, c1, 0, d1, 0) + + let x_shuffled = _mm256_shuffle_epi32(x.into_bits(), 0b11_01_10_00); + let y_shuffled = _mm256_shuffle_epi32(y.into_bits(), 0b10_00_11_01); + + // x' = (a0, b0, 0, 0, c0, d0, 0, 0) + // y' = ( 0, 0, a1, b1, 0, 0, c1, d1) + + return _mm256_blend_epi32(x_shuffled, y_shuffled, 0b11001100).into_bits(); + } +} + +/// The `Lanes` enum represents a subset of the lanes `A,B,C,D` of a +/// `FieldElement2625x4`. +/// +/// It's used to specify blend operations without +/// having to know details about the data layout of the +/// `FieldElement2625x4`. +#[derive(Copy, Clone, Debug)] +pub enum Lanes { + C, + D, + AB, + AC, + CD, + AD, + BC, + ABCD, +} + +/// The `Shuffle` enum represents a shuffle of a `FieldElement2625x4`. +/// +/// The enum variants are named by what they do to a vector \\( +/// (A,B,C,D) \\); for instance, `Shuffle::BADC` turns \\( (A, B, C, +/// D) \\) into \\( (B, A, D, C) \\). +#[derive(Copy, Clone, Debug)] +pub enum Shuffle { + AAAA, + BBBB, + CACA, + DBBD, + ADDA, + CBCB, + ABAB, + BADC, + BACD, + ABDC, +} + +/// A vector of four field elements. +/// +/// Each operation on a `FieldElement2625x4` has documented effects on +/// the bounds of the coefficients. This API is designed for speed +/// and not safety; it is the caller's responsibility to ensure that +/// the post-conditions of one operation are compatible with the +/// pre-conditions of the next. +#[derive(Clone, Copy, Debug)] +pub struct FieldElement2625x4(pub(crate) [u32x8; 5]); + +use subtle::Choice; +use subtle::ConditionallySelectable; + +impl ConditionallySelectable for FieldElement2625x4 { + fn conditional_select( + a: &FieldElement2625x4, + b: &FieldElement2625x4, + choice: Choice, + ) -> FieldElement2625x4 { + let mask = (-(choice.unwrap_u8() as i32)) as u32; + let mask_vec = u32x8::splat(mask); + FieldElement2625x4([ + a.0[0] ^ (mask_vec & (a.0[0] ^ b.0[0])), + a.0[1] ^ (mask_vec & (a.0[1] ^ b.0[1])), + a.0[2] ^ (mask_vec & (a.0[2] ^ b.0[2])), + a.0[3] ^ (mask_vec & (a.0[3] ^ b.0[3])), + a.0[4] ^ (mask_vec & (a.0[4] ^ b.0[4])), + ]) + } + + fn conditional_assign( + &mut self, + other: &FieldElement2625x4, + choice: Choice, + ) { + let mask = (-(choice.unwrap_u8() as i32)) as u32; + let mask_vec = u32x8::splat(mask); + self.0[0] ^= mask_vec & (self.0[0] ^ other.0[0]); + self.0[1] ^= mask_vec & (self.0[1] ^ other.0[1]); + self.0[2] ^= mask_vec & (self.0[2] ^ other.0[2]); + self.0[3] ^= mask_vec & (self.0[3] ^ other.0[3]); + self.0[4] ^= mask_vec & (self.0[4] ^ other.0[4]); + } +} + +impl FieldElement2625x4 { + /// Split this vector into an array of four (serial) field + /// elements. + pub fn split(&self) -> [FieldElement51; 4] { + let mut out = [FieldElement51::zero(); 4]; + for i in 0..5 { + let a_2i = self.0[i].extract(0) as u64; // + let b_2i = self.0[i].extract(1) as u64; // + let a_2i_1 = self.0[i].extract(2) as u64; // `. + let b_2i_1 = self.0[i].extract(3) as u64; // | pre-swapped to avoid + let c_2i = self.0[i].extract(4) as u64; // | a cross lane shuffle + let d_2i = self.0[i].extract(5) as u64; // .' + let c_2i_1 = self.0[i].extract(6) as u64; // + let d_2i_1 = self.0[i].extract(7) as u64; // + + out[0].0[i] = a_2i + (a_2i_1 << 26); + out[1].0[i] = b_2i + (b_2i_1 << 26); + out[2].0[i] = c_2i + (c_2i_1 << 26); + out[3].0[i] = d_2i + (d_2i_1 << 26); + } + + out + } + + /// Rearrange the elements of this vector according to `control`. + /// + /// The `control` parameter should be a compile-time constant, so + /// that when this function is inlined, LLVM is able to lower the + /// shuffle using an immediate. + #[inline] + pub fn shuffle(&self, control: Shuffle) -> FieldElement2625x4 { + #[inline(always)] + fn shuffle_lanes(x: u32x8, control: Shuffle) -> u32x8 { + unsafe { + use core::arch::x86_64::_mm256_permutevar8x32_epi32; + + let c: u32x8 = match control { + Shuffle::AAAA => u32x8::new(0, 0, 2, 2, 0, 0, 2, 2), + Shuffle::BBBB => u32x8::new(1, 1, 3, 3, 1, 1, 3, 3), + Shuffle::CACA => u32x8::new(4, 0, 6, 2, 4, 0, 6, 2), + Shuffle::DBBD => u32x8::new(5, 1, 7, 3, 1, 5, 3, 7), + Shuffle::ADDA => u32x8::new(0, 5, 2, 7, 5, 0, 7, 2), + Shuffle::CBCB => u32x8::new(4, 1, 6, 3, 4, 1, 6, 3), + Shuffle::ABAB => u32x8::new(0, 1, 2, 3, 0, 1, 2, 3), + Shuffle::BADC => u32x8::new(1, 0, 3, 2, 5, 4, 7, 6), + Shuffle::BACD => u32x8::new(1, 0, 3, 2, 4, 5, 6, 7), + Shuffle::ABDC => u32x8::new(0, 1, 2, 3, 5, 4, 7, 6), + }; + // Note that this gets turned into a generic LLVM + // shuffle-by-constants, which can be lowered to a simpler + // instruction than a generic permute. + _mm256_permutevar8x32_epi32(x.into_bits(), c.into_bits()).into_bits() + } + } + + FieldElement2625x4([ + shuffle_lanes(self.0[0], control), + shuffle_lanes(self.0[1], control), + shuffle_lanes(self.0[2], control), + shuffle_lanes(self.0[3], control), + shuffle_lanes(self.0[4], control), + ]) + } + + /// Blend `self` with `other`, taking lanes specified in `control` from `other`. + /// + /// The `control` parameter should be a compile-time constant, so + /// that this function can be inlined and LLVM can lower it to a + /// blend instruction using an immediate. + #[inline] + pub fn blend(&self, other: FieldElement2625x4, control: Lanes) -> FieldElement2625x4 { + #[inline(always)] + fn blend_lanes(x: u32x8, y: u32x8, control: Lanes) -> u32x8 { + unsafe { + use core::arch::x86_64::_mm256_blend_epi32; + + // This would be much cleaner if we could factor out the match + // statement on the control. Unfortunately, rustc forgets + // constant-info very quickly, so we can't even write + // ``` + // match control { + // Lanes::C => { + // let imm = C_LANES as i32; + // _mm256_blend_epi32(..., imm) + // ``` + // let alone + // ``` + // let imm = match control { + // Lanes::C => C_LANES as i32, + // } + // _mm256_blend_epi32(..., imm) + // ``` + // even though both of these would be constant-folded by LLVM + // at a lower level (as happens in the shuffle implementation, + // which does not require a shuffle immediate but *is* lowered + // to immediate shuffles anyways). + match control { + Lanes::C => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), C_LANES as i32).into_bits() + } + Lanes::D => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), D_LANES as i32).into_bits() + } + Lanes::AD => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | D_LANES) as i32) + .into_bits() + } + Lanes::AB => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | B_LANES) as i32) + .into_bits() + } + Lanes::AC => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | C_LANES) as i32) + .into_bits() + } + Lanes::CD => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), (C_LANES | D_LANES) as i32) + .into_bits() + } + Lanes::BC => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), (B_LANES | C_LANES) as i32) + .into_bits() + } + Lanes::ABCD => _mm256_blend_epi32( + x.into_bits(), + y.into_bits(), + (A_LANES | B_LANES | C_LANES | D_LANES) as i32, + ).into_bits(), + } + } + } + + FieldElement2625x4([ + blend_lanes(self.0[0], other.0[0], control), + blend_lanes(self.0[1], other.0[1], control), + blend_lanes(self.0[2], other.0[2], control), + blend_lanes(self.0[3], other.0[3], control), + blend_lanes(self.0[4], other.0[4], control), + ]) + } + + /// Construct a vector of zeros. + pub fn zero() -> FieldElement2625x4 { + FieldElement2625x4([u32x8::splat(0); 5]) + } + + /// Convenience wrapper around `new(x,x,x,x)`. + pub fn splat(x: &FieldElement51) -> FieldElement2625x4 { + FieldElement2625x4::new(x, x, x, x) + } + + /// Create a `FieldElement2625x4` from four `FieldElement51`s. + /// + /// # Postconditions + /// + /// The resulting `FieldElement2625x4` is bounded with \\( b < 0.0002 \\). + pub fn new( + x0: &FieldElement51, + x1: &FieldElement51, + x2: &FieldElement51, + x3: &FieldElement51, + ) -> FieldElement2625x4 { + let mut buf = [u32x8::splat(0); 5]; + let low_26_bits = (1 << 26) - 1; + for i in 0..5 { + let a_2i = (x0.0[i] & low_26_bits) as u32; + let a_2i_1 = (x0.0[i] >> 26) as u32; + let b_2i = (x1.0[i] & low_26_bits) as u32; + let b_2i_1 = (x1.0[i] >> 26) as u32; + let c_2i = (x2.0[i] & low_26_bits) as u32; + let c_2i_1 = (x2.0[i] >> 26) as u32; + let d_2i = (x3.0[i] & low_26_bits) as u32; + let d_2i_1 = (x3.0[i] >> 26) as u32; + + buf[i] = u32x8::new(a_2i, b_2i, a_2i_1, b_2i_1, c_2i, d_2i, c_2i_1, d_2i_1); + } + + // We don't know that the original `FieldElement51`s were + // fully reduced, so the odd limbs may exceed 2^25. + // Reduce them to be sure. + FieldElement2625x4(buf).reduce() + } + + /// Given \\((A,B,C,D)\\), compute \\((-A,-B,-C,-D)\\), without + /// performing a reduction. + /// + /// # Preconditions + /// + /// The coefficients of `self` must be bounded with \\( b < 0.999 \\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 1 \\). + #[inline] + pub fn negate_lazy(&self) -> FieldElement2625x4 { + // The limbs of self are bounded with b < 0.999, while the + // smallest limb of 2*p is 67108845 > 2^{26+0.9999}, so + // underflows are not possible. + FieldElement2625x4([ + P_TIMES_2_LO - self.0[0], + P_TIMES_2_HI - self.0[1], + P_TIMES_2_HI - self.0[2], + P_TIMES_2_HI - self.0[3], + P_TIMES_2_HI - self.0[4], + ]) + } + + /// Given `self = (A,B,C,D)`, compute `(B - A, B + A, D - C, D + C)`. + /// + /// # Preconditions + /// + /// The coefficients of `self` must be bounded with \\( b < 0.01 \\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 1.6 \\). + #[inline] + pub fn diff_sum(&self) -> FieldElement2625x4 { + // tmp1 = (B, A, D, C) + let tmp1 = self.shuffle(Shuffle::BADC); + // tmp2 = (-A, B, -C, D) + let tmp2 = self.blend(self.negate_lazy(), Lanes::AC); + // (B - A, B + A, D - C, D + C) bounded with b < 1.6 + tmp1 + tmp2 + } + + /// Reduce this vector of field elements \\(\mathrm{mod} p\\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.0002 \\). + #[inline] + pub fn reduce(&self) -> FieldElement2625x4 { + let shifts = i32x8::new(26, 26, 25, 25, 26, 26, 25, 25); + let masks = u32x8::new( + (1 << 26) - 1, + (1 << 26) - 1, + (1 << 25) - 1, + (1 << 25) - 1, + (1 << 26) - 1, + (1 << 26) - 1, + (1 << 25) - 1, + (1 << 25) - 1, + ); + + // Let c(x) denote the carryout of the coefficient x. + // + // Given ( x0, y0, x1, y1, z0, w0, z1, w1), + // compute (c(x1), c(y1), c(x0), c(y0), c(z1), c(w1), c(z0), c(w0)). + // + // The carryouts are bounded by 2^(32 - 25) = 2^7. + let rotated_carryout = |v: u32x8| -> u32x8 { + unsafe { + use core::arch::x86_64::_mm256_srlv_epi32; + use core::arch::x86_64::_mm256_shuffle_epi32; + + let c = _mm256_srlv_epi32(v.into_bits(), shifts.into_bits()); + _mm256_shuffle_epi32(c, 0b01_00_11_10).into_bits() + } + }; + + // Combine (lo, lo, lo, lo, lo, lo, lo, lo) + // with (hi, hi, hi, hi, hi, hi, hi, hi) + // to (lo, lo, hi, hi, lo, lo, hi, hi) + // + // This allows combining carryouts, e.g., + // + // lo (c(x1), c(y1), c(x0), c(y0), c(z1), c(w1), c(z0), c(w0)) + // hi (c(x3), c(y3), c(x2), c(y2), c(z3), c(w3), c(z2), c(w2)) + // -> (c(x1), c(y1), c(x2), c(y2), c(z1), c(w1), c(z2), c(w2)) + // + // which is exactly the vector of carryins for + // + // ( x2, y2, x3, y3, z2, w2, z3, w3). + // + let combine = |v_lo: u32x8, v_hi: u32x8| -> u32x8 { + unsafe { + use core::arch::x86_64::_mm256_blend_epi32; + _mm256_blend_epi32(v_lo.into_bits(), v_hi.into_bits(), 0b11_00_11_00).into_bits() + } + }; + + let mut v = self.0; + + let c10 = rotated_carryout(v[0]); + v[0] = (v[0] & masks) + combine(u32x8::splat(0), c10); + + let c32 = rotated_carryout(v[1]); + v[1] = (v[1] & masks) + combine(c10, c32); + + let c54 = rotated_carryout(v[2]); + v[2] = (v[2] & masks) + combine(c32, c54); + + let c76 = rotated_carryout(v[3]); + v[3] = (v[3] & masks) + combine(c54, c76); + + let c98 = rotated_carryout(v[4]); + v[4] = (v[4] & masks) + combine(c76, c98); + + let c9_19: u32x8 = unsafe { + use core::arch::x86_64::_mm256_mul_epu32; + use core::arch::x86_64::_mm256_shuffle_epi32; + + // Need to rearrange c98, since vpmuludq uses the low + // 32-bits of each 64-bit lane to compute the product: + // + // c98 = (c(x9), c(y9), c(x8), c(y8), c(z9), c(w9), c(z8), c(w8)); + // c9_spread = (c(x9), c(x8), c(y9), c(y8), c(z9), c(z8), c(w9), c(w8)). + let c9_spread = _mm256_shuffle_epi32(c98.into_bits(), 0b11_01_10_00); + + // Since the carryouts are bounded by 2^7, their products with 19 + // are bounded by 2^11.25. This means that + // + // c9_19_spread = (19*c(x9), 0, 19*c(y9), 0, 19*c(z9), 0, 19*c(w9), 0). + let c9_19_spread = _mm256_mul_epu32(c9_spread, u64x4::splat(19).into_bits()); + + // Unshuffle: + // c9_19 = (19*c(x9), 19*c(y9), 0, 0, 19*c(z9), 19*c(w9), 0, 0). + _mm256_shuffle_epi32(c9_19_spread, 0b11_01_10_00).into_bits() + }; + + // Add the final carryin. + v[0] = v[0] + c9_19; + + // Each output coefficient has exactly one carryin, which is + // bounded by 2^11.25, so they are bounded as + // + // c_even < 2^26 + 2^11.25 < 26.00006 < 2^{26+b} + // c_odd < 2^25 + 2^11.25 < 25.0001 < 2^{25+b} + // + // where b = 0.0002. + FieldElement2625x4(v) + } + + /// Given an array of wide coefficients, reduce them to a `FieldElement2625x4`. + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.007 \\). + #[inline] + fn reduce64(mut z: [u64x4; 10]) -> FieldElement2625x4 { + // These aren't const because splat isn't a const fn + let LOW_25_BITS: u64x4 = u64x4::splat((1 << 25) - 1); + let LOW_26_BITS: u64x4 = u64x4::splat((1 << 26) - 1); + + // Carry the value from limb i = 0..8 to limb i+1 + let carry = |z: &mut [u64x4; 10], i: usize| { + debug_assert!(i < 9); + if i % 2 == 0 { + // Even limbs have 26 bits + z[i + 1] = z[i + 1] + (z[i] >> 26); + z[i] = z[i] & LOW_26_BITS; + } else { + // Odd limbs have 25 bits + z[i + 1] = z[i + 1] + (z[i] >> 25); + z[i] = z[i] & LOW_25_BITS; + } + }; + + // Perform two halves of the carry chain in parallel. + carry(&mut z, 0); carry(&mut z, 4); + carry(&mut z, 1); carry(&mut z, 5); + carry(&mut z, 2); carry(&mut z, 6); + carry(&mut z, 3); carry(&mut z, 7); + // Since z[3] < 2^64, c < 2^(64-25) = 2^39, + // so z[4] < 2^26 + 2^39 < 2^39.0002 + carry(&mut z, 4); carry(&mut z, 8); + // Now z[4] < 2^26 + // and z[5] < 2^25 + 2^13.0002 < 2^25.0004 (good enough) + + // Last carry has a multiplication by 19. In the serial case we + // do a 64-bit multiplication by 19, but here we want to do a + // 32-bit multiplication. However, if we only know z[9] < 2^64, + // the carry is bounded as c < 2^(64-25) = 2^39, which is too + // big. To ensure c < 2^32, we would need z[9] < 2^57. + // Instead, we split the carry in two, with c = c_0 + c_1*2^26. + + let c = z[9] >> 25; + z[9] = z[9] & LOW_25_BITS; + let mut c0: u64x4 = c & LOW_26_BITS; // c0 < 2^26; + let mut c1: u64x4 = c >> 26; // c1 < 2^(39-26) = 2^13; + + unsafe { + use core::arch::x86_64::_mm256_mul_epu32; + let x19 = u64x4::splat(19); + c0 = _mm256_mul_epu32(c0.into_bits(), x19.into_bits()).into_bits(); // c0 < 2^30.25 + c1 = _mm256_mul_epu32(c1.into_bits(), x19.into_bits()).into_bits(); // c1 < 2^17.25 + } + + z[0] = z[0] + c0; // z0 < 2^26 + 2^30.25 < 2^30.33 + z[1] = z[1] + c1; // z1 < 2^25 + 2^17.25 < 2^25.0067 + carry(&mut z, 0); // z0 < 2^26, z1 < 2^25.0067 + 2^4.33 = 2^25.007 + + // The output coefficients are bounded with + // + // b = 0.007 for z[1] + // b = 0.0004 for z[5] + // b = 0 for other z[i]. + // + // So the packed result is bounded with b = 0.007. + FieldElement2625x4([ + repack_pair(z[0].into_bits(), z[1].into_bits()), + repack_pair(z[2].into_bits(), z[3].into_bits()), + repack_pair(z[4].into_bits(), z[5].into_bits()), + repack_pair(z[6].into_bits(), z[7].into_bits()), + repack_pair(z[8].into_bits(), z[9].into_bits()), + ]) + } + + /// Square this field element, and negate the result's \\(D\\) value. + /// + /// # Preconditions + /// + /// The coefficients of `self` must be bounded with \\( b < 1.5 \\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.007 \\). + pub fn square_and_negate_D(&self) -> FieldElement2625x4 { + #[inline(always)] + fn m(x: u32x8, y: u32x8) -> u64x4 { + use core::arch::x86_64::_mm256_mul_epu32; + unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + } + + #[inline(always)] + fn m_lo(x: u32x8, y: u32x8) -> u32x8 { + use core::arch::x86_64::_mm256_mul_epu32; + unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + } + + let v19 = u32x8::new(19, 0, 19, 0, 19, 0, 19, 0); + + let (x0, x1) = unpack_pair(self.0[0]); + let (x2, x3) = unpack_pair(self.0[1]); + let (x4, x5) = unpack_pair(self.0[2]); + let (x6, x7) = unpack_pair(self.0[3]); + let (x8, x9) = unpack_pair(self.0[4]); + + let x0_2 = x0 << 1; + let x1_2 = x1 << 1; + let x2_2 = x2 << 1; + let x3_2 = x3 << 1; + let x4_2 = x4 << 1; + let x5_2 = x5 << 1; + let x6_2 = x6 << 1; + let x7_2 = x7 << 1; + + let x5_19 = m_lo(v19, x5); + let x6_19 = m_lo(v19, x6); + let x7_19 = m_lo(v19, x7); + let x8_19 = m_lo(v19, x8); + let x9_19 = m_lo(v19, x9); + + let mut z0 = m(x0, x0) + m(x2_2,x8_19) + m(x4_2,x6_19) + ((m(x1_2,x9_19) + m(x3_2,x7_19) + m(x5,x5_19)) << 1); + let mut z1 = m(x0_2,x1) + m(x3_2,x8_19) + m(x5_2,x6_19) + ((m(x2,x9_19) + m(x4,x7_19)) << 1); + let mut z2 = m(x0_2,x2) + m(x1_2,x1) + m(x4_2,x8_19) + m(x6,x6_19) + ((m(x3_2,x9_19) + m(x5_2,x7_19)) << 1); + let mut z3 = m(x0_2,x3) + m(x1_2,x2) + m(x5_2,x8_19) + ((m(x4,x9_19) + m(x6,x7_19)) << 1); + let mut z4 = m(x0_2,x4) + m(x1_2,x3_2) + m(x2, x2) + m(x6_2,x8_19) + ((m(x5_2,x9_19) + m(x7,x7_19)) << 1); + let mut z5 = m(x0_2,x5) + m(x1_2,x4) + m(x2_2,x3) + m(x7_2,x8_19) + ((m(x6,x9_19)) << 1); + let mut z6 = m(x0_2,x6) + m(x1_2,x5_2) + m(x2_2,x4) + m(x3_2,x3) + m(x8,x8_19) + ((m(x7_2,x9_19)) << 1); + let mut z7 = m(x0_2,x7) + m(x1_2,x6) + m(x2_2,x5) + m(x3_2,x4) + ((m(x8,x9_19)) << 1); + let mut z8 = m(x0_2,x8) + m(x1_2,x7_2) + m(x2_2,x6) + m(x3_2,x5_2) + m(x4,x4) + ((m(x9,x9_19)) << 1); + let mut z9 = m(x0_2,x9) + m(x1_2,x8) + m(x2_2,x7) + m(x3_2,x6) + m(x4_2,x5); + + // The biggest z_i is bounded as z_i < 249*2^(51 + 2*b); + // if b < 1.5 we get z_i < 4485585228861014016. + // + // The limbs of the multiples of p are bounded above by + // + // 0x3fffffff << 37 = 9223371899415822336 < 2^63 + // + // and below by + // + // 0x1fffffff << 37 = 4611685880988434432 + // > 4485585228861014016 + // + // So these multiples of p are big enough to avoid underflow + // in subtraction, and small enough to fit within u64 + // with room for a carry. + + let low__p37 = u64x4::splat(0x3ffffed << 37); + let even_p37 = u64x4::splat(0x3ffffff << 37); + let odd__p37 = u64x4::splat(0x1ffffff << 37); + + let negate_D = |x: u64x4, p: u64x4| -> u64x4 { + unsafe { + use core::arch::x86_64::_mm256_blend_epi32; + _mm256_blend_epi32(x.into_bits(), (p - x).into_bits(), D_LANES64 as i32).into_bits() + } + }; + + z0 = negate_D(z0, low__p37); + z1 = negate_D(z1, odd__p37); + z2 = negate_D(z2, even_p37); + z3 = negate_D(z3, odd__p37); + z4 = negate_D(z4, even_p37); + z5 = negate_D(z5, odd__p37); + z6 = negate_D(z6, even_p37); + z7 = negate_D(z7, odd__p37); + z8 = negate_D(z8, even_p37); + z9 = negate_D(z9, odd__p37); + + FieldElement2625x4::reduce64([z0, z1, z2, z3, z4, z5, z6, z7, z8, z9]) + } +} + +impl Neg for FieldElement2625x4 { + type Output = FieldElement2625x4; + + /// Negate this field element, performing a reduction. + /// + /// If the coefficients are known to be small, use `negate_lazy` + /// to avoid performing a reduction. + /// + /// # Preconditions + /// + /// The coefficients of `self` must be bounded with \\( b < 4.0 \\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.0002 \\). + #[inline] + fn neg(self) -> FieldElement2625x4 { + FieldElement2625x4([ + P_TIMES_16_LO - self.0[0], + P_TIMES_16_HI - self.0[1], + P_TIMES_16_HI - self.0[2], + P_TIMES_16_HI - self.0[3], + P_TIMES_16_HI - self.0[4], + ]).reduce() + } +} + +impl Add for FieldElement2625x4 { + type Output = FieldElement2625x4; + /// Add two `FieldElement2625x4`s, without performing a reduction. + #[inline] + fn add(self, rhs: FieldElement2625x4) -> FieldElement2625x4 { + FieldElement2625x4([ + self.0[0] + rhs.0[0], + self.0[1] + rhs.0[1], + self.0[2] + rhs.0[2], + self.0[3] + rhs.0[3], + self.0[4] + rhs.0[4], + ]) + } +} + +impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { + type Output = FieldElement2625x4; + /// Perform a multiplication by a vector of small constants. + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.007 \\). + #[inline] + fn mul(self, scalars: (u32, u32, u32, u32)) -> FieldElement2625x4 { + unsafe { + use core::arch::x86_64::_mm256_mul_epu32; + + let consts = u32x8::new(scalars.0, 0, scalars.1, 0, scalars.2, 0, scalars.3, 0); + + let (b0, b1) = unpack_pair(self.0[0]); + let (b2, b3) = unpack_pair(self.0[1]); + let (b4, b5) = unpack_pair(self.0[2]); + let (b6, b7) = unpack_pair(self.0[3]); + let (b8, b9) = unpack_pair(self.0[4]); + + FieldElement2625x4::reduce64([ + _mm256_mul_epu32(b0.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b1.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b2.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b3.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b4.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b5.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b6.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b7.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b8.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b9.into_bits(), consts.into_bits()).into_bits(), + ]) + } + } +} + +impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { + type Output = FieldElement2625x4; + /// Multiply `self` by `rhs`. + /// + /// # Preconditions + /// + /// The coefficients of `self` must be bounded with \\( b < 2.5 \\). + /// + /// The coefficients of `rhs` must be bounded with \\( b < 1.75 \\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.007 \\). + /// + fn mul(self, rhs: &'b FieldElement2625x4) -> FieldElement2625x4 { + #[inline(always)] + fn m(x: u32x8, y: u32x8) -> u64x4 { + use core::arch::x86_64::_mm256_mul_epu32; + unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + } + + #[inline(always)] + fn m_lo(x: u32x8, y: u32x8) -> u32x8 { + use core::arch::x86_64::_mm256_mul_epu32; + unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + } + + let (x0, x1) = unpack_pair(self.0[0]); + let (x2, x3) = unpack_pair(self.0[1]); + let (x4, x5) = unpack_pair(self.0[2]); + let (x6, x7) = unpack_pair(self.0[3]); + let (x8, x9) = unpack_pair(self.0[4]); + + let (y0, y1) = unpack_pair(rhs.0[0]); + let (y2, y3) = unpack_pair(rhs.0[1]); + let (y4, y5) = unpack_pair(rhs.0[2]); + let (y6, y7) = unpack_pair(rhs.0[3]); + let (y8, y9) = unpack_pair(rhs.0[4]); + + let v19 = u32x8::new(19, 0, 19, 0, 19, 0, 19, 0); + + let y1_19 = m_lo(v19, y1); // This fits in a u32 + let y2_19 = m_lo(v19, y2); // iff 26 + b + lg(19) < 32 + let y3_19 = m_lo(v19, y3); // if b < 32 - 26 - 4.248 = 1.752 + let y4_19 = m_lo(v19, y4); + let y5_19 = m_lo(v19, y5); + let y6_19 = m_lo(v19, y6); + let y7_19 = m_lo(v19, y7); + let y8_19 = m_lo(v19, y8); + let y9_19 = m_lo(v19, y9); + + let x1_2 = x1 + x1; // This fits in a u32 iff 25 + b + 1 < 32 + let x3_2 = x3 + x3; // iff b < 6 + let x5_2 = x5 + x5; + let x7_2 = x7 + x7; + let x9_2 = x9 + x9; + + let z0 = m(x0,y0) + m(x1_2,y9_19) + m(x2,y8_19) + m(x3_2,y7_19) + m(x4,y6_19) + m(x5_2,y5_19) + m(x6,y4_19) + m(x7_2,y3_19) + m(x8,y2_19) + m(x9_2,y1_19); + let z1 = m(x0,y1) + m(x1,y0) + m(x2,y9_19) + m(x3,y8_19) + m(x4,y7_19) + m(x5,y6_19) + m(x6,y5_19) + m(x7,y4_19) + m(x8,y3_19) + m(x9,y2_19); + let z2 = m(x0,y2) + m(x1_2,y1) + m(x2,y0) + m(x3_2,y9_19) + m(x4,y8_19) + m(x5_2,y7_19) + m(x6,y6_19) + m(x7_2,y5_19) + m(x8,y4_19) + m(x9_2,y3_19); + let z3 = m(x0,y3) + m(x1,y2) + m(x2,y1) + m(x3,y0) + m(x4,y9_19) + m(x5,y8_19) + m(x6,y7_19) + m(x7,y6_19) + m(x8,y5_19) + m(x9,y4_19); + let z4 = m(x0,y4) + m(x1_2,y3) + m(x2,y2) + m(x3_2,y1) + m(x4,y0) + m(x5_2,y9_19) + m(x6,y8_19) + m(x7_2,y7_19) + m(x8,y6_19) + m(x9_2,y5_19); + let z5 = m(x0,y5) + m(x1,y4) + m(x2,y3) + m(x3,y2) + m(x4,y1) + m(x5,y0) + m(x6,y9_19) + m(x7,y8_19) + m(x8,y7_19) + m(x9,y6_19); + let z6 = m(x0,y6) + m(x1_2,y5) + m(x2,y4) + m(x3_2,y3) + m(x4,y2) + m(x5_2,y1) + m(x6,y0) + m(x7_2,y9_19) + m(x8,y8_19) + m(x9_2,y7_19); + let z7 = m(x0,y7) + m(x1,y6) + m(x2,y5) + m(x3,y4) + m(x4,y3) + m(x5,y2) + m(x6,y1) + m(x7,y0) + m(x8,y9_19) + m(x9,y8_19); + let z8 = m(x0,y8) + m(x1_2,y7) + m(x2,y6) + m(x3_2,y5) + m(x4,y4) + m(x5_2,y3) + m(x6,y2) + m(x7_2,y1) + m(x8,y0) + m(x9_2,y9_19); + let z9 = m(x0,y9) + m(x1,y8) + m(x2,y7) + m(x3,y6) + m(x4,y5) + m(x5,y4) + m(x6,y3) + m(x7,y2) + m(x8,y1) + m(x9,y0); + + // The bounds on z[i] are the same as in the serial 32-bit code + // and the comment below is copied from there: + + // How big is the contribution to z[i+j] from x[i], y[j]? + // + // Using the bounds above, we get: + // + // i even, j even: x[i]*y[j] < 2^(26+b)*2^(26+b) = 2*2^(51+2*b) + // i odd, j even: x[i]*y[j] < 2^(25+b)*2^(26+b) = 1*2^(51+2*b) + // i even, j odd: x[i]*y[j] < 2^(26+b)*2^(25+b) = 1*2^(51+2*b) + // i odd, j odd: 2*x[i]*y[j] < 2*2^(25+b)*2^(25+b) = 1*2^(51+2*b) + // + // We perform inline reduction mod p by replacing 2^255 by 19 + // (since 2^255 - 19 = 0 mod p). This adds a factor of 19, so + // we get the bounds (z0 is the biggest one, but calculated for + // posterity here in case finer estimation is needed later): + // + // z0 < ( 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 249*2^(51 + 2*b) + // z1 < ( 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 154*2^(51 + 2*b) + // z2 < ( 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 195*2^(51 + 2*b) + // z3 < ( 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 118*2^(51 + 2*b) + // z4 < ( 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 141*2^(51 + 2*b) + // z5 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 82*2^(51 + 2*b) + // z6 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 87*2^(51 + 2*b) + // z7 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 )*2^(51 + 2b) = 46*2^(51 + 2*b) + // z8 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 )*2^(51 + 2b) = 33*2^(51 + 2*b) + // z9 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 )*2^(51 + 2b) = 10*2^(51 + 2*b) + // + // So z[0] fits into a u64 if 51 + 2*b + lg(249) < 64 + // if b < 2.5. + + // In fact this bound is slightly sloppy, since it treats both + // inputs x and y as being bounded by the same parameter b, + // while they are in fact bounded by b_x and b_y, and we + // already require that b_y < 1.75 in order to fit the + // multiplications by 19 into a u32. The tighter bound on b_y + // means we could get a tighter bound on the outputs, or a + // looser bound on b_x. + FieldElement2625x4::reduce64([z0, z1, z2, z3, z4, z5, z6, z7, z8, z9]) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn scale_by_curve_constants() { + let mut x = FieldElement2625x4::splat(&FieldElement51::one()); + + x = x * (121666, 121666, 2*121666, 2*121665); + + let xs = x.split(); + assert_eq!(xs[0], FieldElement51([121666, 0, 0, 0, 0])); + assert_eq!(xs[1], FieldElement51([121666, 0, 0, 0, 0])); + assert_eq!(xs[2], FieldElement51([2 * 121666, 0, 0, 0, 0])); + assert_eq!(xs[3], FieldElement51([2 * 121665, 0, 0, 0, 0])); + } + + #[test] + fn diff_sum_vs_serial() { + let x0 = FieldElement51([10000, 10001, 10002, 10003, 10004]); + let x1 = FieldElement51([10100, 10101, 10102, 10103, 10104]); + let x2 = FieldElement51([10200, 10201, 10202, 10203, 10204]); + let x3 = FieldElement51([10300, 10301, 10302, 10303, 10304]); + + let vec = FieldElement2625x4::new(&x0, &x1, &x2, &x3).diff_sum(); + + let result = vec.split(); + + assert_eq!(result[0], &x1 - &x0); + assert_eq!(result[1], &x1 + &x0); + assert_eq!(result[2], &x3 - &x2); + assert_eq!(result[3], &x3 + &x2); + } + + #[test] + fn square_vs_serial() { + let x0 = FieldElement51([10000, 10001, 10002, 10003, 10004]); + let x1 = FieldElement51([10100, 10101, 10102, 10103, 10104]); + let x2 = FieldElement51([10200, 10201, 10202, 10203, 10204]); + let x3 = FieldElement51([10300, 10301, 10302, 10303, 10304]); + + let vec = FieldElement2625x4::new(&x0, &x1, &x2, &x3); + + let result = vec.square_and_negate_D().split(); + + assert_eq!(result[0], &x0 * &x0); + assert_eq!(result[1], &x1 * &x1); + assert_eq!(result[2], &x2 * &x2); + assert_eq!(result[3], -&(&x3 * &x3)); + } + + #[test] + fn multiply_vs_serial() { + let x0 = FieldElement51([10000, 10001, 10002, 10003, 10004]); + let x1 = FieldElement51([10100, 10101, 10102, 10103, 10104]); + let x2 = FieldElement51([10200, 10201, 10202, 10203, 10204]); + let x3 = FieldElement51([10300, 10301, 10302, 10303, 10304]); + + let vec = FieldElement2625x4::new(&x0, &x1, &x2, &x3); + let vecprime = vec.clone(); + + let result = (&vec * &vecprime).split(); + + assert_eq!(result[0], &x0 * &x0); + assert_eq!(result[1], &x1 * &x1); + assert_eq!(result[2], &x2 * &x2); + assert_eq!(result[3], &x3 * &x3); + } + + #[test] + fn test_unpack_repack_pair() { + let x0 = FieldElement51([10000 + (10001 << 26), 0, 0, 0, 0]); + let x1 = FieldElement51([10100 + (10101 << 26), 0, 0, 0, 0]); + let x2 = FieldElement51([10200 + (10201 << 26), 0, 0, 0, 0]); + let x3 = FieldElement51([10300 + (10301 << 26), 0, 0, 0, 0]); + + let vec = FieldElement2625x4::new(&x0, &x1, &x2, &x3); + + let src = vec.0[0]; + + let (a, b) = unpack_pair(src); + + let expected_a = u32x8::new(10000, 0, 10100, 0, 10200, 0, 10300, 0); + let expected_b = u32x8::new(10001, 0, 10101, 0, 10201, 0, 10301, 0); + + assert_eq!(a, expected_a); + assert_eq!(b, expected_b); + + let expected_src = repack_pair(a, b); + + assert_eq!(src, expected_src); + } + + #[test] + fn new_split_roundtrips() { + let x0 = FieldElement51::from_bytes(&[0x10; 32]); + let x1 = FieldElement51::from_bytes(&[0x11; 32]); + let x2 = FieldElement51::from_bytes(&[0x12; 32]); + let x3 = FieldElement51::from_bytes(&[0x13; 32]); + + let vec = FieldElement2625x4::new(&x0, &x1, &x2, &x3); + + let splits = vec.split(); + + assert_eq!(x0, splits[0]); + assert_eq!(x1, splits[1]); + assert_eq!(x2, splits[2]); + assert_eq!(x3, splits[3]); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/mod.rs new file mode 100644 index 0000000..175b7eb --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/avx2/mod.rs @@ -0,0 +1,20 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +#![cfg_attr( + feature = "nightly", + doc(include = "../../../../docs/avx2-notes.md") +)] + +pub(crate) mod field; + +pub(crate) mod edwards; + +pub(crate) mod constants; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/constants.rs new file mode 100644 index 0000000..fd89058 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/constants.rs @@ -0,0 +1,2062 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2018-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +//! This module contains constants used by the IFMA backend. + +use packed_simd::u64x4; + +use window::NafLookupTable8; + +use super::edwards::{CachedPoint, ExtendedPoint}; +use super::field::{F51x4Reduced, F51x4Unreduced}; + +/// The identity element as an `ExtendedPoint`. +pub(crate) static EXTENDEDPOINT_IDENTITY: ExtendedPoint = ExtendedPoint(F51x4Unreduced([ + u64x4::new(0, 1, 1, 0), + u64x4::new(0, 0, 0, 0), + u64x4::new(0, 0, 0, 0), + u64x4::new(0, 0, 0, 0), + u64x4::new(0, 0, 0, 0), +])); + +/// The identity element as a `CachedPoint`. +pub(crate) static CACHEDPOINT_IDENTITY: CachedPoint = CachedPoint(F51x4Reduced([ + u64x4::new(121647, 121666, 243332, 2251799813685229), + u64x4::new(2251799813685248, 0, 0, 2251799813685247), + u64x4::new(2251799813685247, 0, 0, 2251799813685247), + u64x4::new(2251799813685247, 0, 0, 2251799813685247), + u64x4::new(2251799813685247, 0, 0, 2251799813685247), +])); + +/// Odd multiples of the Ed25519 basepoint: +pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = NafLookupTable8([ + CachedPoint(F51x4Reduced([ + u64x4::new(1277522120965857, 73557767439946, 243332, 1943719795065404), + u64x4::new(108375142003455, 341984820733594, 0, 2097709862669256), + u64x4::new(150073485536043, 750646439938056, 0, 581130035634455), + u64x4::new(2149983732744869, 1903255931888577, 0, 646644904824193), + u64x4::new(291045673509296, 1060034214701851, 0, 325245010451737), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1970681836121889, + 1660307753655178, + 1077207637163462, + 1436413309977108, + ), + u64x4::new( + 158785710838757, + 919645875412951, + 174577133496574, + 2213787394009350, + ), + u64x4::new( + 1017606396438281, + 1240932851489554, + 918203302506967, + 1239827708070863, + ), + u64x4::new( + 1748989883612327, + 1745367742532782, + 1168385548387, + 1211387683826673, + ), + u64x4::new( + 799349980018733, + 1471088235739693, + 1505351346057417, + 2104975925096407, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 171437462972293, + 36016853025886, + 1184164975342640, + 1633525003912147, + ), + u64x4::new( + 2113383632509037, + 1946216474924125, + 1884174984466256, + 1373317790955847, + ), + u64x4::new( + 791293623466401, + 1796466048084189, + 444977763198796, + 629823271230872, + ), + u64x4::new( + 1093217720067380, + 2157024270666135, + 238122980108466, + 806820763806847, + ), + u64x4::new( + 793658959468458, + 368578641413741, + 11592529764159, + 2144017075993471, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1538027396670268, + 1588896993892061, + 675619548648376, + 788373514423313, + ), + u64x4::new( + 1987517656073805, + 1940987929951188, + 666993851697339, + 2040540928108427, + ), + u64x4::new( + 375514548584082, + 1726008037083790, + 1070069155000872, + 570111103756303, + ), + u64x4::new( + 772223645372213, + 2123395244967674, + 868238486911408, + 1846639042240362, + ), + u64x4::new( + 872865734460736, + 32277956842850, + 1701451131455402, + 773883376061880, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1845177363882902, + 275858237213625, + 1052127336883600, + 171072805852218, + ), + u64x4::new( + 139016783952609, + 462699304987089, + 430046471494974, + 410922720999257, + ), + u64x4::new( + 846403935976337, + 243817706931454, + 971825428236901, + 571800039596794, + ), + u64x4::new( + 807642685434918, + 1933536976438782, + 812324278898440, + 688391556487313, + ), + u64x4::new( + 76239450396192, + 629532732688863, + 1833302026979779, + 650067934544499, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1373931604989264, + 331159264656614, + 364391529321767, + 874765630865409, + ), + u64x4::new( + 2109908262150241, + 473400816504190, + 91544045127333, + 976307977609515, + ), + u64x4::new( + 330175435673491, + 2126511895885904, + 1022944071588421, + 2158480209801463, + ), + u64x4::new( + 1305666795527971, + 162063591028664, + 2193154870675382, + 1789166662611800, + ), + u64x4::new( + 817858592500508, + 1672743239440202, + 859976879916778, + 1167423340862516, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 274334925170164, + 565841102587251, + 603083835949120, + 607539210240861, + ), + u64x4::new( + 196754662972649, + 1339063476699167, + 1406077076979491, + 896902435668469, + ), + u64x4::new( + 397962210956733, + 174839587476217, + 1381082665748936, + 175195877334136, + ), + u64x4::new( + 717429432748391, + 1635309821746318, + 363374010274647, + 882908746261699, + ), + u64x4::new( + 600946602802781, + 1946596133370711, + 1532135183320341, + 690530671668253, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2074443704000945, + 2163534804938345, + 425423840926528, + 1100826171404853, + ), + u64x4::new( + 111700142796101, + 1456893872751964, + 1186145518682968, + 2192182627706116, + ), + u64x4::new( + 1848722121856066, + 2123239575044749, + 1323870754599272, + 883211262889775, + ), + u64x4::new( + 938263017712916, + 689670293631396, + 183944529557576, + 501908638166580, + ), + u64x4::new( + 2170571907220631, + 36636756989655, + 1875035480138608, + 803703278398018, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1053429956874064, + 1636640618139765, + 1556890827801070, + 2142720579528828, + ), + u64x4::new( + 1814240918422814, + 692326274601777, + 1054896561802157, + 2025454041705534, + ), + u64x4::new( + 2109495823888757, + 1287497869997176, + 194170063200096, + 621116840113213, + ), + u64x4::new( + 2156505873679998, + 2197064359737385, + 1312887672223536, + 369862818895912, + ), + u64x4::new( + 977381163563657, + 1878897311974033, + 2144566861359744, + 1832960882773351, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1266492498289486, + 1301524759372145, + 324789537938521, + 442710471023019, + ), + u64x4::new( + 1232722320001345, + 1191193089162455, + 176474006074813, + 2158950213252857, + ), + u64x4::new( + 1901782191467749, + 494791441598902, + 1820415815322129, + 854954583485223, + ), + u64x4::new( + 1511383667649702, + 792536415032464, + 2027741263854728, + 1727944381044738, + ), + u64x4::new( + 606355788891204, + 1670687521471220, + 582824350365415, + 1509135066079912, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1079942762813598, + 2015830004785901, + 479916361323351, + 1907956590950158, + ), + u64x4::new( + 2053400302939156, + 1319799126867070, + 19493088767391, + 1908755581402373, + ), + u64x4::new( + 2235858054780980, + 885832711204321, + 810332865560178, + 103174191215441, + ), + u64x4::new( + 1843466881032833, + 355511728384038, + 693846715794114, + 186545012724117, + ), + u64x4::new( + 1661758432892509, + 1491022339899281, + 698941123765263, + 174945407208560, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1075933251927831, + 400263885306647, + 1308157532880528, + 347933379126665, + ), + u64x4::new( + 673811632329433, + 1584860147186478, + 271778891257244, + 498194055154207, + ), + u64x4::new( + 703783427747558, + 1051624728592032, + 1371463103351544, + 230351033002960, + ), + u64x4::new( + 860729466483372, + 421647596766583, + 1520613871336707, + 635298775280054, + ), + u64x4::new( + 1168352891728845, + 1691216293752089, + 1799491997061519, + 399728882318504, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 420156727446514, + 1483649215777128, + 165508610199900, + 1918121104840431, + ), + u64x4::new( + 2129902293682427, + 730952770435213, + 2184527544565390, + 1939880362232986, + ), + u64x4::new( + 1771978364905086, + 510975579746524, + 927564335219142, + 177574146260558, + ), + u64x4::new( + 2164104536437514, + 1532598873799015, + 406875369182421, + 1367005937406517, + ), + u64x4::new( + 35073200082587, + 1981124717036219, + 1854087014063833, + 122419694385217, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1963785875777739, + 411497142699119, + 1974557512687408, + 1268304422747183, + ), + u64x4::new( + 762752575978150, + 1443822019541748, + 1331556159904338, + 377726798263780, + ), + u64x4::new( + 825953972847841, + 353487068141356, + 1955697322427207, + 2048226560172078, + ), + u64x4::new( + 1482378558684434, + 657691905625918, + 923870001994493, + 1694132799397736, + ), + u64x4::new( + 1643904759603122, + 170495566698285, + 1218312703413378, + 784318735038131, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 939230507241903, + 2238763473105245, + 1827325199528162, + 1153939339775538, + ), + u64x4::new( + 38544505283339, + 258889431497015, + 351721979677947, + 1357907379592829, + ), + u64x4::new( + 1393974676373341, + 1131355528938676, + 473104915298872, + 978783482501776, + ), + u64x4::new( + 2131516168980501, + 2113911780991092, + 1477027502354261, + 542884524860340, + ), + u64x4::new( + 1029606261349423, + 64226378557628, + 1669131167474348, + 2212808057234874, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1423176501543193, + 163313632579593, + 2220495688893001, + 2220041045291870, + ), + u64x4::new( + 1111834224023697, + 1026815658023689, + 1404605100939775, + 1412149108248227, + ), + u64x4::new( + 1542537854906076, + 1270288391129127, + 991419278941933, + 1824939809581980, + ), + u64x4::new( + 1142003215657891, + 525980550896367, + 1508270666157963, + 917719462309053, + ), + u64x4::new( + 400851268057105, + 1620818232405188, + 1251478578139510, + 2162841805361886, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2125383272208441, + 1368790097335984, + 11813369275978, + 639513785921674, + ), + u64x4::new( + 2200806265616284, + 1041996387620216, + 1275149397833084, + 1723371028064068, + ), + u64x4::new( + 603720163891275, + 2135593511176153, + 2049641644431548, + 1198460677818310, + ), + u64x4::new( + 1862491879401621, + 2008116580769441, + 626566325260235, + 1058308304975798, + ), + u64x4::new( + 628557314314858, + 1075323332046522, + 1631772244117095, + 1812174547405683, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1222773123817104, + 363276129291452, + 796237592807883, + 1914425291893078, + ), + u64x4::new( + 1721259057429088, + 734941709009373, + 1553365830564638, + 1492120931079419, + ), + u64x4::new( + 1009354843273686, + 293884504384873, + 1050281954944357, + 134132942667344, + ), + u64x4::new( + 23119363298711, + 1694754778833445, + 1725925193393496, + 1738396998222001, + ), + u64x4::new( + 1753692057254667, + 118428526447110, + 840961387840295, + 1227619055408558, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1004186117579547, + 508771992330056, + 1426571663072421, + 2238524171903259, + ), + u64x4::new( + 744764613007812, + 398885442368825, + 2047459490294949, + 2141797621077959, + ), + u64x4::new( + 4556204156489, + 1708213022802363, + 1071381560923933, + 393474529142567, + ), + u64x4::new( + 350116198213005, + 945907227204695, + 168267474358731, + 1801504420122711, + ), + u64x4::new( + 728788674520360, + 1262722049156121, + 455259596607008, + 1159442365834489, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2226818917892677, + 185673745808179, + 2240952219732549, + 324137961621908, + ), + u64x4::new( + 1659527641857410, + 973964060249383, + 1349692151487730, + 1172743533370593, + ), + u64x4::new( + 310591478467746, + 2123977244137170, + 774562885265820, + 430035546191685, + ), + u64x4::new( + 2150863173197992, + 2101978317708856, + 193592648406011, + 1375328504508580, + ), + u64x4::new( + 1946235834250479, + 121741431658675, + 1004342690620100, + 2063466488599450, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 463079632200153, + 40415275714025, + 545935352782679, + 1458043501600908, + ), + u64x4::new( + 783771976559993, + 880839641726471, + 1782028201271831, + 41664413404590, + ), + u64x4::new( + 985129151724159, + 187728621410000, + 16620051933318, + 378011085567733, + ), + u64x4::new( + 1820372198168638, + 905710046480679, + 1912961774249737, + 1868135861067161, + ), + u64x4::new( + 474460473983187, + 1455684425673661, + 652771171116843, + 733511920760779, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1088886980746809, + 1660218575261626, + 527921875040240, + 915086639857889, + ), + u64x4::new( + 1814735788528175, + 1586698876186367, + 2040856637532862, + 405684812785624, + ), + u64x4::new( + 658578559700999, + 1751442070931114, + 1293623371490094, + 715026719042518, + ), + u64x4::new( + 382156225644820, + 897982285504960, + 577673183555858, + 1158728558309719, + ), + u64x4::new( + 1865791902475663, + 124491617513788, + 758484125168765, + 734065580770143, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 330985690350617, + 2214424721795630, + 973374650780848, + 1507267060932964, + ), + u64x4::new( + 1733823971011290, + 1730742552292995, + 669018866977489, + 604527664126146, + ), + u64x4::new( + 1082092498645474, + 1029182053935309, + 756799947765834, + 1764720030308351, + ), + u64x4::new( + 969912105693756, + 38116887248276, + 2148030115687613, + 995140534653865, + ), + u64x4::new( + 2154373397460354, + 298128883464656, + 479587543632539, + 1061127201140779, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 843064865526549, + 2019481782959016, + 1873125524281672, + 2013330239022371, + ), + u64x4::new( + 1192932403815186, + 1818108671859220, + 1247005102016258, + 1210577394628058, + ), + u64x4::new( + 132359273326717, + 795492788299178, + 1235924489372816, + 891705064411550, + ), + u64x4::new( + 1425833709104858, + 152114045731085, + 991347902581315, + 1387773338707683, + ), + u64x4::new( + 48024203807922, + 157005564892977, + 1474053161953744, + 727448023498345, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1076621484026788, + 1309917234320927, + 1786998180233659, + 1595497085944737, + ), + u64x4::new( + 1737334672694726, + 2038133716999447, + 1929061192400917, + 620544235219084, + ), + u64x4::new( + 1550527313469747, + 329096759623509, + 1585214659209474, + 693419841748324, + ), + u64x4::new( + 1450010875912315, + 2085047082180569, + 757421110771886, + 389367139787400, + ), + u64x4::new( + 781339490566117, + 132941783448971, + 258650459725225, + 2042274962585613, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 859638991542650, + 2249840007426442, + 1138753070862357, + 793751342318913, + ), + u64x4::new( + 2133476133447306, + 1027010646129239, + 436851910892865, + 866949948830344, + ), + u64x4::new( + 1936003572431223, + 531513680252193, + 1929877059408416, + 830585477662503, + ), + u64x4::new( + 1460760405777960, + 686673748420916, + 275475330051554, + 1581792376993692, + ), + u64x4::new( + 894482039456784, + 1801274480988632, + 16407898635278, + 1668497039215206, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 258585746227669, + 936490904651492, + 1826793887434108, + 1201219990633823, + ), + u64x4::new( + 979462791643635, + 461762372210187, + 218708929991480, + 1378150755760178, + ), + u64x4::new( + 642542170229970, + 787135445552820, + 371168855880557, + 182642566486693, + ), + u64x4::new( + 1152277399721904, + 1726910452705576, + 1452393215705343, + 2117799581546845, + ), + u64x4::new( + 1211265143925330, + 14373046151823, + 1745528818271507, + 1842106288572078, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 635154614562157, + 1956763034454109, + 509123035953043, + 445727657534780, + ), + u64x4::new( + 2072765509783252, + 1282639891593570, + 1075086397362049, + 722996110178195, + ), + u64x4::new( + 1385572918825603, + 1190035835509576, + 218317841176013, + 1047865370756924, + ), + u64x4::new( + 473991569426488, + 1910588123704592, + 1338270051770806, + 401676861680875, + ), + u64x4::new( + 992455353618436, + 126422733426929, + 1955248037756399, + 119233843022643, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1555272991526078, + 2214378187116349, + 366893798097444, + 1401502118355702, + ), + u64x4::new( + 1157229521930713, + 2144787187506262, + 1681597469697840, + 847499096518697, + ), + u64x4::new( + 1872802655800758, + 1027119609820793, + 1137278714788290, + 1664750301179485, + ), + u64x4::new( + 1091289858897030, + 910126419483563, + 1101920147235731, + 597083075893952, + ), + u64x4::new( + 1711011533670315, + 185206680336278, + 1620960612579784, + 1968598849170880, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 73077300235958, + 257216723095630, + 466947267713785, + 847105214181598, + ), + u64x4::new( + 1322905631406309, + 407458059314731, + 230045063190376, + 923800751267786, + ), + u64x4::new( + 1146027205000415, + 1541328763727623, + 768510249199119, + 1630223587589059, + ), + u64x4::new( + 1930368769879433, + 1376145403022159, + 1898149855343131, + 1709421930518180, + ), + u64x4::new( + 633944191571764, + 58314960742839, + 2050971151574988, + 757799756090059, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 361576929158539, + 1035682890165818, + 160945739362874, + 266975208626222, + ), + u64x4::new( + 1635371797076046, + 2106722851965197, + 451585919077206, + 6692426667180, + ), + u64x4::new( + 175820543533852, + 2057511393764025, + 1531846543720469, + 1648320903946519, + ), + u64x4::new( + 947461770620940, + 1107335044817620, + 1725565474111216, + 2182263619949220, + ), + u64x4::new( + 726444888601221, + 1379664085279206, + 1517215633290417, + 1763968936542507, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 686545355846512, + 1712283265573167, + 1743509592736302, + 1653906616429153, + ), + u64x4::new( + 985108805667149, + 2244347650874753, + 1304749057936860, + 321846134330589, + ), + u64x4::new( + 296321076156886, + 1717929256240029, + 450933772486425, + 2015536856431605, + ), + u64x4::new( + 1690393512821866, + 646913049470189, + 2198650647576397, + 1230646705710442, + ), + u64x4::new( + 601961913448442, + 878806578800541, + 620497587492381, + 330716414244629, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 631510982676132, + 1755753187697174, + 1596201246674299, + 2197888384902121, + ), + u64x4::new( + 626957678275745, + 1447583371478595, + 1375375216702128, + 1443613232818823, + ), + u64x4::new( + 1962997804660501, + 1051744123184519, + 1002558639300437, + 1237313314603385, + ), + u64x4::new( + 2118828335274995, + 226398203764759, + 889099617161107, + 1620967117678504, + ), + u64x4::new( + 227261019362935, + 2046897556746842, + 591524060355369, + 2178552047369691, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1375403119051662, + 222313965014452, + 539873444241395, + 213198095917915, + ), + u64x4::new( + 1436952871599114, + 1229749762725246, + 1174441562267670, + 265367077740349, + ), + u64x4::new( + 11107426165917, + 985954476039181, + 1147329112365579, + 1133931640328107, + ), + u64x4::new( + 585235055006843, + 699515259687482, + 299559608721134, + 2134819767146767, + ), + u64x4::new( + 1376401105588528, + 391412107507860, + 302743651807545, + 1362834426455518, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1802940904616205, + 1615132760193234, + 869321663313735, + 666494072545310, + ), + u64x4::new( + 1452849320020701, + 1472716813676364, + 472862999490802, + 359937983286145, + ), + u64x4::new( + 1221198323133843, + 491718521756528, + 1387135774113906, + 793779904904008, + ), + u64x4::new( + 1032129287829151, + 30730741946697, + 217603185195068, + 2118169309744162, + ), + u64x4::new( + 225899335574721, + 1767553399797342, + 881082465669982, + 1435383196392870, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1127093564374276, + 2245188499702906, + 1250041622887441, + 2179324911668149, + ), + u64x4::new( + 908019210866875, + 1879900391060964, + 1355047706206597, + 647218945377302, + ), + u64x4::new( + 1616265604422592, + 2134336781521657, + 1157711219915601, + 1227494173135033, + ), + u64x4::new( + 136450294813355, + 1984543542455033, + 1199486053011083, + 33687889941331, + ), + u64x4::new( + 1053447012707371, + 68239344331930, + 537448158443925, + 1829189783369646, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 996806463322563, + 2043104667851348, + 1110361398300309, + 1218740346887957, + ), + u64x4::new( + 399141907016839, + 1307691109658227, + 532535384961264, + 896201194398872, + ), + u64x4::new( + 111705272106160, + 1790972382466021, + 1159338112559144, + 303544352897203, + ), + u64x4::new( + 1036600573322969, + 1457119922663674, + 334117653665514, + 460023361701263, + ), + u64x4::new( + 1363773215189933, + 1915594049343802, + 1661249423378694, + 1744945551969247, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 3093919631215, + 574886478077610, + 1704446919728971, + 250093147254210, + ), + u64x4::new( + 1387413348737796, + 360142717826981, + 2116185073015983, + 474541388374100, + ), + u64x4::new( + 1632539630892580, + 1332404016215719, + 2145297637794728, + 1289783723173504, + ), + u64x4::new( + 1030244179060173, + 579782698595797, + 1062365251139982, + 677149839815546, + ), + u64x4::new( + 6671539419876, + 1426937459653775, + 406942403696343, + 675479224223817, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 271984148441782, + 1708099625818957, + 1499011822959235, + 516808451044836, + ), + u64x4::new( + 1124847751346323, + 2038336022958449, + 1721698491022600, + 705944403212572, + ), + u64x4::new( + 85459783780275, + 1715213099986669, + 1728445509034791, + 730657630359717, + ), + u64x4::new( + 1185034652652387, + 755472578204310, + 476118360897817, + 1800434542785310, + ), + u64x4::new( + 1815589628676941, + 491778500674079, + 1547664984392513, + 279891608681267, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2036337168672113, + 1730787524684269, + 639134121311693, + 698060925015524, + ), + u64x4::new( + 315211075189491, + 1329055848835358, + 688621136402134, + 1271193060119448, + ), + u64x4::new( + 1697984374314012, + 459330773536457, + 305481314707918, + 61676911066002, + ), + u64x4::new( + 2166631826859191, + 2105217187401781, + 937587962768434, + 357397435365683, + ), + u64x4::new( + 1206757093145471, + 1287847622009294, + 1951336140421622, + 2233789834777410, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 82144190081093, + 1568417433687791, + 907555979158442, + 2037855062523867, + ), + u64x4::new( + 1225315484058853, + 315317868015613, + 1765025920288384, + 175223259828436, + ), + u64x4::new( + 1215010304871271, + 662713408454950, + 429517658575616, + 991062684008811, + ), + u64x4::new( + 993837615254894, + 1485561584889450, + 2001836754226476, + 1915943063896801, + ), + u64x4::new( + 818895101625673, + 1342479472068804, + 1380235330010671, + 23315169761453, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1500726307559118, + 956166860173424, + 512663951564436, + 1940180717699824, + ), + u64x4::new( + 1789521472720825, + 779456898652427, + 2035063615853504, + 863582140589407, + ), + u64x4::new( + 634508890793787, + 1748041666732214, + 259642099961634, + 1294936839797812, + ), + u64x4::new( + 2183334898697038, + 2197242820694806, + 2217225409073703, + 992633998226449, + ), + u64x4::new( + 2197077498155916, + 1562008797791883, + 1395088759904208, + 331715244679294, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 186854731652320, + 284389440026580, + 1252175415119400, + 1025377410100223, + ), + u64x4::new( + 1578732129417607, + 898645497852382, + 2237766074482974, + 1939197790303592, + ), + u64x4::new( + 1438830390640145, + 1682452015845597, + 1108441197232223, + 1984134492898664, + ), + u64x4::new( + 282668727301669, + 1609018289552856, + 390363439795705, + 1138459124667912, + ), + u64x4::new( + 18889015928490, + 532489638086725, + 324621535996080, + 2210046082697453, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2041327051605378, + 2244037852176483, + 2116336876147147, + 9616672544864, + ), + u64x4::new( + 969847387559191, + 1059119127679639, + 1764630094670633, + 364568045311834, + ), + u64x4::new( + 505938893153679, + 2075421412172902, + 326984153045666, + 1959549727324704, + ), + u64x4::new( + 1088715617911260, + 13917085151028, + 950568481355929, + 23687195265771, + ), + u64x4::new( + 1798284568673198, + 808382292203333, + 2214698741961545, + 610817203275867, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1731488929623777, + 1158815615106413, + 1491090861948525, + 1428384712900962, + ), + u64x4::new( + 722237139522457, + 1514290328911535, + 1366197913116230, + 1519472657321210, + ), + u64x4::new( + 246028966932273, + 1888239319448405, + 423720022211163, + 455243905681470, + ), + u64x4::new( + 738323403716001, + 1758018973481179, + 1180718299482318, + 1008495946606708, + ), + u64x4::new( + 334959381596119, + 1704599537529481, + 2172191232106896, + 13502508918495, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 273393076768079, + 427388720298603, + 1071733376018227, + 1715429388968611, + ), + u64x4::new( + 751776629892313, + 1965239102856011, + 541955408230119, + 831043488876080, + ), + u64x4::new( + 643718536393104, + 390543998404644, + 2176730661486279, + 499459234889079, + ), + u64x4::new( + 1482404333915009, + 865527293526285, + 507957951411713, + 216456252558825, + ), + u64x4::new( + 2210281256300231, + 1519357818277551, + 1257866936775246, + 1689605217672864, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2135395168187905, + 2214400157568614, + 2032983817870823, + 1124945109072647, + ), + u64x4::new( + 1602820011758145, + 906675633903289, + 782700735390986, + 2067218823525601, + ), + u64x4::new( + 786785748926382, + 1433583123655616, + 905839404290873, + 2249680349963778, + ), + u64x4::new( + 1940824582370584, + 1610961256326291, + 285307858781375, + 1755588655461194, + ), + u64x4::new( + 233682812055333, + 2146114223476434, + 41132209533476, + 535292431776371, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 600257696476418, + 18449221564824, + 1422209458591138, + 239571584769716, + ), + u64x4::new( + 2056372917056980, + 1155290566623531, + 1252473955568148, + 1276690716882081, + ), + u64x4::new( + 246974369025311, + 658117221519903, + 2000380937898441, + 1351183273924850, + ), + u64x4::new( + 1803747363753112, + 1736801515030186, + 2025633577199091, + 603378480769167, + ), + u64x4::new( + 57348749438551, + 1893551220299655, + 657926732731806, + 1522499384853705, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 591809128842736, + 284860517232591, + 27436696863545, + 886306697195798, + ), + u64x4::new( + 2113192175751749, + 1405882509906423, + 561316282804847, + 835573846576266, + ), + u64x4::new( + 94407289485409, + 1781534171669004, + 2098782516531528, + 598529921520053, + ), + u64x4::new( + 1860137004504786, + 2197323407480349, + 1516772733981532, + 961740253777086, + ), + u64x4::new( + 1484139612868217, + 1593557644636881, + 838834937143441, + 36382198263380, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1165898865828562, + 1153420815042389, + 1068625028915785, + 1945927229911090, + ), + u64x4::new( + 843454394017146, + 571029655293754, + 386282254545998, + 1804608237584150, + ), + u64x4::new( + 370552451091100, + 1279105656351124, + 1864742949668631, + 2093071521726981, + ), + u64x4::new( + 1872542389052198, + 1679083953574330, + 349872262454465, + 1470311090717925, + ), + u64x4::new( + 685345654160323, + 319718985807814, + 1359932285384164, + 1410900103316331, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2083666668832889, + 314624387816655, + 1496694646480345, + 1946728950459189, + ), + u64x4::new( + 1579153761571203, + 508771185291380, + 1002249659402007, + 551517831173801, + ), + u64x4::new( + 2132371471626150, + 1988122278556533, + 1552195130653890, + 1327637750292755, + ), + u64x4::new( + 118937099181527, + 382610380973142, + 634951529106471, + 382740054041699, + ), + u64x4::new( + 801287519643470, + 87822941589258, + 1908825350108451, + 1404208826499115, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 330347226380261, + 672119116965146, + 1761510370768005, + 1959200302484704, + ), + u64x4::new( + 1631876583009250, + 1684917718484264, + 1027256947805920, + 2174612545251129, + ), + u64x4::new( + 636668855699872, + 625187713984839, + 265886954766790, + 167898557908504, + ), + u64x4::new( + 1210974548180860, + 2051308710365526, + 907620584086428, + 1081788677970850, + ), + u64x4::new( + 621792955460854, + 1450945504745382, + 1666728650687828, + 977937146451674, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 24725936182267, + 2226765032752574, + 2036560083102883, + 2002351185719584, + ), + u64x4::new( + 1620080779405308, + 1493220053370419, + 2245691691038916, + 1152182628629603, + ), + u64x4::new( + 317928527147500, + 1855194218440212, + 979380281964169, + 861442286685289, + ), + u64x4::new( + 393308472784625, + 486143087279967, + 1234071346236405, + 777748237119399, + ), + u64x4::new( + 43850412814718, + 1497656407486446, + 744128331046695, + 1618035787321792, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1670169946550211, + 1230951698726438, + 806586940221293, + 23159779184607, + ), + u64x4::new( + 634011340979302, + 764182085034744, + 731065727766955, + 1737985776442180, + ), + u64x4::new( + 240492712141842, + 73976435954441, + 162810587166835, + 697230894340912, + ), + u64x4::new( + 1299745598348388, + 1359436039694544, + 1856609816731554, + 25228008461513, + ), + u64x4::new( + 2180690501932381, + 2161211192848458, + 87069466793408, + 2003456332883860, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1106932458043379, + 1675181364231371, + 1681785724775243, + 131824742557210, + ), + u64x4::new( + 1671649414647169, + 1827849994880670, + 1097958057111899, + 701956891169434, + ), + u64x4::new( + 2095539283710881, + 591029812888096, + 1699571518315654, + 1297589045812566, + ), + u64x4::new( + 1345612272298537, + 2166754730876055, + 2047982622154948, + 1785222806258129, + ), + u64x4::new( + 2181915268829890, + 1895697064378670, + 1288412327355885, + 1561075738281368, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 741330264098392, + 357073519729966, + 1603572339180975, + 433572083688575, + ), + u64x4::new( + 699685108971208, + 1719650727634959, + 1941668009419214, + 870374958347891, + ), + u64x4::new( + 385971389331537, + 11655507719711, + 94814615497633, + 515572102810609, + ), + u64x4::new( + 1396688200590426, + 1518748475144123, + 162386454324368, + 2083303971579002, + ), + u64x4::new( + 1511688632419263, + 251584258592336, + 545345887993880, + 1229840230314160, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1298668855706029, + 2017860934939344, + 2224150456036391, + 1925926576297971, + ), + u64x4::new( + 259522963883544, + 1312469129541229, + 1647530465049600, + 1113737129047154, + ), + u64x4::new( + 733193298663145, + 2115712816303403, + 897628702762311, + 116440277571901, + ), + u64x4::new( + 1998719395229750, + 1662774553684237, + 194395608126452, + 98796702872301, + ), + u64x4::new( + 2226158244229144, + 91961728239158, + 526869903032152, + 849263805316773, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 472779569333556, + 854477760843410, + 2070906720349401, + 734613359834689, + ), + u64x4::new( + 1771897100487404, + 1604024196006064, + 319699348925383, + 437152129592623, + ), + u64x4::new( + 627618365135361, + 1768642666037955, + 588564169143939, + 35295037750744, + ), + u64x4::new( + 220241884231278, + 319104161410840, + 1048165719448798, + 1583931089774347, + ), + u64x4::new( + 166479451884333, + 1623611819962804, + 59990366193679, + 900727256046987, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1944687327687331, + 1328410791053991, + 2083980670913902, + 609396833380574, + ), + u64x4::new( + 1907563845734496, + 1385619047697883, + 869817384774457, + 106642388505109, + ), + u64x4::new( + 1006516581737154, + 1561918369633937, + 1921172883211450, + 2216650451558824, + ), + u64x4::new( + 1780506017391778, + 233064930371847, + 1332962603425752, + 1380075261612354, + ), + u64x4::new( + 1907624789747741, + 1310065402098523, + 1838275780706825, + 884225500782782, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 198729830692545, + 100156148743413, + 2140568641558859, + 2220606475942394, + ), + u64x4::new( + 1108788217903741, + 1706330932366163, + 2050449866410661, + 684907598542847, + ), + u64x4::new( + 1101958322366646, + 659427843062405, + 253899933868173, + 896574852821269, + ), + u64x4::new( + 1157052140740658, + 440541103447032, + 2173354981480949, + 604768603561932, + ), + u64x4::new( + 961238337866054, + 830849154351308, + 1643852412409441, + 1436749321770368, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 784870637473285, + 1180234052037572, + 2086951602998715, + 419328169540373, + ), + u64x4::new( + 1966862397394559, + 788036164772123, + 2024355635709481, + 1471696676696146, + ), + u64x4::new( + 1468884300957205, + 1408016588131185, + 2229595828577885, + 240413942963547, + ), + u64x4::new( + 1481791691942441, + 970648959691160, + 1635500996148197, + 2236917233261585, + ), + u64x4::new( + 31660820731028, + 801794768903647, + 1069092619607344, + 282652554845923, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 911659428682786, + 762502588057038, + 1311399152500807, + 1966922911783311, + ), + u64x4::new( + 1229849228728540, + 258161307933217, + 2140796867375541, + 1569345075547911, + ), + u64x4::new( + 1487354676143742, + 1818317546165791, + 811033554173350, + 1768788663337616, + ), + u64x4::new( + 450017165913234, + 962535873747168, + 2099104262993585, + 503030952485785, + ), + u64x4::new( + 1259958681304518, + 479589250923541, + 1503904042161640, + 706283657294305, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 794562643024291, + 198670993088241, + 1678984629358943, + 273399517554618, + ), + u64x4::new( + 188458991574433, + 1389872130156447, + 1461868931574746, + 795140878721432, + ), + u64x4::new( + 624046647169653, + 630363741191019, + 911018499983500, + 1410140563046579, + ), + u64x4::new( + 1675056174405076, + 632544713589250, + 795454163559811, + 1535271563341780, + ), + u64x4::new( + 25504547444781, + 812510098987855, + 51290042016232, + 1992260991700127, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 269968325452358, + 470932785179706, + 1684444304834150, + 1027482126748243, + ), + u64x4::new( + 457941065342419, + 2117377568137882, + 1209423706730905, + 2192403099717071, + ), + u64x4::new( + 1899046404863678, + 1359500336071762, + 1492389156724726, + 1455627081827750, + ), + u64x4::new( + 2016101061876546, + 1967000012916571, + 582539481696050, + 1197538178790094, + ), + u64x4::new( + 639684852217504, + 1799941252757449, + 1470016556327743, + 846111828965901, + ), + ])), +]); diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/edwards.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/edwards.rs new file mode 100644 index 0000000..5c8d819 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/edwards.rs @@ -0,0 +1,315 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2018-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +#![allow(non_snake_case)] + +use traits::Identity; + +use std::ops::{Add, Neg, Sub}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use edwards; +use window::{LookupTable, NafLookupTable5, NafLookupTable8}; + +use super::constants; +use super::field::{F51x4Reduced, F51x4Unreduced, Lanes, Shuffle}; + +#[derive(Copy, Clone, Debug)] +pub struct ExtendedPoint(pub(super) F51x4Unreduced); + +#[derive(Copy, Clone, Debug)] +pub struct CachedPoint(pub(super) F51x4Reduced); + +impl From for ExtendedPoint { + fn from(P: edwards::EdwardsPoint) -> ExtendedPoint { + ExtendedPoint(F51x4Unreduced::new(&P.X, &P.Y, &P.Z, &P.T)) + } +} + +impl From for edwards::EdwardsPoint { + fn from(P: ExtendedPoint) -> edwards::EdwardsPoint { + let reduced = F51x4Reduced::from(P.0); + let tmp = F51x4Unreduced::from(reduced).split(); + edwards::EdwardsPoint { + X: tmp[0], + Y: tmp[1], + Z: tmp[2], + T: tmp[3], + } + } +} + +impl From for CachedPoint { + fn from(P: ExtendedPoint) -> CachedPoint { + let mut x = P.0; + + x = x.blend(&x.diff_sum(), Lanes::AB); + x = &F51x4Reduced::from(x) * (121666, 121666, 2 * 121666, 2 * 121665); + x = x.blend(&x.negate_lazy(), Lanes::D); + + CachedPoint(F51x4Reduced::from(x)) + } +} + +impl Default for ExtendedPoint { + fn default() -> ExtendedPoint { + ExtendedPoint::identity() + } +} + +impl Identity for ExtendedPoint { + fn identity() -> ExtendedPoint { + constants::EXTENDEDPOINT_IDENTITY + } +} + +impl ExtendedPoint { + pub fn double(&self) -> ExtendedPoint { + // (Y1 X1 T1 Z1) -- uses vpshufd (1c latency @ 1/c) + let mut tmp0 = self.0.shuffle(Shuffle::BADC); + + // (X1+Y1 X1+Y1 X1+Y1 X1+Y1) -- can use vpinserti128 + let mut tmp1 = (self.0 + tmp0).shuffle(Shuffle::ABAB); + + // (X1 Y1 Z1 X1+Y1) + tmp0 = self.0.blend(&tmp1, Lanes::D); + + tmp1 = F51x4Reduced::from(tmp0).square(); + // Now tmp1 = (S1 S2 S3 S4) + + // We want to compute + // + // + | S1 | S1 | S1 | S1 | + // + | S2 | | | S2 | + // + | | | S3 | | + // + | | | S3 | | + // + | |16p |16p |16p | + // - | | S2 | S2 | | + // - | | | | S4 | + // ======================= + // S5 S6 S8 S9 + + let zero = F51x4Unreduced::zero(); + + let S1_S1_S1_S1 = tmp1.shuffle(Shuffle::AAAA); + let S2_S2_S2_S2 = tmp1.shuffle(Shuffle::BBBB); + + let S2_S2_S2_S4 = S2_S2_S2_S2.blend(&tmp1, Lanes::D).negate_lazy(); + + tmp0 = S1_S1_S1_S1 + zero.blend(&(tmp1 + tmp1), Lanes::C); + tmp0 = tmp0 + zero.blend(&S2_S2_S2_S2, Lanes::AD); + tmp0 = tmp0 + zero.blend(&S2_S2_S2_S4, Lanes::BCD); + + let tmp2 = F51x4Reduced::from(tmp0); + + ExtendedPoint(&tmp2.shuffle(Shuffle::DBBD) * &tmp2.shuffle(Shuffle::CACA)) + } + + pub fn mul_by_pow_2(&self, k: u32) -> ExtendedPoint { + let mut tmp: ExtendedPoint = *self; + for _ in 0..k { + tmp = tmp.double(); + } + tmp + } +} + +impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { + type Output = ExtendedPoint; + + /// Add an `ExtendedPoint` and a `CachedPoint`. + fn add(self, other: &'b CachedPoint) -> ExtendedPoint { + let mut tmp = self.0; + + tmp = tmp.blend(&tmp.diff_sum(), Lanes::AB); + // tmp = (Y1-X1 Y1+X1 Z1 T1) = (S0 S1 Z1 T1) + + tmp = &F51x4Reduced::from(tmp) * &other.0; + // tmp = (S0*S2' S1*S3' Z1*Z2' T1*T2') = (S8 S9 S10 S11) + + tmp = tmp.shuffle(Shuffle::ABDC); + // tmp = (S8 S9 S11 S10) + + let tmp = F51x4Reduced::from(tmp.diff_sum()); + // tmp = (S9-S8 S9+S8 S10-S11 S10+S11) = (S12 S13 S14 S15) + + let t0 = tmp.shuffle(Shuffle::ADDA); + // t0 = (S12 S15 S15 S12) + let t1 = tmp.shuffle(Shuffle::CBCB); + // t1 = (S14 S13 S14 S13) + + // Return (S12*S14 S15*S13 S15*S14 S12*S13) = (X3 Y3 Z3 T3) + ExtendedPoint(&t0 * &t1) + } +} + +impl Default for CachedPoint { + fn default() -> CachedPoint { + CachedPoint::identity() + } +} + +impl Identity for CachedPoint { + fn identity() -> CachedPoint { + constants::CACHEDPOINT_IDENTITY + } +} + +impl ConditionallySelectable for CachedPoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + CachedPoint(F51x4Reduced::conditional_select(&a.0, &b.0, choice)) + } + + fn conditional_assign(&mut self, other: &Self, choice: Choice) { + self.0.conditional_assign(&other.0, choice); + } +} + +impl<'a> Neg for &'a CachedPoint { + type Output = CachedPoint; + + fn neg(self) -> CachedPoint { + let swapped = self.0.shuffle(Shuffle::BACD); + CachedPoint(swapped.blend(&(-self.0), Lanes::D)) + } +} + +impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { + type Output = ExtendedPoint; + + /// Implement subtraction by negating the point and adding. + fn sub(self, other: &'b CachedPoint) -> ExtendedPoint { + self + &(-other) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let P = ExtendedPoint::from(*point); + let mut points = [CachedPoint::from(P); 8]; + for i in 0..7 { + points[i + 1] = (&P + &points[i]).into(); + } + LookupTable(points) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let A = ExtendedPoint::from(*point); + let mut Ai = [CachedPoint::from(A); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).into(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + NafLookupTable5(Ai) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let A = ExtendedPoint::from(*point); + let mut Ai = [CachedPoint::from(A); 64]; + let A2 = A.double(); + for i in 0..63 { + Ai[i + 1] = (&A2 + &Ai[i]).into(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] + NafLookupTable8(Ai) + } +} + +#[cfg(test)] +mod test { + use super::*; + + fn addition_test_helper(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) { + // Test the serial implementation of the parallel addition formulas + //let R_serial: edwards::EdwardsPoint = serial_add(P.into(), Q.into()).into(); + + // Test the vector implementation of the parallel readdition formulas + let cached_Q = CachedPoint::from(ExtendedPoint::from(Q)); + let R_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) + &cached_Q).into(); + let S_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) - &cached_Q).into(); + + println!("Testing point addition:"); + println!("P = {:?}", P); + println!("Q = {:?}", Q); + println!("cached Q = {:?}", cached_Q); + println!("R = P + Q = {:?}", &P + &Q); + //println!("R_serial = {:?}", R_serial); + println!("R_vector = {:?}", R_vector); + println!("S = P - Q = {:?}", &P - &Q); + println!("S_vector = {:?}", S_vector); + //assert_eq!(R_serial.compress(), (&P + &Q).compress()); + assert_eq!(R_vector.compress(), (&P + &Q).compress()); + assert_eq!(S_vector.compress(), (&P - &Q).compress()); + println!("OK!\n"); + } + + #[test] + fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() { + use constants; + use scalar::Scalar; + + println!("Testing id +- id"); + let P = edwards::EdwardsPoint::identity(); + let Q = edwards::EdwardsPoint::identity(); + addition_test_helper(P, Q); + + println!("Testing id +- B"); + let P = edwards::EdwardsPoint::identity(); + let Q = constants::ED25519_BASEPOINT_POINT; + addition_test_helper(P, Q); + + println!("Testing B +- B"); + let P = constants::ED25519_BASEPOINT_POINT; + let Q = constants::ED25519_BASEPOINT_POINT; + addition_test_helper(P, Q); + + println!("Testing B +- kB"); + let P = constants::ED25519_BASEPOINT_POINT; + let Q = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + addition_test_helper(P, Q); + } + + fn doubling_test_helper(P: edwards::EdwardsPoint) { + //let R1: edwards::EdwardsPoint = serial_double(P.into()).into(); + let R2: edwards::EdwardsPoint = ExtendedPoint::from(P).double().into(); + println!("Testing point doubling:"); + println!("P = {:?}", P); + //println!("(serial) R1 = {:?}", R1); + println!("(vector) R2 = {:?}", R2); + println!("P + P = {:?}", &P + &P); + //assert_eq!(R1.compress(), (&P + &P).compress()); + assert_eq!(R2.compress(), (&P + &P).compress()); + println!("OK!\n"); + } + + #[test] + fn vector_doubling_vs_serial_doubling_vs_edwards_extendedpoint() { + use constants; + use scalar::Scalar; + + println!("Testing [2]id"); + let P = edwards::EdwardsPoint::identity(); + doubling_test_helper(P); + + println!("Testing [2]B"); + let P = constants::ED25519_BASEPOINT_POINT; + doubling_test_helper(P); + + println!("Testing [2]([k]B)"); + let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + doubling_test_helper(P); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/field.rs new file mode 100644 index 0000000..5b7c092 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/field.rs @@ -0,0 +1,824 @@ +// -*- mode: rust; coding: utf-8; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2018-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +#![allow(non_snake_case)] + +use core::ops::{Add, Mul, Neg}; +use packed_simd::{u64x4, IntoBits}; + +use backend::serial::u64::field::FieldElement51; + +/// A wrapper around `vpmadd52luq` that works on `u64x4`. +#[inline(always)] +unsafe fn madd52lo(z: u64x4, x: u64x4, y: u64x4) -> u64x4 { + use core::arch::x86_64::_mm256_madd52lo_epu64; + _mm256_madd52lo_epu64(z.into_bits(), x.into_bits(), y.into_bits()).into_bits() +} + +/// A wrapper around `vpmadd52huq` that works on `u64x4`. +#[inline(always)] +unsafe fn madd52hi(z: u64x4, x: u64x4, y: u64x4) -> u64x4 { + use core::arch::x86_64::_mm256_madd52hi_epu64; + _mm256_madd52hi_epu64(z.into_bits(), x.into_bits(), y.into_bits()).into_bits() +} + +/// A vector of four field elements in radix 2^51, with unreduced coefficients. +#[derive(Copy, Clone, Debug)] +pub struct F51x4Unreduced(pub(crate) [u64x4; 5]); + +/// A vector of four field elements in radix 2^51, with reduced coefficients. +#[derive(Copy, Clone, Debug)] +pub struct F51x4Reduced(pub(crate) [u64x4; 5]); + +#[derive(Copy, Clone)] +pub enum Shuffle { + AAAA, + BBBB, + BADC, + BACD, + ADDA, + CBCB, + ABDC, + ABAB, + DBBD, + CACA, +} + +#[inline(always)] +fn shuffle_lanes(x: u64x4, control: Shuffle) -> u64x4 { + unsafe { + use core::arch::x86_64::_mm256_permute4x64_epi64 as perm; + + match control { + Shuffle::AAAA => perm(x.into_bits(), 0b00_00_00_00).into_bits(), + Shuffle::BBBB => perm(x.into_bits(), 0b01_01_01_01).into_bits(), + Shuffle::BADC => perm(x.into_bits(), 0b10_11_00_01).into_bits(), + Shuffle::BACD => perm(x.into_bits(), 0b11_10_00_01).into_bits(), + Shuffle::ADDA => perm(x.into_bits(), 0b00_11_11_00).into_bits(), + Shuffle::CBCB => perm(x.into_bits(), 0b01_10_01_10).into_bits(), + Shuffle::ABDC => perm(x.into_bits(), 0b10_11_01_00).into_bits(), + Shuffle::ABAB => perm(x.into_bits(), 0b01_00_01_00).into_bits(), + Shuffle::DBBD => perm(x.into_bits(), 0b11_01_01_11).into_bits(), + Shuffle::CACA => perm(x.into_bits(), 0b00_10_00_10).into_bits(), + } + } +} + +#[derive(Copy, Clone)] +pub enum Lanes { + D, + C, + AB, + AC, + AD, + BCD, +} + +#[inline] +fn blend_lanes(x: u64x4, y: u64x4, control: Lanes) -> u64x4 { + unsafe { + use core::arch::x86_64::_mm256_blend_epi32 as blend; + + match control { + Lanes::D => blend(x.into_bits(), y.into_bits(), 0b11_00_00_00).into_bits(), + Lanes::C => blend(x.into_bits(), y.into_bits(), 0b00_11_00_00).into_bits(), + Lanes::AB => blend(x.into_bits(), y.into_bits(), 0b00_00_11_11).into_bits(), + Lanes::AC => blend(x.into_bits(), y.into_bits(), 0b00_11_00_11).into_bits(), + Lanes::AD => blend(x.into_bits(), y.into_bits(), 0b11_00_00_11).into_bits(), + Lanes::BCD => blend(x.into_bits(), y.into_bits(), 0b11_11_11_00).into_bits(), + } + } +} + +impl F51x4Unreduced { + pub fn zero() -> F51x4Unreduced { + F51x4Unreduced([u64x4::splat(0); 5]) + } + + pub fn new( + x0: &FieldElement51, + x1: &FieldElement51, + x2: &FieldElement51, + x3: &FieldElement51, + ) -> F51x4Unreduced { + F51x4Unreduced([ + u64x4::new(x0.0[0], x1.0[0], x2.0[0], x3.0[0]), + u64x4::new(x0.0[1], x1.0[1], x2.0[1], x3.0[1]), + u64x4::new(x0.0[2], x1.0[2], x2.0[2], x3.0[2]), + u64x4::new(x0.0[3], x1.0[3], x2.0[3], x3.0[3]), + u64x4::new(x0.0[4], x1.0[4], x2.0[4], x3.0[4]), + ]) + } + + pub fn split(&self) -> [FieldElement51; 4] { + let x = &self.0; + [ + FieldElement51([ + x[0].extract(0), + x[1].extract(0), + x[2].extract(0), + x[3].extract(0), + x[4].extract(0), + ]), + FieldElement51([ + x[0].extract(1), + x[1].extract(1), + x[2].extract(1), + x[3].extract(1), + x[4].extract(1), + ]), + FieldElement51([ + x[0].extract(2), + x[1].extract(2), + x[2].extract(2), + x[3].extract(2), + x[4].extract(2), + ]), + FieldElement51([ + x[0].extract(3), + x[1].extract(3), + x[2].extract(3), + x[3].extract(3), + x[4].extract(3), + ]), + ] + } + + #[inline] + pub fn diff_sum(&self) -> F51x4Unreduced { + // tmp1 = (B, A, D, C) + let tmp1 = self.shuffle(Shuffle::BADC); + // tmp2 = (-A, B, -C, D) + let tmp2 = self.blend(&self.negate_lazy(), Lanes::AC); + // (B - A, B + A, D - C, D + C) + tmp1 + tmp2 + } + + #[inline] + pub fn negate_lazy(&self) -> F51x4Unreduced { + let lo = u64x4::splat(36028797018963664u64); + let hi = u64x4::splat(36028797018963952u64); + F51x4Unreduced([ + lo - self.0[0], + hi - self.0[1], + hi - self.0[2], + hi - self.0[3], + hi - self.0[4], + ]) + } + + #[inline] + pub fn shuffle(&self, control: Shuffle) -> F51x4Unreduced { + F51x4Unreduced([ + shuffle_lanes(self.0[0], control), + shuffle_lanes(self.0[1], control), + shuffle_lanes(self.0[2], control), + shuffle_lanes(self.0[3], control), + shuffle_lanes(self.0[4], control), + ]) + } + + #[inline] + pub fn blend(&self, other: &F51x4Unreduced, control: Lanes) -> F51x4Unreduced { + F51x4Unreduced([ + blend_lanes(self.0[0], other.0[0], control), + blend_lanes(self.0[1], other.0[1], control), + blend_lanes(self.0[2], other.0[2], control), + blend_lanes(self.0[3], other.0[3], control), + blend_lanes(self.0[4], other.0[4], control), + ]) + } +} + +impl Neg for F51x4Reduced { + type Output = F51x4Reduced; + + fn neg(self) -> F51x4Reduced { + F51x4Unreduced::from(self).negate_lazy().into() + } +} + +use subtle::Choice; +use subtle::ConditionallySelectable; + +impl ConditionallySelectable for F51x4Reduced { + #[inline] + fn conditional_select(a: &F51x4Reduced, b: &F51x4Reduced, choice: Choice) -> F51x4Reduced { + let mask = (-(choice.unwrap_u8() as i64)) as u64; + let mask_vec = u64x4::splat(mask); + F51x4Reduced([ + a.0[0] ^ (mask_vec & (a.0[0] ^ b.0[0])), + a.0[1] ^ (mask_vec & (a.0[1] ^ b.0[1])), + a.0[2] ^ (mask_vec & (a.0[2] ^ b.0[2])), + a.0[3] ^ (mask_vec & (a.0[3] ^ b.0[3])), + a.0[4] ^ (mask_vec & (a.0[4] ^ b.0[4])), + ]) + } + + #[inline] + fn conditional_assign(&mut self, other: &F51x4Reduced, choice: Choice) { + let mask = (-(choice.unwrap_u8() as i64)) as u64; + let mask_vec = u64x4::splat(mask); + self.0[0] ^= mask_vec & (self.0[0] ^ other.0[0]); + self.0[1] ^= mask_vec & (self.0[1] ^ other.0[1]); + self.0[2] ^= mask_vec & (self.0[2] ^ other.0[2]); + self.0[3] ^= mask_vec & (self.0[3] ^ other.0[3]); + self.0[4] ^= mask_vec & (self.0[4] ^ other.0[4]); + } +} + +impl F51x4Reduced { + #[inline] + pub fn shuffle(&self, control: Shuffle) -> F51x4Reduced { + F51x4Reduced([ + shuffle_lanes(self.0[0], control), + shuffle_lanes(self.0[1], control), + shuffle_lanes(self.0[2], control), + shuffle_lanes(self.0[3], control), + shuffle_lanes(self.0[4], control), + ]) + } + + #[inline] + pub fn blend(&self, other: &F51x4Reduced, control: Lanes) -> F51x4Reduced { + F51x4Reduced([ + blend_lanes(self.0[0], other.0[0], control), + blend_lanes(self.0[1], other.0[1], control), + blend_lanes(self.0[2], other.0[2], control), + blend_lanes(self.0[3], other.0[3], control), + blend_lanes(self.0[4], other.0[4], control), + ]) + } + + #[inline] + pub fn square(&self) -> F51x4Unreduced { + unsafe { + let x = &self.0; + + // Represent values with coeff. 2 + let mut z0_2 = u64x4::splat(0); + let mut z1_2 = u64x4::splat(0); + let mut z2_2 = u64x4::splat(0); + let mut z3_2 = u64x4::splat(0); + let mut z4_2 = u64x4::splat(0); + let mut z5_2 = u64x4::splat(0); + let mut z6_2 = u64x4::splat(0); + let mut z7_2 = u64x4::splat(0); + let mut z9_2 = u64x4::splat(0); + + // Represent values with coeff. 4 + let mut z2_4 = u64x4::splat(0); + let mut z3_4 = u64x4::splat(0); + let mut z4_4 = u64x4::splat(0); + let mut z5_4 = u64x4::splat(0); + let mut z6_4 = u64x4::splat(0); + let mut z7_4 = u64x4::splat(0); + let mut z8_4 = u64x4::splat(0); + + let mut z0_1 = u64x4::splat(0); + z0_1 = madd52lo(z0_1, x[0], x[0]); + + let mut z1_1 = u64x4::splat(0); + z1_2 = madd52lo(z1_2, x[0], x[1]); + z1_2 = madd52hi(z1_2, x[0], x[0]); + + z2_4 = madd52hi(z2_4, x[0], x[1]); + let mut z2_1 = z2_4 << 2; + z2_2 = madd52lo(z2_2, x[0], x[2]); + z2_1 = madd52lo(z2_1, x[1], x[1]); + + z3_4 = madd52hi(z3_4, x[0], x[2]); + let mut z3_1 = z3_4 << 2; + z3_2 = madd52lo(z3_2, x[1], x[2]); + z3_2 = madd52lo(z3_2, x[0], x[3]); + z3_2 = madd52hi(z3_2, x[1], x[1]); + + z4_4 = madd52hi(z4_4, x[1], x[2]); + z4_4 = madd52hi(z4_4, x[0], x[3]); + let mut z4_1 = z4_4 << 2; + z4_2 = madd52lo(z4_2, x[1], x[3]); + z4_2 = madd52lo(z4_2, x[0], x[4]); + z4_1 = madd52lo(z4_1, x[2], x[2]); + + z5_4 = madd52hi(z5_4, x[1], x[3]); + z5_4 = madd52hi(z5_4, x[0], x[4]); + let mut z5_1 = z5_4 << 2; + z5_2 = madd52lo(z5_2, x[2], x[3]); + z5_2 = madd52lo(z5_2, x[1], x[4]); + z5_2 = madd52hi(z5_2, x[2], x[2]); + + z6_4 = madd52hi(z6_4, x[2], x[3]); + z6_4 = madd52hi(z6_4, x[1], x[4]); + let mut z6_1 = z6_4 << 2; + z6_2 = madd52lo(z6_2, x[2], x[4]); + z6_1 = madd52lo(z6_1, x[3], x[3]); + + z7_4 = madd52hi(z7_4, x[2], x[4]); + let mut z7_1 = z7_4 << 2; + z7_2 = madd52lo(z7_2, x[3], x[4]); + z7_2 = madd52hi(z7_2, x[3], x[3]); + + z8_4 = madd52hi(z8_4, x[3], x[4]); + let mut z8_1 = z8_4 << 2; + z8_1 = madd52lo(z8_1, x[4], x[4]); + + let mut z9_1 = u64x4::splat(0); + z9_2 = madd52hi(z9_2, x[4], x[4]); + + z5_1 += z5_2 << 1; + z6_1 += z6_2 << 1; + z7_1 += z7_2 << 1; + z9_1 += z9_2 << 1; + + let mut t0 = u64x4::splat(0); + let mut t1 = u64x4::splat(0); + let r19 = u64x4::splat(19); + + t0 = madd52hi(t0, r19, z9_1); + t1 = madd52lo(t1, r19, z9_1 >> 52); + + z4_2 = madd52lo(z4_2, r19, z8_1 >> 52); + z3_2 = madd52lo(z3_2, r19, z7_1 >> 52); + z2_2 = madd52lo(z2_2, r19, z6_1 >> 52); + z1_2 = madd52lo(z1_2, r19, z5_1 >> 52); + + z0_2 = madd52lo(z0_2, r19, t0 + t1); + z1_2 = madd52hi(z1_2, r19, z5_1); + z2_2 = madd52hi(z2_2, r19, z6_1); + z3_2 = madd52hi(z3_2, r19, z7_1); + z4_2 = madd52hi(z4_2, r19, z8_1); + + z0_1 = madd52lo(z0_1, r19, z5_1); + z1_1 = madd52lo(z1_1, r19, z6_1); + z2_1 = madd52lo(z2_1, r19, z7_1); + z3_1 = madd52lo(z3_1, r19, z8_1); + z4_1 = madd52lo(z4_1, r19, z9_1); + + F51x4Unreduced([ + z0_1 + z0_2 + z0_2, + z1_1 + z1_2 + z1_2, + z2_1 + z2_2 + z2_2, + z3_1 + z3_2 + z3_2, + z4_1 + z4_2 + z4_2, + ]) + } + } +} + +impl From for F51x4Unreduced { + #[inline] + fn from(x: F51x4Reduced) -> F51x4Unreduced { + F51x4Unreduced(x.0) + } +} + +impl From for F51x4Reduced { + #[inline] + fn from(x: F51x4Unreduced) -> F51x4Reduced { + let mask = u64x4::splat((1 << 51) - 1); + let r19 = u64x4::splat(19); + + // Compute carryouts in parallel + let c0 = x.0[0] >> 51; + let c1 = x.0[1] >> 51; + let c2 = x.0[2] >> 51; + let c3 = x.0[3] >> 51; + let c4 = x.0[4] >> 51; + + unsafe { + F51x4Reduced([ + madd52lo(x.0[0] & mask, c4, r19), + (x.0[1] & mask) + c0, + (x.0[2] & mask) + c1, + (x.0[3] & mask) + c2, + (x.0[4] & mask) + c3, + ]) + } + } +} + +impl Add for F51x4Unreduced { + type Output = F51x4Unreduced; + #[inline] + fn add(self, rhs: F51x4Unreduced) -> F51x4Unreduced { + F51x4Unreduced([ + self.0[0] + rhs.0[0], + self.0[1] + rhs.0[1], + self.0[2] + rhs.0[2], + self.0[3] + rhs.0[3], + self.0[4] + rhs.0[4], + ]) + } +} + +impl<'a> Mul<(u32, u32, u32, u32)> for &'a F51x4Reduced { + type Output = F51x4Unreduced; + #[inline] + fn mul(self, scalars: (u32, u32, u32, u32)) -> F51x4Unreduced { + unsafe { + let x = &self.0; + let y = u64x4::new( + scalars.0 as u64, + scalars.1 as u64, + scalars.2 as u64, + scalars.3 as u64, + ); + let r19 = u64x4::splat(19); + + let mut z0_1 = u64x4::splat(0); + let mut z1_1 = u64x4::splat(0); + let mut z2_1 = u64x4::splat(0); + let mut z3_1 = u64x4::splat(0); + let mut z4_1 = u64x4::splat(0); + let mut z1_2 = u64x4::splat(0); + let mut z2_2 = u64x4::splat(0); + let mut z3_2 = u64x4::splat(0); + let mut z4_2 = u64x4::splat(0); + let mut z5_2 = u64x4::splat(0); + + // Wave 0 + z4_2 = madd52hi(z4_2, y, x[3]); + z5_2 = madd52hi(z5_2, y, x[4]); + z4_1 = madd52lo(z4_1, y, x[4]); + z0_1 = madd52lo(z0_1, y, x[0]); + z3_1 = madd52lo(z3_1, y, x[3]); + z2_1 = madd52lo(z2_1, y, x[2]); + z1_1 = madd52lo(z1_1, y, x[1]); + z3_2 = madd52hi(z3_2, y, x[2]); + + // Wave 2 + z2_2 = madd52hi(z2_2, y, x[1]); + z1_2 = madd52hi(z1_2, y, x[0]); + z0_1 = madd52lo(z0_1, z5_2 + z5_2, r19); + + F51x4Unreduced([ + z0_1, + z1_1 + z1_2 + z1_2, + z2_1 + z2_2 + z2_2, + z3_1 + z3_2 + z3_2, + z4_1 + z4_2 + z4_2, + ]) + } + } +} + +impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced { + type Output = F51x4Unreduced; + #[inline] + fn mul(self, rhs: &'b F51x4Reduced) -> F51x4Unreduced { + unsafe { + // Inputs + let x = &self.0; + let y = &rhs.0; + + // Accumulators for terms with coeff 1 + let mut z0_1 = u64x4::splat(0); + let mut z1_1 = u64x4::splat(0); + let mut z2_1 = u64x4::splat(0); + let mut z3_1 = u64x4::splat(0); + let mut z4_1 = u64x4::splat(0); + let mut z5_1 = u64x4::splat(0); + let mut z6_1 = u64x4::splat(0); + let mut z7_1 = u64x4::splat(0); + let mut z8_1 = u64x4::splat(0); + + // Accumulators for terms with coeff 2 + let mut z0_2 = u64x4::splat(0); + let mut z1_2 = u64x4::splat(0); + let mut z2_2 = u64x4::splat(0); + let mut z3_2 = u64x4::splat(0); + let mut z4_2 = u64x4::splat(0); + let mut z5_2 = u64x4::splat(0); + let mut z6_2 = u64x4::splat(0); + let mut z7_2 = u64x4::splat(0); + let mut z8_2 = u64x4::splat(0); + let mut z9_2 = u64x4::splat(0); + + // LLVM doesn't seem to do much work reordering IFMA + // instructions, so try to organize them into "waves" of 8 + // independent operations (4c latency, 0.5 c throughput + // means 8 in flight) + + // Wave 0 + z4_1 = madd52lo(z4_1, x[2], y[2]); + z5_2 = madd52hi(z5_2, x[2], y[2]); + z5_1 = madd52lo(z5_1, x[4], y[1]); + z6_2 = madd52hi(z6_2, x[4], y[1]); + z6_1 = madd52lo(z6_1, x[4], y[2]); + z7_2 = madd52hi(z7_2, x[4], y[2]); + z7_1 = madd52lo(z7_1, x[4], y[3]); + z8_2 = madd52hi(z8_2, x[4], y[3]); + + // Wave 1 + z4_1 = madd52lo(z4_1, x[3], y[1]); + z5_2 = madd52hi(z5_2, x[3], y[1]); + z5_1 = madd52lo(z5_1, x[3], y[2]); + z6_2 = madd52hi(z6_2, x[3], y[2]); + z6_1 = madd52lo(z6_1, x[3], y[3]); + z7_2 = madd52hi(z7_2, x[3], y[3]); + z7_1 = madd52lo(z7_1, x[3], y[4]); + z8_2 = madd52hi(z8_2, x[3], y[4]); + + // Wave 2 + z8_1 = madd52lo(z8_1, x[4], y[4]); + z9_2 = madd52hi(z9_2, x[4], y[4]); + z4_1 = madd52lo(z4_1, x[4], y[0]); + z5_2 = madd52hi(z5_2, x[4], y[0]); + z5_1 = madd52lo(z5_1, x[2], y[3]); + z6_2 = madd52hi(z6_2, x[2], y[3]); + z6_1 = madd52lo(z6_1, x[2], y[4]); + z7_2 = madd52hi(z7_2, x[2], y[4]); + + let z8 = z8_1 + z8_2 + z8_2; + let z9 = z9_2 + z9_2; + + // Wave 3 + z3_1 = madd52lo(z3_1, x[3], y[0]); + z4_2 = madd52hi(z4_2, x[3], y[0]); + z4_1 = madd52lo(z4_1, x[1], y[3]); + z5_2 = madd52hi(z5_2, x[1], y[3]); + z5_1 = madd52lo(z5_1, x[1], y[4]); + z6_2 = madd52hi(z6_2, x[1], y[4]); + z2_1 = madd52lo(z2_1, x[2], y[0]); + z3_2 = madd52hi(z3_2, x[2], y[0]); + + let z6 = z6_1 + z6_2 + z6_2; + let z7 = z7_1 + z7_2 + z7_2; + + // Wave 4 + z3_1 = madd52lo(z3_1, x[2], y[1]); + z4_2 = madd52hi(z4_2, x[2], y[1]); + z4_1 = madd52lo(z4_1, x[0], y[4]); + z5_2 = madd52hi(z5_2, x[0], y[4]); + z1_1 = madd52lo(z1_1, x[1], y[0]); + z2_2 = madd52hi(z2_2, x[1], y[0]); + z2_1 = madd52lo(z2_1, x[1], y[1]); + z3_2 = madd52hi(z3_2, x[1], y[1]); + + let z5 = z5_1 + z5_2 + z5_2; + + // Wave 5 + z3_1 = madd52lo(z3_1, x[1], y[2]); + z4_2 = madd52hi(z4_2, x[1], y[2]); + z0_1 = madd52lo(z0_1, x[0], y[0]); + z1_2 = madd52hi(z1_2, x[0], y[0]); + z1_1 = madd52lo(z1_1, x[0], y[1]); + z2_1 = madd52lo(z2_1, x[0], y[2]); + z2_2 = madd52hi(z2_2, x[0], y[1]); + z3_2 = madd52hi(z3_2, x[0], y[2]); + + let mut t0 = u64x4::splat(0); + let mut t1 = u64x4::splat(0); + let r19 = u64x4::splat(19); + + // Wave 6 + t0 = madd52hi(t0, r19, z9); + t1 = madd52lo(t1, r19, z9 >> 52); + z3_1 = madd52lo(z3_1, x[0], y[3]); + z4_2 = madd52hi(z4_2, x[0], y[3]); + z1_2 = madd52lo(z1_2, r19, z5 >> 52); + z2_2 = madd52lo(z2_2, r19, z6 >> 52); + z3_2 = madd52lo(z3_2, r19, z7 >> 52); + z0_1 = madd52lo(z0_1, r19, z5); + + // Wave 7 + z4_1 = madd52lo(z4_1, r19, z9); + z1_1 = madd52lo(z1_1, r19, z6); + z0_2 = madd52lo(z0_2, r19, t0 + t1); + z4_2 = madd52hi(z4_2, r19, z8); + z2_1 = madd52lo(z2_1, r19, z7); + z1_2 = madd52hi(z1_2, r19, z5); + z2_2 = madd52hi(z2_2, r19, z6); + z3_2 = madd52hi(z3_2, r19, z7); + + // Wave 8 + z3_1 = madd52lo(z3_1, r19, z8); + z4_2 = madd52lo(z4_2, r19, z8 >> 52); + + F51x4Unreduced([ + z0_1 + z0_2 + z0_2, + z1_1 + z1_2 + z1_2, + z2_1 + z2_2 + z2_2, + z3_1 + z3_2 + z3_2, + z4_1 + z4_2 + z4_2, + ]) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn vpmadd52luq() { + let x = u64x4::splat(2); + let y = u64x4::splat(3); + let mut z = u64x4::splat(5); + + z = unsafe { madd52lo(z, x, y) }; + + assert_eq!(z, u64x4::splat(5 + 2 * 3)); + } + + #[test] + fn new_split_round_trip_on_reduced_input() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + + let ax4 = F51x4Unreduced::new(&a, &a, &a, &a); + let splits = ax4.split(); + + for i in 0..4 { + assert_eq!(a, splits[i]); + } + } + + #[test] + fn new_split_round_trip_on_unreduced_input() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + // ... but now multiply it by 16 without reducing coeffs + let a16 = FieldElement51([ + a.0[0] << 4, + a.0[1] << 4, + a.0[2] << 4, + a.0[3] << 4, + a.0[4] << 4, + ]); + + let a16x4 = F51x4Unreduced::new(&a16, &a16, &a16, &a16); + let splits = a16x4.split(); + + for i in 0..4 { + assert_eq!(a16, splits[i]); + } + } + + #[test] + fn test_reduction() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + // ... but now multiply it by 128 without reducing coeffs + let abig = FieldElement51([ + a.0[0] << 4, + a.0[1] << 4, + a.0[2] << 4, + a.0[3] << 4, + a.0[4] << 4, + ]); + + let abigx4: F51x4Reduced = F51x4Unreduced::new(&abig, &abig, &abig, &abig).into(); + + let splits = F51x4Unreduced::from(abigx4).split(); + let c = &a * &FieldElement51([(1 << 4), 0, 0, 0, 0]); + + for i in 0..4 { + assert_eq!(c, splits[i]); + } + } + + #[test] + fn mul_matches_serial() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + let b = FieldElement51([98098, 87987897, 0, 1, 0]).invert(); + let c = &a * &b; + + let ax4: F51x4Reduced = F51x4Unreduced::new(&a, &a, &a, &a).into(); + let bx4: F51x4Reduced = F51x4Unreduced::new(&b, &b, &b, &b).into(); + let cx4 = &ax4 * &bx4; + + let splits = cx4.split(); + + for i in 0..4 { + assert_eq!(c, splits[i]); + } + } + + #[test] + fn iterated_mul_matches_serial() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + let b = FieldElement51([98098, 87987897, 0, 1, 0]).invert(); + let mut c = &a * &b; + for _i in 0..1024 { + c = &a * &c; + c = &b * &c; + } + + let ax4: F51x4Reduced = F51x4Unreduced::new(&a, &a, &a, &a).into(); + let bx4: F51x4Reduced = F51x4Unreduced::new(&b, &b, &b, &b).into(); + let mut cx4 = &ax4 * &bx4; + for _i in 0..1024 { + cx4 = &ax4 * &F51x4Reduced::from(cx4); + cx4 = &bx4 * &F51x4Reduced::from(cx4); + } + + let splits = cx4.split(); + + for i in 0..4 { + assert_eq!(c, splits[i]); + } + } + + #[test] + fn square_matches_mul() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + + let ax4: F51x4Reduced = F51x4Unreduced::new(&a, &a, &a, &a).into(); + let cx4 = &ax4 * &ax4; + let cx4_sq = ax4.square(); + + let splits = cx4.split(); + let splits_sq = cx4_sq.split(); + + for i in 0..4 { + assert_eq!(splits_sq[i], splits[i]); + } + } + + #[test] + fn iterated_square_matches_serial() { + // Invert a small field element to get a big one + let mut a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + let mut ax4 = F51x4Unreduced::new(&a, &a, &a, &a); + for _j in 0..1024 { + a = a.square(); + ax4 = F51x4Reduced::from(ax4).square(); + + let splits = ax4.split(); + for i in 0..4 { + assert_eq!(a, splits[i]); + } + } + } + + #[test] + fn iterated_u32_mul_matches_serial() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + let b = FieldElement51([121665, 0, 0, 0, 0]); + let mut c = &a * &b; + for _i in 0..1024 { + c = &b * &c; + } + + let ax4 = F51x4Unreduced::new(&a, &a, &a, &a); + let bx4 = (121665u32, 121665u32, 121665u32, 121665u32); + let mut cx4 = &F51x4Reduced::from(ax4) * bx4; + for _i in 0..1024 { + cx4 = &F51x4Reduced::from(cx4) * bx4; + } + + let splits = cx4.split(); + + for i in 0..4 { + assert_eq!(c, splits[i]); + } + } + + #[test] + fn shuffle_AAAA() { + let x0 = FieldElement51::from_bytes(&[0x10; 32]); + let x1 = FieldElement51::from_bytes(&[0x11; 32]); + let x2 = FieldElement51::from_bytes(&[0x12; 32]); + let x3 = FieldElement51::from_bytes(&[0x13; 32]); + + let x = F51x4Unreduced::new(&x0, &x1, &x2, &x3); + + let y = x.shuffle(Shuffle::AAAA); + let splits = y.split(); + + assert_eq!(splits[0], x0); + assert_eq!(splits[1], x0); + assert_eq!(splits[2], x0); + assert_eq!(splits[3], x0); + } + + #[test] + fn blend_AB() { + let x0 = FieldElement51::from_bytes(&[0x10; 32]); + let x1 = FieldElement51::from_bytes(&[0x11; 32]); + let x2 = FieldElement51::from_bytes(&[0x12; 32]); + let x3 = FieldElement51::from_bytes(&[0x13; 32]); + + let x = F51x4Unreduced::new(&x0, &x1, &x2, &x3); + let z = F51x4Unreduced::new(&x3, &x2, &x1, &x0); + + let y = x.blend(&z, Lanes::AB); + let splits = y.split(); + + assert_eq!(splits[0], x3); + assert_eq!(splits[1], x2); + assert_eq!(splits[2], x2); + assert_eq!(splits[3], x3); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/mod.rs new file mode 100644 index 0000000..6191ecc --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/ifma/mod.rs @@ -0,0 +1,19 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2018-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +#![cfg_attr( + feature = "nightly", + doc(include = "../../../../docs/ifma-notes.md") +)] + +pub mod field; + +pub mod edwards; + +pub mod constants; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/mod.rs new file mode 100644 index 0000000..9726c71 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/mod.rs @@ -0,0 +1,42 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +// Conditionally include the notes if we're on nightly (so we can include docs at all). +#![cfg_attr( + feature = "nightly", + doc(include = "../../../docs/parallel-formulas.md") +)] + +#[cfg(not(any(target_feature = "avx2", target_feature = "avx512ifma", rustdoc)))] +compile_error!("simd_backend selected without target_feature=+avx2 or +avx512ifma"); + +#[cfg(any( + all(target_feature = "avx2", not(target_feature = "avx512ifma")), + rustdoc +))] +#[doc(cfg(all(target_feature = "avx2", not(target_feature = "avx512ifma"))))] +pub mod avx2; +#[cfg(any( + all(target_feature = "avx2", not(target_feature = "avx512ifma")), + rustdoc +))] +pub(crate) use self::avx2::{ + constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, +}; + +#[cfg(any(target_feature = "avx512ifma", rustdoc))] +#[doc(cfg(target_feature = "avx512ifma"))] +pub mod ifma; +#[cfg(target_feature = "avx512ifma")] +pub(crate) use self::ifma::{ + constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, +}; + +pub mod scalar_mul; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/mod.rs new file mode 100644 index 0000000..2fc1b18 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/mod.rs @@ -0,0 +1,22 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +pub mod variable_base; + +pub mod vartime_double_base; + +#[cfg(feature = "alloc")] +pub mod straus; + +#[cfg(feature = "alloc")] +pub mod precomputed_straus; + +#[cfg(feature = "alloc")] +pub mod pippenger; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/pippenger.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/pippenger.rs new file mode 100644 index 0000000..7f9e241 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/pippenger.rs @@ -0,0 +1,164 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Oleg Andreev +// See LICENSE for licensing information. +// +// Authors: +// - Oleg Andreev + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use backend::vector::{CachedPoint, ExtendedPoint}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::{Identity, VartimeMultiscalarMul}; + +#[allow(unused_imports)] +use prelude::*; + +/// Implements a version of Pippenger's algorithm. +/// +/// See the documentation in the serial `scalar_mul::pippenger` module for details. +pub struct Pippenger; + +#[cfg(any(feature = "alloc", feature = "std"))] +impl VartimeMultiscalarMul for Pippenger { + type Point = EdwardsPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + let mut scalars = scalars.into_iter(); + let size = scalars.by_ref().size_hint().0; + let w = if size < 500 { + 6 + } else if size < 800 { + 7 + } else { + 8 + }; + + let max_digit: usize = 1 << w; + let digits_count: usize = Scalar::to_radix_2w_size_hint(w); + let buckets_count: usize = max_digit / 2; // digits are signed+centered hence 2^w/2, excluding 0-th bucket + + // Collect optimized scalars and points in a buffer for repeated access + // (scanning the whole collection per each digit position). + let scalars = scalars + .into_iter() + .map(|s| s.borrow().to_radix_2w(w)); + + let points = points + .into_iter() + .map(|p| p.map(|P| CachedPoint::from(ExtendedPoint::from(P)))); + + let scalars_points = scalars + .zip(points) + .map(|(s, maybe_p)| maybe_p.map(|p| (s, p))) + .collect::>>()?; + + // Prepare 2^w/2 buckets. + // buckets[i] corresponds to a multiplication factor (i+1). + let mut buckets: Vec = (0..buckets_count) + .map(|_| ExtendedPoint::identity()) + .collect(); + + let mut columns = (0..digits_count).rev().map(|digit_index| { + // Clear the buckets when processing another digit. + for i in 0..buckets_count { + buckets[i] = ExtendedPoint::identity(); + } + + // Iterate over pairs of (point, scalar) + // and add/sub the point to the corresponding bucket. + // Note: if we add support for precomputed lookup tables, + // we'll be adding/subtractiong point premultiplied by `digits[i]` to buckets[0]. + for (digits, pt) in scalars_points.iter() { + // Widen digit so that we don't run into edge cases when w=8. + let digit = digits[digit_index] as i16; + if digit > 0 { + let b = (digit - 1) as usize; + buckets[b] = &buckets[b] + pt; + } else if digit < 0 { + let b = (-digit - 1) as usize; + buckets[b] = &buckets[b] - pt; + } + } + + // Add the buckets applying the multiplication factor to each bucket. + // The most efficient way to do that is to have a single sum with two running sums: + // an intermediate sum from last bucket to the first, and a sum of intermediate sums. + // + // For example, to add buckets 1*A, 2*B, 3*C we need to add these points: + // C + // C B + // C B A Sum = C + (C+B) + (C+B+A) + let mut buckets_intermediate_sum = buckets[buckets_count - 1]; + let mut buckets_sum = buckets[buckets_count - 1]; + for i in (0..(buckets_count - 1)).rev() { + buckets_intermediate_sum = + &buckets_intermediate_sum + &CachedPoint::from(buckets[i]); + buckets_sum = &buckets_sum + &CachedPoint::from(buckets_intermediate_sum); + } + + buckets_sum + }); + + // Take the high column as an initial value to avoid wasting time doubling the identity element in `fold()`. + // `unwrap()` always succeeds because we know we have more than zero digits. + let hi_column = columns.next().unwrap(); + + Some( + columns + .fold(hi_column, |total, p| { + &total.mul_by_pow_2(w as u32) + &CachedPoint::from(p) + }) + .into(), + ) + } +} + +#[cfg(test)] +mod test { + use super::*; + use constants; + use scalar::Scalar; + + #[test] + fn test_vartime_pippenger() { + // Reuse points across different tests + let mut n = 512; + let x = Scalar::from(2128506u64).invert(); + let y = Scalar::from(4443282u64).invert(); + let points: Vec<_> = (0..n) + .map(|i| constants::ED25519_BASEPOINT_POINT * Scalar::from(1 + i as u64)) + .collect(); + let scalars: Vec<_> = (0..n) + .map(|i| x + (Scalar::from(i as u64) * y)) // fast way to make ~random but deterministic scalars + .collect(); + + let premultiplied: Vec = scalars + .iter() + .zip(points.iter()) + .map(|(sc, pt)| sc * pt) + .collect(); + + while n > 0 { + let scalars = &scalars[0..n].to_vec(); + let points = &points[0..n].to_vec(); + let control: EdwardsPoint = premultiplied[0..n].iter().sum(); + + let subject = Pippenger::vartime_multiscalar_mul(scalars.clone(), points.clone()); + + assert_eq!(subject.compress(), control.compress()); + + n = n / 2; + } + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/precomputed_straus.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/precomputed_straus.rs new file mode 100644 index 0000000..2c6fdf5 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -0,0 +1,107 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Henry de Valence. +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +//! Precomputation for Straus's method. + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use backend::vector::{CachedPoint, ExtendedPoint}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::Identity; +use traits::VartimePrecomputedMultiscalarMul; +use window::{NafLookupTable5, NafLookupTable8}; + +#[allow(unused_imports)] +use prelude::*; + + +pub struct VartimePrecomputedStraus { + static_lookup_tables: Vec>, +} + +impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { + type Point = EdwardsPoint; + + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + Self { + static_lookup_tables: static_points + .into_iter() + .map(|P| NafLookupTable8::::from(P.borrow())) + .collect(), + } + } + + fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator>, + { + let static_nafs = static_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + let dynamic_nafs: Vec<_> = dynamic_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + + let dynamic_lookup_tables = dynamic_points + .into_iter() + .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) + .collect::>>()?; + + let sp = self.static_lookup_tables.len(); + let dp = dynamic_lookup_tables.len(); + assert_eq!(sp, static_nafs.len()); + assert_eq!(dp, dynamic_nafs.len()); + + // We could save some doublings by looking for the highest + // nonzero NAF coefficient, but since we might have a lot of + // them to search, it's not clear it's worthwhile to check. + let mut R = ExtendedPoint::identity(); + for j in (0..256).rev() { + R = R.double(); + + for i in 0..dp { + let t_ij = dynamic_nafs[i][j]; + if t_ij > 0 { + R = &R + &dynamic_lookup_tables[i].select(t_ij as usize); + } else if t_ij < 0 { + R = &R - &dynamic_lookup_tables[i].select(-t_ij as usize); + } + } + + for i in 0..sp { + let t_ij = static_nafs[i][j]; + if t_ij > 0 { + R = &R + &self.static_lookup_tables[i].select(t_ij as usize); + } else if t_ij < 0 { + R = &R - &self.static_lookup_tables[i].select(-t_ij as usize); + } + } + } + + Some(R.into()) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/straus.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/straus.rs new file mode 100644 index 0000000..7206cf3 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/straus.rs @@ -0,0 +1,107 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use zeroize::Zeroizing; + +use backend::vector::{CachedPoint, ExtendedPoint}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use window::{LookupTable, NafLookupTable5}; +use traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; + +#[allow(unused_imports)] +use prelude::*; + +/// Multiscalar multiplication using interleaved window / Straus' +/// method. See the `Straus` struct in the serial backend for more +/// details. +/// +/// This exists as a seperate implementation from that one because the +/// AVX2 code uses different curve models (it does not pass between +/// multiple models during scalar mul), and it has to convert the +/// point representation on the fly. +pub struct Straus {} + +impl MultiscalarMul for Straus { + type Point = EdwardsPoint; + + fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + { + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + // for each input point P + let lookup_tables: Vec<_> = points + .into_iter() + .map(|point| LookupTable::::from(point.borrow())) + .collect(); + + let scalar_digits_vec: Vec<_> = scalars + .into_iter() + .map(|s| s.borrow().to_radix_16()) + .collect(); + // Pass ownership to a `Zeroizing` wrapper + let scalar_digits = Zeroizing::new(scalar_digits_vec); + + let mut Q = ExtendedPoint::identity(); + for j in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + let it = scalar_digits.iter().zip(lookup_tables.iter()); + for (s_i, lookup_table_i) in it { + // Q = Q + s_{i,j} * P_i + Q = &Q + &lookup_table_i.select(s_i[j]); + } + } + Q.into() + } +} + +impl VartimeMultiscalarMul for Straus { + type Point = EdwardsPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + let nafs: Vec<_> = scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect(); + let lookup_tables: Vec<_> = points + .into_iter() + .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) + .collect::>>()?; + + let mut Q = ExtendedPoint::identity(); + + for i in (0..256).rev() { + Q = Q.double(); + + for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) { + if naf[i] > 0 { + Q = &Q + &lookup_table.select(naf[i] as usize); + } else if naf[i] < 0 { + Q = &Q - &lookup_table.select(-naf[i] as usize); + } + } + } + + Some(Q.into()) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/variable_base.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/variable_base.rs new file mode 100644 index 0000000..f53c4a0 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/variable_base.rs @@ -0,0 +1,32 @@ +#![allow(non_snake_case)] + +use backend::vector::{CachedPoint, ExtendedPoint}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::Identity; +use window::LookupTable; + +/// Perform constant-time, variable-base scalar multiplication. +pub fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + let lookup_table = LookupTable::::from(point); + // Setting s = scalar, compute + // + // s = s_0 + s_1*16^1 + ... + s_63*16^63, + // + // with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`. + let scalar_digits = scalar.to_radix_16(); + // Compute s*P as + // + // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) + // s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63 + // s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...)) + // + // We sum right-to-left. + let mut Q = ExtendedPoint::identity(); + for i in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + Q = &Q + &lookup_table.select(scalar_digits[i]); + } + Q.into() +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/vartime_double_base.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/vartime_double_base.rs new file mode 100644 index 0000000..d78e46d --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/backend/vector/scalar_mul/vartime_double_base.rs @@ -0,0 +1,60 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence +#![allow(non_snake_case)] + +use backend::vector::BASEPOINT_ODD_LOOKUP_TABLE; +use backend::vector::{CachedPoint, ExtendedPoint}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::Identity; +use window::NafLookupTable5; + +/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. +pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { + let a_naf = a.non_adjacent_form(5); + let b_naf = b.non_adjacent_form(8); + + // Find starting index + let mut i: usize = 255; + for j in (0..256).rev() { + i = j; + if a_naf[i] != 0 || b_naf[i] != 0 { + break; + } + } + + let table_A = NafLookupTable5::::from(A); + let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; + + let mut Q = ExtendedPoint::identity(); + + loop { + Q = Q.double(); + + if a_naf[i] > 0 { + Q = &Q + &table_A.select(a_naf[i] as usize); + } else if a_naf[i] < 0 { + Q = &Q - &table_A.select(-a_naf[i] as usize); + } + + if b_naf[i] > 0 { + Q = &Q + &table_B.select(b_naf[i] as usize); + } else if b_naf[i] < 0 { + Q = &Q - &table_B.select(-b_naf[i] as usize); + } + + if i == 0 { + break; + } + i -= 1; + } + + Q.into() +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/constants.rs new file mode 100644 index 0000000..e30d35e --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/constants.rs @@ -0,0 +1,176 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Various constants, such as the Ristretto and Ed25519 basepoints. +//! +//! Most of the constants are given with +//! `LONG_DESCRIPTIVE_UPPER_CASE_NAMES`, but they can be brought into +//! scope using a `let` binding: +//! +//! ``` +//! use curve25519_dalek::constants; +//! use curve25519_dalek::traits::IsIdentity; +//! +//! let B = &constants::RISTRETTO_BASEPOINT_TABLE; +//! let l = &constants::BASEPOINT_ORDER; +//! +//! let A = l * B; +//! assert!(A.is_identity()); +//! ``` + +#![allow(non_snake_case)] + +use edwards::CompressedEdwardsY; +use ristretto::RistrettoPoint; +use ristretto::CompressedRistretto; +use montgomery::MontgomeryPoint; +use scalar::Scalar; + +#[cfg(feature = "u64_backend")] +pub use backend::serial::u64::constants::*; +#[cfg(feature = "u32_backend")] +pub use backend::serial::u32::constants::*; + +/// The Ed25519 basepoint, in `CompressedEdwardsY` format. +/// +/// This is the little-endian byte encoding of \\( 4/5 \pmod p \\), +/// which is the \\(y\\)-coordinate of the Ed25519 basepoint. +/// +/// The sign bit is 0 since the basepoint has \\(x\\) chosen to be positive. +pub const ED25519_BASEPOINT_COMPRESSED: CompressedEdwardsY = + CompressedEdwardsY([0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]); + +/// The X25519 basepoint, in `MontgomeryPoint` format. +pub const X25519_BASEPOINT: MontgomeryPoint = + MontgomeryPoint([0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); + +/// The Ristretto basepoint, in `CompressedRistretto` format. +pub const RISTRETTO_BASEPOINT_COMPRESSED: CompressedRistretto = + CompressedRistretto([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]); + +/// The Ristretto basepoint, as a `RistrettoPoint`. +/// +/// This is called `_POINT` to distinguish it from `_TABLE`, which +/// provides fast scalar multiplication. +pub const RISTRETTO_BASEPOINT_POINT: RistrettoPoint = RistrettoPoint(ED25519_BASEPOINT_POINT); + +/// `BASEPOINT_ORDER` is the order of the Ristretto group and of the Ed25519 basepoint, i.e., +/// $$ +/// \ell = 2^\{252\} + 27742317777372353535851937790883648493. +/// $$ +pub const BASEPOINT_ORDER: Scalar = Scalar{ + bytes: [ + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + ], +}; + +use ristretto::RistrettoBasepointTable; +/// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication. +pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable + = RistrettoBasepointTable(ED25519_BASEPOINT_TABLE); + +#[cfg(test)] +mod test { + use field::FieldElement; + use traits::{IsIdentity, ValidityCheck}; + use constants; + + #[test] + fn test_eight_torsion() { + for i in 0..8 { + let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(3); + assert!(Q.is_valid()); + assert!(Q.is_identity()); + } + } + + #[test] + fn test_four_torsion() { + for i in (0..8).filter(|i| i % 2 == 0) { + let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(2); + assert!(Q.is_valid()); + assert!(Q.is_identity()); + } + } + + #[test] + fn test_two_torsion() { + for i in (0..8).filter(|i| i % 4 == 0) { + let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(1); + assert!(Q.is_valid()); + assert!(Q.is_identity()); + } + } + + /// Test that SQRT_M1 is the positive square root of -1 + #[test] + fn test_sqrt_minus_one() { + let minus_one = FieldElement::minus_one(); + let sqrt_m1_sq = &constants::SQRT_M1 * &constants::SQRT_M1; + assert_eq!(minus_one, sqrt_m1_sq); + assert_eq!(constants::SQRT_M1.is_negative().unwrap_u8(), 0); + } + + #[test] + fn test_sqrt_constants_sign() { + let minus_one = FieldElement::minus_one(); + let (was_nonzero_square, invsqrt_m1) = minus_one.invsqrt(); + assert_eq!(was_nonzero_square.unwrap_u8(), 1u8); + let sign_test_sqrt = &invsqrt_m1 * &constants::SQRT_M1; + assert_eq!(sign_test_sqrt, minus_one); + } + + /// Test that d = -121665/121666 + #[test] + #[cfg(feature = "u32_backend")] + fn test_d_vs_ratio() { + use backend::serial::u32::field::FieldElement2625; + let a = -&FieldElement2625([121665,0,0,0,0,0,0,0,0,0]); + let b = FieldElement2625([121666,0,0,0,0,0,0,0,0,0]); + let d = &a * &b.invert(); + let d2 = &d + &d; + assert_eq!(d, constants::EDWARDS_D); + assert_eq!(d2, constants::EDWARDS_D2); + } + + /// Test that d = -121665/121666 + #[test] + #[cfg(feature = "u64_backend")] + fn test_d_vs_ratio() { + use backend::serial::u64::field::FieldElement51; + let a = -&FieldElement51([121665,0,0,0,0]); + let b = FieldElement51([121666,0,0,0,0]); + let d = &a * &b.invert(); + let d2 = &d + &d; + assert_eq!(d, constants::EDWARDS_D); + assert_eq!(d2, constants::EDWARDS_D2); + } + + #[test] + fn test_sqrt_ad_minus_one() { + let a = FieldElement::minus_one(); + let ad_minus_one = &(&a * &constants::EDWARDS_D) + &a; + let should_be_ad_minus_one = constants::SQRT_AD_MINUS_ONE.square(); + assert_eq!(should_be_ad_minus_one, ad_minus_one); + } + +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/edwards.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/edwards.rs new file mode 100644 index 0000000..998af8d --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/edwards.rs @@ -0,0 +1,1435 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Group operations for Curve25519, in Edwards form. +//! +//! ## Encoding and Decoding +//! +//! Encoding is done by converting to and from a `CompressedEdwardsY` +//! struct, which is a typed wrapper around `[u8; 32]`. +//! +//! ## Equality Testing +//! +//! The `EdwardsPoint` struct implements the `subtle::ConstantTimeEq` +//! trait for constant-time equality checking, and the Rust `Eq` trait +//! for variable-time equality checking. +//! +//! ## Cofactor-related functions +//! +//! The order of the group of points on the curve \\(\mathcal E\\) +//! is \\(|\mathcal E| = 8\ell \\), so its structure is \\( \mathcal +//! E = \mathcal E[8] \times \mathcal E[\ell]\\). The torsion +//! subgroup \\( \mathcal E[8] \\) consists of eight points of small +//! order. Technically, all of \\(\mathcal E\\) is torsion, but we +//! use the word only to refer to the small \\(\mathcal E[8]\\) part, not +//! the large prime-order \\(\mathcal E[\ell]\\) part. +//! +//! To test if a point is in \\( \mathcal E[8] \\), use +//! `EdwardsPoint::is_small_order()`. +//! +//! To test if a point is in \\( \mathcal E[\ell] \\), use +//! `EdwardsPoint::is_torsion_free()`. +//! +//! To multiply by the cofactor, use `EdwardsPoint::mul_by_cofactor()`. +//! +//! To avoid dealing with cofactors entirely, consider using Ristretto. +//! +//! ## Scalars +//! +//! Scalars are represented by the `Scalar` struct. To construct a scalar with a specific bit +//! pattern, see `Scalar::from_bits()`. +//! +//! ## Scalar Multiplication +//! +//! Scalar multiplication on Edwards points is provided by: +//! +//! * the `*` operator between a `Scalar` and a `EdwardsPoint`, which +//! performs constant-time variable-base scalar multiplication; +//! +//! * the `*` operator between a `Scalar` and a +//! `EdwardsBasepointTable`, which performs constant-time fixed-base +//! scalar multiplication; +//! +//! * an implementation of the +//! [`MultiscalarMul`](../traits/trait.MultiscalarMul.html) trait for +//! constant-time variable-base multiscalar multiplication; +//! +//! * an implementation of the +//! [`VartimeMultiscalarMul`](../traits/trait.VartimeMultiscalarMul.html) +//! trait for variable-time variable-base multiscalar multiplication; +//! +//! ## Implementation +//! +//! The Edwards arithmetic is implemented using the “extended twisted +//! coordinates” of Hisil, Wong, Carter, and Dawson, and the +//! corresponding complete formulas. For more details, +//! see the [`curve_models` submodule][curve_models] +//! of the internal documentation. +//! +//! ## Validity Checking +//! +//! There is no function for checking whether a point is valid. +//! Instead, the `EdwardsPoint` struct is guaranteed to hold a valid +//! point on the curve. +//! +//! We use the Rust type system to make invalid points +//! unrepresentable: `EdwardsPoint` objects can only be created via +//! successful decompression of a compressed point, or else by +//! operations on other (valid) `EdwardsPoint`s. +//! +//! [curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/backend/serial/curve_models/index.html + +// We allow non snake_case names because coordinates in projective space are +// traditionally denoted by the capitalisation of their respective +// counterparts in affine space. Yeah, you heard me, rustc, I'm gonna have my +// affine and projective cakes and eat both of them too. +#![allow(non_snake_case)] + +use core::borrow::Borrow; +use core::fmt::Debug; +use core::iter::Iterator; +use core::iter::Sum; +use core::ops::{Add, Neg, Sub}; +use core::ops::{AddAssign, SubAssign}; +use core::ops::{Mul, MulAssign}; + +use subtle::Choice; +use subtle::ConditionallyNegatable; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; + +use constants; + +use field::FieldElement; +use scalar::Scalar; + +use montgomery::MontgomeryPoint; + +use backend::serial::curve_models::AffineNielsPoint; +use backend::serial::curve_models::CompletedPoint; +use backend::serial::curve_models::ProjectiveNielsPoint; +use backend::serial::curve_models::ProjectivePoint; + +use window::LookupTable; + +#[allow(unused_imports)] +use prelude::*; + +use traits::ValidityCheck; +use traits::{Identity, IsIdentity}; + +#[cfg(any(feature = "alloc", feature = "std"))] +use traits::MultiscalarMul; +#[cfg(any(feature = "alloc", feature = "std"))] +use traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; + +#[cfg(not(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +)))] +use backend::serial::scalar_mul; +#[cfg(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +))] +use backend::vector::scalar_mul; + +// ------------------------------------------------------------------------ +// Compressed points +// ------------------------------------------------------------------------ + +/// In "Edwards y" / "Ed25519" format, the curve point \\((x,y)\\) is +/// determined by the \\(y\\)-coordinate and the sign of \\(x\\). +/// +/// The first 255 bits of a `CompressedEdwardsY` represent the +/// \\(y\\)-coordinate. The high bit of the 32nd byte gives the sign of \\(x\\). +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct CompressedEdwardsY(pub [u8; 32]); + +impl ConstantTimeEq for CompressedEdwardsY { + fn ct_eq(&self, other: &CompressedEdwardsY) -> Choice { + self.as_bytes().ct_eq(other.as_bytes()) + } +} + +impl Debug for CompressedEdwardsY { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "CompressedEdwardsY: {:?}", self.as_bytes()) + } +} + +impl CompressedEdwardsY { + /// View this `CompressedEdwardsY` as an array of bytes. + pub fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } + + /// Copy this `CompressedEdwardsY` to an array of bytes. + pub fn to_bytes(&self) -> [u8; 32] { + self.0 + } + + /// Attempt to decompress to an `EdwardsPoint`. + /// + /// Returns `None` if the input is not the \\(y\\)-coordinate of a + /// curve point. + pub fn decompress(&self) -> Option { + let Y = FieldElement::from_bytes(self.as_bytes()); + let Z = FieldElement::one(); + let YY = Y.square(); + let u = &YY - &Z; // u = y²-1 + let v = &(&YY * &constants::EDWARDS_D) + &Z; // v = dy²+1 + let (is_valid_y_coord, mut X) = FieldElement::sqrt_ratio_i(&u, &v); + + if is_valid_y_coord.unwrap_u8() != 1u8 { return None; } + + // FieldElement::sqrt_ratio_i always returns the nonnegative square root, + // so we negate according to the supplied sign bit. + let compressed_sign_bit = Choice::from(self.as_bytes()[31] >> 7); + X.conditional_negate(compressed_sign_bit); + + Some(EdwardsPoint{ X, Y, Z, T: &X * &Y }) + } +} + +// ------------------------------------------------------------------------ +// Serde support +// ------------------------------------------------------------------------ +// Serializes to and from `EdwardsPoint` directly, doing compression +// and decompression internally. This means that users can create +// structs containing `EdwardsPoint`s and use Serde's derived +// serializers to serialize those structures. + +#[cfg(feature = "serde")] +use serde::{self, Serialize, Deserialize, Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +#[cfg(feature = "serde")] +impl Serialize for EdwardsPoint { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + use serde::ser::SerializeTuple; + let mut tup = serializer.serialize_tuple(32)?; + for byte in self.compress().as_bytes().iter() { + tup.serialize_element(byte)?; + } + tup.end() + } +} + +#[cfg(feature = "serde")] +impl Serialize for CompressedEdwardsY { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + use serde::ser::SerializeTuple; + let mut tup = serializer.serialize_tuple(32)?; + for byte in self.as_bytes().iter() { + tup.serialize_element(byte)?; + } + tup.end() + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for EdwardsPoint { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + struct EdwardsPointVisitor; + + impl<'de> Visitor<'de> for EdwardsPointVisitor { + type Value = EdwardsPoint; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("a valid point in Edwards y + sign format") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de> + { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = seq.next_element()? + .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + CompressedEdwardsY(bytes) + .decompress() + .ok_or(serde::de::Error::custom("decompression failed")) + } + } + + deserializer.deserialize_tuple(32, EdwardsPointVisitor) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for CompressedEdwardsY { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + struct CompressedEdwardsYVisitor; + + impl<'de> Visitor<'de> for CompressedEdwardsYVisitor { + type Value = CompressedEdwardsY; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("32 bytes of data") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de> + { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = seq.next_element()? + .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + Ok(CompressedEdwardsY(bytes)) + } + } + + deserializer.deserialize_tuple(32, CompressedEdwardsYVisitor) + } +} + +// ------------------------------------------------------------------------ +// Internal point representations +// ------------------------------------------------------------------------ + +/// An `EdwardsPoint` represents a point on the Edwards form of Curve25519. +#[derive(Copy, Clone)] +#[allow(missing_docs)] +pub struct EdwardsPoint { + pub(crate) X: FieldElement, + pub(crate) Y: FieldElement, + pub(crate) Z: FieldElement, + pub(crate) T: FieldElement, +} + +// ------------------------------------------------------------------------ +// Constructors +// ------------------------------------------------------------------------ + +impl Identity for CompressedEdwardsY { + fn identity() -> CompressedEdwardsY { + CompressedEdwardsY([1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0]) + } +} + +impl Default for CompressedEdwardsY { + fn default() -> CompressedEdwardsY { + CompressedEdwardsY::identity() + } +} + +impl CompressedEdwardsY { + /// Construct a `CompressedEdwardsY` from a slice of bytes. + /// + /// # Panics + /// + /// If the input `bytes` slice does not have a length of 32. + pub fn from_slice(bytes: &[u8]) -> CompressedEdwardsY { + let mut tmp = [0u8; 32]; + + tmp.copy_from_slice(bytes); + + CompressedEdwardsY(tmp) + } +} + +impl Identity for EdwardsPoint { + fn identity() -> EdwardsPoint { + EdwardsPoint { + X: FieldElement::zero(), + Y: FieldElement::one(), + Z: FieldElement::one(), + T: FieldElement::zero(), + } + } +} + +impl Default for EdwardsPoint { + fn default() -> EdwardsPoint { + EdwardsPoint::identity() + } +} + +// ------------------------------------------------------------------------ +// Validity checks (for debugging, not CT) +// ------------------------------------------------------------------------ + +impl ValidityCheck for EdwardsPoint { + fn is_valid(&self) -> bool { + let point_on_curve = self.to_projective().is_valid(); + let on_segre_image = (&self.X * &self.Y) == (&self.Z * &self.T); + + point_on_curve && on_segre_image + } +} + +// ------------------------------------------------------------------------ +// Constant-time assignment +// ------------------------------------------------------------------------ + +impl ConditionallySelectable for EdwardsPoint { + fn conditional_select(a: &EdwardsPoint, b: &EdwardsPoint, choice: Choice) -> EdwardsPoint { + EdwardsPoint { + X: FieldElement::conditional_select(&a.X, &b.X, choice), + Y: FieldElement::conditional_select(&a.Y, &b.Y, choice), + Z: FieldElement::conditional_select(&a.Z, &b.Z, choice), + T: FieldElement::conditional_select(&a.T, &b.T, choice), + } + } +} + +// ------------------------------------------------------------------------ +// Equality +// ------------------------------------------------------------------------ + +impl ConstantTimeEq for EdwardsPoint { + fn ct_eq(&self, other: &EdwardsPoint) -> Choice { + // We would like to check that the point (X/Z, Y/Z) is equal to + // the point (X'/Z', Y'/Z') without converting into affine + // coordinates (x, y) and (x', y'), which requires two inversions. + // We have that X = xZ and X' = x'Z'. Thus, x = x' is equivalent to + // (xZ)Z' = (x'Z')Z, and similarly for the y-coordinate. + + (&self.X * &other.Z).ct_eq(&(&other.X * &self.Z)) + & (&self.Y * &other.Z).ct_eq(&(&other.Y * &self.Z)) + } +} + +impl PartialEq for EdwardsPoint { + fn eq(&self, other: &EdwardsPoint) -> bool { + self.ct_eq(other).unwrap_u8() == 1u8 + } +} + +impl Eq for EdwardsPoint {} + +// ------------------------------------------------------------------------ +// Point conversions +// ------------------------------------------------------------------------ + +impl EdwardsPoint { + /// Convert to a ProjectiveNielsPoint + pub(crate) fn to_projective_niels(&self) -> ProjectiveNielsPoint { + ProjectiveNielsPoint{ + Y_plus_X: &self.Y + &self.X, + Y_minus_X: &self.Y - &self.X, + Z: self.Z, + T2d: &self.T * &constants::EDWARDS_D2, + } + } + + /// Convert the representation of this point from extended + /// coordinates to projective coordinates. + /// + /// Free. + pub(crate) fn to_projective(&self) -> ProjectivePoint { + ProjectivePoint{ + X: self.X, + Y: self.Y, + Z: self.Z, + } + } + + /// Dehomogenize to a AffineNielsPoint. + /// Mainly for testing. + pub(crate) fn to_affine_niels(&self) -> AffineNielsPoint { + let recip = self.Z.invert(); + let x = &self.X * &recip; + let y = &self.Y * &recip; + let xy2d = &(&x * &y) * &constants::EDWARDS_D2; + AffineNielsPoint{ + y_plus_x: &y + &x, + y_minus_x: &y - &x, + xy2d + } + } + + /// Convert this `EdwardsPoint` on the Edwards model to the + /// corresponding `MontgomeryPoint` on the Montgomery model. + /// + /// This function has one exceptional case; the identity point of + /// the Edwards curve is sent to the 2-torsion point \\((0,0)\\) + /// on the Montgomery curve. + /// + /// Note that this is a one-way conversion, since the Montgomery + /// model does not retain sign information. + pub fn to_montgomery(&self) -> MontgomeryPoint { + // We have u = (1+y)/(1-y) = (Z+Y)/(Z-Y). + // + // The denominator is zero only when y=1, the identity point of + // the Edwards curve. Since 0.invert() = 0, in this case we + // compute the 2-torsion point (0,0). + let U = &self.Z + &self.Y; + let W = &self.Z - &self.Y; + let u = &U * &W.invert(); + MontgomeryPoint(u.to_bytes()) + } + + /// Compress this point to `CompressedEdwardsY` format. + pub fn compress(&self) -> CompressedEdwardsY { + let recip = self.Z.invert(); + let x = &self.X * &recip; + let y = &self.Y * &recip; + let mut s: [u8; 32]; + + s = y.to_bytes(); + s[31] ^= x.is_negative().unwrap_u8() << 7; + CompressedEdwardsY(s) + } +} + +// ------------------------------------------------------------------------ +// Doubling +// ------------------------------------------------------------------------ + +impl EdwardsPoint { + /// Add this point to itself. + pub(crate) fn double(&self) -> EdwardsPoint { + self.to_projective().double().to_extended() + } +} + +// ------------------------------------------------------------------------ +// Addition and Subtraction +// ------------------------------------------------------------------------ + +impl<'a, 'b> Add<&'b EdwardsPoint> for &'a EdwardsPoint { + type Output = EdwardsPoint; + fn add(self, other: &'b EdwardsPoint) -> EdwardsPoint { + (self + &other.to_projective_niels()).to_extended() + } +} + +define_add_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint, Output = EdwardsPoint); + +impl<'b> AddAssign<&'b EdwardsPoint> for EdwardsPoint { + fn add_assign(&mut self, _rhs: &'b EdwardsPoint) { + *self = (self as &EdwardsPoint) + _rhs; + } +} + +define_add_assign_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint); + +impl<'a, 'b> Sub<&'b EdwardsPoint> for &'a EdwardsPoint { + type Output = EdwardsPoint; + fn sub(self, other: &'b EdwardsPoint) -> EdwardsPoint { + (self - &other.to_projective_niels()).to_extended() + } +} + +define_sub_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint, Output = EdwardsPoint); + +impl<'b> SubAssign<&'b EdwardsPoint> for EdwardsPoint { + fn sub_assign(&mut self, _rhs: &'b EdwardsPoint) { + *self = (self as &EdwardsPoint) - _rhs; + } +} + +define_sub_assign_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint); + +impl Sum for EdwardsPoint +where + T: Borrow +{ + fn sum(iter: I) -> Self + where + I: Iterator + { + iter.fold(EdwardsPoint::identity(), |acc, item| acc + item.borrow()) + } +} + + +// ------------------------------------------------------------------------ +// Negation +// ------------------------------------------------------------------------ + +impl<'a> Neg for &'a EdwardsPoint { + type Output = EdwardsPoint; + + fn neg(self) -> EdwardsPoint { + EdwardsPoint{ + X: -(&self.X), + Y: self.Y, + Z: self.Z, + T: -(&self.T), + } + } +} + +impl Neg for EdwardsPoint { + type Output = EdwardsPoint; + + fn neg(self) -> EdwardsPoint { + -&self + } +} + +// ------------------------------------------------------------------------ +// Scalar multiplication +// ------------------------------------------------------------------------ + +impl<'b> MulAssign<&'b Scalar> for EdwardsPoint { + fn mul_assign(&mut self, scalar: &'b Scalar) { + let result = (self as &EdwardsPoint) * scalar; + *self = result; + } +} + +define_mul_assign_variants!(LHS = EdwardsPoint, RHS = Scalar); + +define_mul_variants!(LHS = EdwardsPoint, RHS = Scalar, Output = EdwardsPoint); +define_mul_variants!(LHS = Scalar, RHS = EdwardsPoint, Output = EdwardsPoint); + +impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsPoint { + type Output = EdwardsPoint; + /// Scalar multiplication: compute `scalar * self`. + /// + /// For scalar multiplication of a basepoint, + /// `EdwardsBasepointTable` is approximately 4x faster. + fn mul(self, scalar: &'b Scalar) -> EdwardsPoint { + scalar_mul::variable_base::mul(self, scalar) + } +} + +impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar { + type Output = EdwardsPoint; + + /// Scalar multiplication: compute `scalar * self`. + /// + /// For scalar multiplication of a basepoint, + /// `EdwardsBasepointTable` is approximately 4x faster. + fn mul(self, point: &'b EdwardsPoint) -> EdwardsPoint { + point * self + } +} + +// ------------------------------------------------------------------------ +// Multiscalar Multiplication impls +// ------------------------------------------------------------------------ + +// These use the iterator's size hint and the target settings to +// forward to a specific backend implementation. + +#[cfg(feature = "alloc")] +impl MultiscalarMul for EdwardsPoint { + type Point = EdwardsPoint; + + fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + { + // Sanity-check lengths of input iterators + let mut scalars = scalars.into_iter(); + let mut points = points.into_iter(); + + // Lower and upper bounds on iterators + let (s_lo, s_hi) = scalars.by_ref().size_hint(); + let (p_lo, p_hi) = points.by_ref().size_hint(); + + // They should all be equal + assert_eq!(s_lo, p_lo); + assert_eq!(s_hi, Some(s_lo)); + assert_eq!(p_hi, Some(p_lo)); + + // Now we know there's a single size. When we do + // size-dependent algorithm dispatch, use this as the hint. + let _size = s_lo; + + scalar_mul::straus::Straus::multiscalar_mul(scalars, points) + } +} + +#[cfg(feature = "alloc")] +impl VartimeMultiscalarMul for EdwardsPoint { + type Point = EdwardsPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + // Sanity-check lengths of input iterators + let mut scalars = scalars.into_iter(); + let mut points = points.into_iter(); + + // Lower and upper bounds on iterators + let (s_lo, s_hi) = scalars.by_ref().size_hint(); + let (p_lo, p_hi) = points.by_ref().size_hint(); + + // They should all be equal + assert_eq!(s_lo, p_lo); + assert_eq!(s_hi, Some(s_lo)); + assert_eq!(p_hi, Some(p_lo)); + + // Now we know there's a single size. + // Use this as the hint to decide which algorithm to use. + let size = s_lo; + + if size < 190 { + scalar_mul::straus::Straus::optional_multiscalar_mul(scalars, points) + } else { + scalar_mul::pippenger::Pippenger::optional_multiscalar_mul(scalars, points) + } + } +} + +/// Precomputation for variable-time multiscalar multiplication with `EdwardsPoint`s. +// This wraps the inner implementation in a facade type so that we can +// decouple stability of the inner type from the stability of the +// outer type. +#[cfg(feature = "alloc")] +pub struct VartimeEdwardsPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); + +#[cfg(feature = "alloc")] +impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation { + type Point = EdwardsPoint; + + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + Self(scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points)) + } + + fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator>, + { + self.0 + .optional_mixed_multiscalar_mul(static_scalars, dynamic_scalars, dynamic_points) + } +} + +impl EdwardsPoint { + /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. + pub fn vartime_double_scalar_mul_basepoint( + a: &Scalar, + A: &EdwardsPoint, + b: &Scalar, + ) -> EdwardsPoint { + scalar_mul::vartime_double_base::mul(a, A, b) + } +} + +/// A precomputed table of multiples of a basepoint, for accelerating +/// fixed-base scalar multiplication. One table, for the Ed25519 +/// basepoint, is provided in the `constants` module. +/// +/// The basepoint tables are reasonably large (30KB), so they should +/// probably be boxed. +#[derive(Clone)] +pub struct EdwardsBasepointTable(pub(crate) [LookupTable; 32]); + +impl EdwardsBasepointTable { + /// The computation uses Pippeneger's algorithm, as described on + /// page 13 of the Ed25519 paper. Write the scalar \\(a\\) in radix \\(16\\) with + /// coefficients in \\([-8,8)\\), i.e., + /// $$ + /// a = a\_0 + a\_1 16\^1 + \cdots + a\_{63} 16\^{63}, + /// $$ + /// with \\(-8 \leq a_i < 8\\), \\(-8 \leq a\_{63} \leq 8\\). Then + /// $$ + /// a B = a\_0 B + a\_1 16\^1 B + \cdots + a\_{63} 16\^{63} B. + /// $$ + /// Grouping even and odd coefficients gives + /// $$ + /// \begin{aligned} + /// a B = \quad a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B \\\\ + /// + a\_1 16\^1 B +& a\_3 16\^3 B + \cdots + a\_{63} 16\^{63} B \\\\ + /// = \quad(a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B) \\\\ + /// + 16(a\_1 16\^0 B +& a\_3 16\^2 B + \cdots + a\_{63} 16\^{62} B). \\\\ + /// \end{aligned} + /// $$ + /// For each \\(i = 0 \ldots 31\\), we create a lookup table of + /// $$ + /// [16\^{2i} B, \ldots, 8\cdot16\^{2i} B], + /// $$ + /// and use it to select \\( x \cdot 16\^{2i} \cdot B \\) in constant time. + /// + /// The radix-\\(16\\) representation requires that the scalar is bounded + /// by \\(2\^{255}\\), which is always the case. + fn basepoint_mul(&self, scalar: &Scalar) -> EdwardsPoint { + let a = scalar.to_radix_16(); + + let tables = &self.0; + let mut P = EdwardsPoint::identity(); + + for i in (0..64).filter(|x| x % 2 == 1) { + P = (&P + &tables[i/2].select(a[i])).to_extended(); + } + + P = P.mul_by_pow_2(4); + + for i in (0..64).filter(|x| x % 2 == 0) { + P = (&P + &tables[i/2].select(a[i])).to_extended(); + } + + P + } +} + +impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable { + type Output = EdwardsPoint; + + /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by + /// computing the multiple \\(aB\\) of this basepoint \\(B\\). + fn mul(self, scalar: &'b Scalar) -> EdwardsPoint { + // delegate to a private function so that its documentation appears in internal docs + self.basepoint_mul(scalar) + } +} + +impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar { + type Output = EdwardsPoint; + + /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by + /// computing the multiple \\(aB\\) of this basepoint \\(B\\). + fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> EdwardsPoint { + basepoint_table * self + } +} + +impl EdwardsBasepointTable { + /// Create a table of precomputed multiples of `basepoint`. + pub fn create(basepoint: &EdwardsPoint) -> EdwardsBasepointTable { + // XXX use init_with + let mut table = EdwardsBasepointTable([LookupTable::default(); 32]); + let mut P = *basepoint; + for i in 0..32 { + // P = (16^2)^i * B + table.0[i] = LookupTable::from(&P); + P = P.mul_by_pow_2(8); + } + table + } + + /// Get the basepoint for this table as an `EdwardsPoint`. + pub fn basepoint(&self) -> EdwardsPoint { + // self.0[0].select(1) = 1*(16^2)^0*B + // but as an `AffineNielsPoint`, so add identity to convert to extended. + (&EdwardsPoint::identity() + &self.0[0].select(1)).to_extended() + } +} + +impl EdwardsPoint { + /// Multiply by the cofactor: return \\([8]P\\). + pub fn mul_by_cofactor(&self) -> EdwardsPoint { + self.mul_by_pow_2(3) + } + + /// Compute \\([2\^k] P \\) by successive doublings. Requires \\( k > 0 \\). + pub(crate) fn mul_by_pow_2(&self, k: u32) -> EdwardsPoint { + debug_assert!( k > 0 ); + let mut r: CompletedPoint; + let mut s = self.to_projective(); + for _ in 0..(k-1) { + r = s.double(); s = r.to_projective(); + } + // Unroll last iteration so we can go directly to_extended() + s.double().to_extended() + } + + /// Determine if this point is of small order. + /// + /// # Return + /// + /// * `true` if `self` is in the torsion subgroup \\( \mathcal E[8] \\); + /// * `false` if `self` is not in the torsion subgroup \\( \mathcal E[8] \\). + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::constants; + /// + /// // Generator of the prime-order subgroup + /// let P = constants::ED25519_BASEPOINT_POINT; + /// // Generator of the torsion subgroup + /// let Q = constants::EIGHT_TORSION[1]; + /// + /// // P has large order + /// assert_eq!(P.is_small_order(), false); + /// + /// // Q has small order + /// assert_eq!(Q.is_small_order(), true); + /// ``` + pub fn is_small_order(&self) -> bool { + self.mul_by_cofactor().is_identity() + } + + /// Determine if this point is “torsion-free”, i.e., is contained in + /// the prime-order subgroup. + /// + /// # Return + /// + /// * `true` if `self` has zero torsion component and is in the + /// prime-order subgroup; + /// * `false` if `self` has a nonzero torsion component and is not + /// in the prime-order subgroup. + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::constants; + /// + /// // Generator of the prime-order subgroup + /// let P = constants::ED25519_BASEPOINT_POINT; + /// // Generator of the torsion subgroup + /// let Q = constants::EIGHT_TORSION[1]; + /// + /// // P is torsion-free + /// assert_eq!(P.is_torsion_free(), true); + /// + /// // P + Q is not torsion-free + /// assert_eq!((P+Q).is_torsion_free(), false); + /// ``` + pub fn is_torsion_free(&self) -> bool { + (self * constants::BASEPOINT_ORDER).is_identity() + } +} + +// ------------------------------------------------------------------------ +// Debug traits +// ------------------------------------------------------------------------ + +impl Debug for EdwardsPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "EdwardsPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", + &self.X, &self.Y, &self.Z, &self.T) + } +} + +impl Debug for EdwardsBasepointTable { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "EdwardsBasepointTable([\n")?; + for i in 0..32 { + write!(f, "\t{:?},\n", &self.0[i])?; + } + write!(f, "])") + } +} + +// ------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------ + +#[cfg(test)] +mod test { + use field::FieldElement; + use scalar::Scalar; + use subtle::ConditionallySelectable; + use constants; + use super::*; + + /// X coordinate of the basepoint. + /// = 15112221349535400772501151409588531511454012693041857206046113283949847762202 + static BASE_X_COORD_BYTES: [u8; 32] = + [0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, + 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21]; + + /// Compressed Edwards Y form of 2*basepoint. + static BASE2_CMPRSSD: CompressedEdwardsY = + CompressedEdwardsY([0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0xe, + 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97, + 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, + 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22]); + + /// Compressed Edwards Y form of 16*basepoint. + static BASE16_CMPRSSD: CompressedEdwardsY = + CompressedEdwardsY([0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, + 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0, + 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, + 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70]); + + /// 4493907448824000747700850167940867464579944529806937181821189941592931634714 + pub static A_SCALAR: Scalar = Scalar{ + bytes: [ + 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, + 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d, + 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, + 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09, + ], + }; + + /// 2506056684125797857694181776241676200180934651973138769173342316833279714961 + pub static B_SCALAR: Scalar = Scalar{ + bytes: [ + 0x91, 0x26, 0x7a, 0xcf, 0x25, 0xc2, 0x09, 0x1b, + 0xa2, 0x17, 0x74, 0x7b, 0x66, 0xf0, 0xb3, 0x2e, + 0x9d, 0xf2, 0xa5, 0x67, 0x41, 0xcf, 0xda, 0xc4, + 0x56, 0xa7, 0xd4, 0xaa, 0xb8, 0x60, 0x8a, 0x05, + ], + }; + + /// A_SCALAR * basepoint, computed with ed25519.py + pub static A_TIMES_BASEPOINT: CompressedEdwardsY = CompressedEdwardsY([ + 0xea, 0x27, 0xe2, 0x60, 0x53, 0xdf, 0x1b, 0x59, + 0x56, 0xf1, 0x4d, 0x5d, 0xec, 0x3c, 0x34, 0xc3, + 0x84, 0xa2, 0x69, 0xb7, 0x4c, 0xc3, 0x80, 0x3e, + 0xa8, 0xe2, 0xe7, 0xc9, 0x42, 0x5e, 0x40, 0xa5]); + + /// A_SCALAR * (A_TIMES_BASEPOINT) + B_SCALAR * BASEPOINT + /// computed with ed25519.py + static DOUBLE_SCALAR_MULT_RESULT: CompressedEdwardsY = CompressedEdwardsY([ + 0x7d, 0xfd, 0x6c, 0x45, 0xaf, 0x6d, 0x6e, 0x0e, + 0xba, 0x20, 0x37, 0x1a, 0x23, 0x64, 0x59, 0xc4, + 0xc0, 0x46, 0x83, 0x43, 0xde, 0x70, 0x4b, 0x85, + 0x09, 0x6f, 0xfe, 0x35, 0x4f, 0x13, 0x2b, 0x42]); + + /// Test round-trip decompression for the basepoint. + #[test] + fn basepoint_decompression_compression() { + let base_X = FieldElement::from_bytes(&BASE_X_COORD_BYTES); + let bp = constants::ED25519_BASEPOINT_COMPRESSED.decompress().unwrap(); + assert!(bp.is_valid()); + // Check that decompression actually gives the correct X coordinate + assert_eq!(base_X, bp.X); + assert_eq!(bp.compress(), constants::ED25519_BASEPOINT_COMPRESSED); + } + + /// Test sign handling in decompression + #[test] + fn decompression_sign_handling() { + // Manually set the high bit of the last byte to flip the sign + let mut minus_basepoint_bytes = constants::ED25519_BASEPOINT_COMPRESSED.as_bytes().clone(); + minus_basepoint_bytes[31] |= 1 << 7; + let minus_basepoint = CompressedEdwardsY(minus_basepoint_bytes) + .decompress().unwrap(); + // Test projective coordinates exactly since we know they should + // only differ by a flipped sign. + assert_eq!(minus_basepoint.X, -(&constants::ED25519_BASEPOINT_POINT.X)); + assert_eq!(minus_basepoint.Y, constants::ED25519_BASEPOINT_POINT.Y); + assert_eq!(minus_basepoint.Z, constants::ED25519_BASEPOINT_POINT.Z); + assert_eq!(minus_basepoint.T, -(&constants::ED25519_BASEPOINT_POINT.T)); + } + + /// Test that computing 1*basepoint gives the correct basepoint. + #[test] + fn basepoint_mult_one_vs_basepoint() { + let bp = &constants::ED25519_BASEPOINT_TABLE * &Scalar::one(); + let compressed = bp.compress(); + assert_eq!(compressed, constants::ED25519_BASEPOINT_COMPRESSED); + } + + /// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint. + #[test] + fn basepoint_table_basepoint_function_correct() { + let bp = constants::ED25519_BASEPOINT_TABLE.basepoint(); + assert_eq!(bp.compress(), constants::ED25519_BASEPOINT_COMPRESSED); + } + + /// Test `impl Add for EdwardsPoint` + /// using basepoint + basepoint versus the 2*basepoint constant. + #[test] + fn basepoint_plus_basepoint_vs_basepoint2() { + let bp = constants::ED25519_BASEPOINT_POINT; + let bp_added = &bp + &bp; + assert_eq!(bp_added.compress(), BASE2_CMPRSSD); + } + + /// Test `impl Add for EdwardsPoint` + /// using the basepoint, basepoint2 constants + #[test] + fn basepoint_plus_basepoint_projective_niels_vs_basepoint2() { + let bp = constants::ED25519_BASEPOINT_POINT; + let bp_added = (&bp + &bp.to_projective_niels()).to_extended(); + assert_eq!(bp_added.compress(), BASE2_CMPRSSD); + } + + /// Test `impl Add for EdwardsPoint` + /// using the basepoint, basepoint2 constants + #[test] + fn basepoint_plus_basepoint_affine_niels_vs_basepoint2() { + let bp = constants::ED25519_BASEPOINT_POINT; + let bp_affine_niels = bp.to_affine_niels(); + let bp_added = (&bp + &bp_affine_niels).to_extended(); + assert_eq!(bp_added.compress(), BASE2_CMPRSSD); + } + + /// Check that equality of `EdwardsPoints` handles projective + /// coordinates correctly. + #[test] + fn extended_point_equality_handles_scaling() { + let mut two_bytes = [0u8; 32]; two_bytes[0] = 2; + let id1 = EdwardsPoint::identity(); + let id2 = EdwardsPoint{ + X: FieldElement::zero(), + Y: FieldElement::from_bytes(&two_bytes), + Z: FieldElement::from_bytes(&two_bytes), + T: FieldElement::zero() + }; + assert_eq!(id1.ct_eq(&id2).unwrap_u8(), 1u8); + } + + /// Sanity check for conversion to precomputed points + #[test] + fn to_affine_niels_clears_denominators() { + // construct a point as aB so it has denominators (ie. Z != 1) + let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; + let aB_affine_niels = aB.to_affine_niels(); + let also_aB = (&EdwardsPoint::identity() + &aB_affine_niels).to_extended(); + assert_eq!( aB.compress(), + also_aB.compress()); + } + + /// Test basepoint_mult versus a known scalar multiple from ed25519.py + #[test] + fn basepoint_mult_vs_ed25519py() { + let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; + assert_eq!(aB.compress(), A_TIMES_BASEPOINT); + } + + /// Test that multiplication by the basepoint order kills the basepoint + #[test] + fn basepoint_mult_by_basepoint_order() { + let B = &constants::ED25519_BASEPOINT_TABLE; + let should_be_id = B * &constants::BASEPOINT_ORDER; + assert!(should_be_id.is_identity()); + } + + /// Test precomputed basepoint mult + #[test] + fn test_precomputed_basepoint_mult() { + let aB_1 = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; + let aB_2 = &constants::ED25519_BASEPOINT_POINT * &A_SCALAR; + assert_eq!(aB_1.compress(), aB_2.compress()); + } + + /// Test scalar_mul versus a known scalar multiple from ed25519.py + #[test] + fn scalar_mul_vs_ed25519py() { + let aB = &constants::ED25519_BASEPOINT_POINT * &A_SCALAR; + assert_eq!(aB.compress(), A_TIMES_BASEPOINT); + } + + /// Test basepoint.double() versus the 2*basepoint constant. + #[test] + fn basepoint_double_vs_basepoint2() { + assert_eq!(constants::ED25519_BASEPOINT_POINT.double().compress(), + BASE2_CMPRSSD); + } + + /// Test that computing 2*basepoint is the same as basepoint.double() + #[test] + fn basepoint_mult_two_vs_basepoint2() { + let two = Scalar::from(2u64); + let bp2 = &constants::ED25519_BASEPOINT_TABLE * &two; + assert_eq!(bp2.compress(), BASE2_CMPRSSD); + } + + /// Check that converting to projective and then back to extended round-trips. + #[test] + fn basepoint_projective_extended_round_trip() { + assert_eq!(constants::ED25519_BASEPOINT_POINT + .to_projective().to_extended().compress(), + constants::ED25519_BASEPOINT_COMPRESSED); + } + + /// Test computing 16*basepoint vs mul_by_pow_2(4) + #[test] + fn basepoint16_vs_mul_by_pow_2_4() { + let bp16 = constants::ED25519_BASEPOINT_POINT.mul_by_pow_2(4); + assert_eq!(bp16.compress(), BASE16_CMPRSSD); + } + + #[test] + fn impl_sum() { + + // Test that sum works for non-empty iterators + let BASE = constants::ED25519_BASEPOINT_POINT; + + let s1 = Scalar::from(999u64); + let P1 = &BASE * &s1; + + let s2 = Scalar::from(333u64); + let P2 = &BASE * &s2; + + let vec = vec![P1.clone(), P2.clone()]; + let sum: EdwardsPoint = vec.iter().sum(); + + assert_eq!(sum, P1 + P2); + + // Test that sum works for the empty iterator + let empty_vector: Vec = vec![]; + let sum: EdwardsPoint = empty_vector.iter().sum(); + + assert_eq!(sum, EdwardsPoint::identity()); + + // Test that sum works on owning iterators + let s = Scalar::from(2u64); + let mapped = vec.iter().map(|x| x * s); + let sum: EdwardsPoint = mapped.sum(); + + assert_eq!(sum, &P1 * &s + &P2 * &s); + } + + + /// Test that the conditional assignment trait works for AffineNielsPoints. + #[test] + fn conditional_assign_for_affine_niels_point() { + let id = AffineNielsPoint::identity(); + let mut p1 = AffineNielsPoint::identity(); + let bp = constants::ED25519_BASEPOINT_POINT.to_affine_niels(); + + p1.conditional_assign(&bp, Choice::from(0)); + assert_eq!(p1, id); + p1.conditional_assign(&bp, Choice::from(1)); + assert_eq!(p1, bp); + } + + #[test] + fn is_small_order() { + // The basepoint has large prime order + assert!(!constants::ED25519_BASEPOINT_POINT.is_small_order()); + // constants::EIGHT_TORSION has all points of small order. + for torsion_point in &constants::EIGHT_TORSION { + assert!(torsion_point.is_small_order()); + } + } + + #[test] + fn compressed_identity() { + assert_eq!(EdwardsPoint::identity().compress(), + CompressedEdwardsY::identity()); + } + + #[test] + fn is_identity() { + assert!( EdwardsPoint::identity().is_identity()); + assert!(!constants::ED25519_BASEPOINT_POINT.is_identity()); + } + + /// Rust's debug builds have overflow and underflow trapping, + /// and enable `debug_assert!()`. This performs many scalar + /// multiplications to attempt to trigger possible overflows etc. + /// + /// For instance, the `u64` `Mul` implementation for + /// `FieldElements` requires the input `Limb`s to be bounded by + /// 2^54, but we cannot enforce this dynamically at runtime, or + /// statically at compile time (until Rust gets type-level + /// integers, at which point we can encode "bits of headroom" into + /// the type system and prove correctness). + #[test] + fn monte_carlo_overflow_underflow_debug_assert_test() { + let mut P = constants::ED25519_BASEPOINT_POINT; + // N.B. each scalar_mul does 1407 field mults, 1024 field squarings, + // so this does ~ 1M of each operation. + for _ in 0..1_000 { + P *= &A_SCALAR; + } + } + + #[test] + fn scalarmult_extended_point_works_both_ways() { + let G: EdwardsPoint = constants::ED25519_BASEPOINT_POINT; + let s: Scalar = A_SCALAR; + + let P1 = &G * &s; + let P2 = &s * &G; + + assert!(P1.compress().to_bytes() == P2.compress().to_bytes()); + } + + // A single iteration of a consistency check for MSM. + fn multiscalar_consistency_iter(n: usize) { + use core::iter; + let mut rng = rand::thread_rng(); + + // Construct random coefficients x0, ..., x_{n-1}, + // followed by some extra hardcoded ones. + let xs = (0..n) + .map(|_| Scalar::random(&mut rng)) + // The largest scalar allowed by the type system, 2^255-1 + .chain(iter::once(Scalar::from_bits([0xff; 32]))) + .collect::>(); + let check = xs.iter() + .map(|xi| xi * xi) + .sum::(); + + // Construct points G_i = x_i * B + let Gs = xs.iter() + .map(|xi| xi * &constants::ED25519_BASEPOINT_TABLE) + .collect::>(); + + // Compute H1 = (consttime) + let H1 = EdwardsPoint::multiscalar_mul(&xs, &Gs); + // Compute H2 = (vartime) + let H2 = EdwardsPoint::vartime_multiscalar_mul(&xs, &Gs); + // Compute H3 = = sum(xi^2) * B + let H3 = &check * &constants::ED25519_BASEPOINT_TABLE; + + assert_eq!(H1, H3); + assert_eq!(H2, H3); + } + + // Use different multiscalar sizes to hit different internal + // parameters. + + #[test] + fn multiscalar_consistency_n_100() { + let iters = 50; + for _ in 0..iters { + multiscalar_consistency_iter(100); + } + } + + #[test] + fn multiscalar_consistency_n_250() { + let iters = 50; + for _ in 0..iters { + multiscalar_consistency_iter(250); + } + } + + #[test] + fn multiscalar_consistency_n_500() { + let iters = 50; + for _ in 0..iters { + multiscalar_consistency_iter(500); + } + } + + #[test] + fn multiscalar_consistency_n_1000() { + let iters = 50; + for _ in 0..iters { + multiscalar_consistency_iter(1000); + } + } + + #[test] + fn vartime_precomputed_vs_nonprecomputed_multiscalar() { + let mut rng = rand::thread_rng(); + + let B = &::constants::ED25519_BASEPOINT_TABLE; + + let static_scalars = (0..128) + .map(|_| Scalar::random(&mut rng)) + .collect::>(); + + let dynamic_scalars = (0..128) + .map(|_| Scalar::random(&mut rng)) + .collect::>(); + + let check_scalar: Scalar = static_scalars + .iter() + .chain(dynamic_scalars.iter()) + .map(|s| s * s) + .sum(); + + let static_points = static_scalars.iter().map(|s| s * B).collect::>(); + let dynamic_points = dynamic_scalars.iter().map(|s| s * B).collect::>(); + + let precomputation = VartimeEdwardsPrecomputation::new(static_points.iter()); + + let P = precomputation.vartime_mixed_multiscalar_mul( + &static_scalars, + &dynamic_scalars, + &dynamic_points, + ); + + use traits::VartimeMultiscalarMul; + let Q = EdwardsPoint::vartime_multiscalar_mul( + static_scalars.iter().chain(dynamic_scalars.iter()), + static_points.iter().chain(dynamic_points.iter()), + ); + + let R = &check_scalar * B; + + assert_eq!(P.compress(), R.compress()); + assert_eq!(Q.compress(), R.compress()); + } + + mod vartime { + use super::super::*; + use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT}; + + /// Test double_scalar_mul_vartime vs ed25519.py + #[test] + fn double_scalar_mul_basepoint_vs_ed25519py() { + let A = A_TIMES_BASEPOINT.decompress().unwrap(); + let result = EdwardsPoint::vartime_double_scalar_mul_basepoint(&A_SCALAR, &A, &B_SCALAR); + assert_eq!(result.compress(), DOUBLE_SCALAR_MULT_RESULT); + } + + #[test] + fn multiscalar_mul_vs_ed25519py() { + let A = A_TIMES_BASEPOINT.decompress().unwrap(); + let result = EdwardsPoint::vartime_multiscalar_mul( + &[A_SCALAR, B_SCALAR], + &[A, constants::ED25519_BASEPOINT_POINT] + ); + assert_eq!(result.compress(), DOUBLE_SCALAR_MULT_RESULT); + } + + #[test] + fn multiscalar_mul_vartime_vs_consttime() { + let A = A_TIMES_BASEPOINT.decompress().unwrap(); + let result_vartime = EdwardsPoint::vartime_multiscalar_mul( + &[A_SCALAR, B_SCALAR], + &[A, constants::ED25519_BASEPOINT_POINT] + ); + let result_consttime = EdwardsPoint::multiscalar_mul( + &[A_SCALAR, B_SCALAR], + &[A, constants::ED25519_BASEPOINT_POINT] + ); + + assert_eq!(result_vartime.compress(), result_consttime.compress()); + } + } + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_basepoint_roundtrip() { + use bincode; + + let encoded = bincode::serialize(&constants::ED25519_BASEPOINT_POINT).unwrap(); + let enc_compressed = bincode::serialize(&constants::ED25519_BASEPOINT_COMPRESSED).unwrap(); + assert_eq!(encoded, enc_compressed); + + // Check that the encoding is 32 bytes exactly + assert_eq!(encoded.len(), 32); + + let dec_uncompressed: EdwardsPoint = bincode::deserialize(&encoded).unwrap(); + let dec_compressed: CompressedEdwardsY = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(dec_uncompressed, constants::ED25519_BASEPOINT_POINT); + assert_eq!(dec_compressed, constants::ED25519_BASEPOINT_COMPRESSED); + + // Check that the encoding itself matches the usual one + let raw_bytes = constants::ED25519_BASEPOINT_COMPRESSED.as_bytes(); + let bp: EdwardsPoint = bincode::deserialize(raw_bytes).unwrap(); + assert_eq!(bp, constants::ED25519_BASEPOINT_POINT); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/field.rs new file mode 100644 index 0000000..54d048d --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/field.rs @@ -0,0 +1,460 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\). +//! +//! The `curve25519_dalek::field` module provides a type alias +//! `curve25519_dalek::field::FieldElement` to a field element type +//! defined in the `backend` module; either `FieldElement51` or +//! `FieldElement2625`. +//! +//! Field operations defined in terms of machine +//! operations, such as field multiplication or squaring, are defined in +//! the backend implementation. +//! +//! Field operations defined in terms of other field operations, such as +//! field inversion or square roots, are defined here. + +use core::cmp::{Eq, PartialEq}; + +use subtle::ConditionallySelectable; +use subtle::ConditionallyNegatable; +use subtle::Choice; +use subtle::ConstantTimeEq; + +use constants; +use backend; + +#[cfg(feature = "u64_backend")] +pub use backend::serial::u64::field::*; +/// A `FieldElement` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// The `FieldElement` type is an alias for one of the platform-specific +/// implementations. +#[cfg(feature = "u64_backend")] +pub type FieldElement = backend::serial::u64::field::FieldElement51; + +#[cfg(feature = "u32_backend")] +pub use backend::serial::u32::field::*; +/// A `FieldElement` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// The `FieldElement` type is an alias for one of the platform-specific +/// implementations. +#[cfg(feature = "u32_backend")] +pub type FieldElement = backend::serial::u32::field::FieldElement2625; + +impl Eq for FieldElement {} + +impl PartialEq for FieldElement { + fn eq(&self, other: &FieldElement) -> bool { + self.ct_eq(other).unwrap_u8() == 1u8 + } +} + +impl ConstantTimeEq for FieldElement { + /// Test equality between two `FieldElement`s. Since the + /// internal representation is not canonical, the field elements + /// are normalized to wire format before comparison. + fn ct_eq(&self, other: &FieldElement) -> Choice { + self.to_bytes().ct_eq(&other.to_bytes()) + } +} + +impl FieldElement { + /// Determine if this `FieldElement` is negative, in the sense + /// used in the ed25519 paper: `x` is negative if the low bit is + /// set. + /// + /// # Return + /// + /// If negative, return `Choice(1)`. Otherwise, return `Choice(0)`. + pub fn is_negative(&self) -> Choice { + let bytes = self.to_bytes(); + (bytes[0] & 1).into() + } + + /// Determine if this `FieldElement` is zero. + /// + /// # Return + /// + /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. + pub fn is_zero(&self) -> Choice { + let zero = [0u8; 32]; + let bytes = self.to_bytes(); + + bytes.ct_eq(&zero) + } + + /// Compute (self^(2^250-1), self^11), used as a helper function + /// within invert() and pow22523(). + fn pow22501(&self) -> (FieldElement, FieldElement) { + // Instead of managing which temporary variables are used + // for what, we define as many as we need and leave stack + // allocation to the compiler + // + // Each temporary variable t_i is of the form (self)^e_i. + // Squaring t_i corresponds to multiplying e_i by 2, + // so the pow2k function shifts e_i left by k places. + // Multiplying t_i and t_j corresponds to adding e_i + e_j. + // + // Temporary t_i Nonzero bits of e_i + // + let t0 = self.square(); // 1 e_0 = 2^1 + let t1 = t0.square().square(); // 3 e_1 = 2^3 + let t2 = self * &t1; // 3,0 e_2 = 2^3 + 2^0 + let t3 = &t0 * &t2; // 3,1,0 + let t4 = t3.square(); // 4,2,1 + let t5 = &t2 * &t4; // 4,3,2,1,0 + let t6 = t5.pow2k(5); // 9,8,7,6,5 + let t7 = &t6 * &t5; // 9,8,7,6,5,4,3,2,1,0 + let t8 = t7.pow2k(10); // 19..10 + let t9 = &t8 * &t7; // 19..0 + let t10 = t9.pow2k(20); // 39..20 + let t11 = &t10 * &t9; // 39..0 + let t12 = t11.pow2k(10); // 49..10 + let t13 = &t12 * &t7; // 49..0 + let t14 = t13.pow2k(50); // 99..50 + let t15 = &t14 * &t13; // 99..0 + let t16 = t15.pow2k(100); // 199..100 + let t17 = &t16 * &t15; // 199..0 + let t18 = t17.pow2k(50); // 249..50 + let t19 = &t18 * &t13; // 249..0 + + (t19, t3) + } + + /// Given a slice of public `FieldElements`, replace each with its inverse. + /// + /// All input `FieldElements` **MUST** be nonzero. + #[cfg(feature = "alloc")] + pub fn batch_invert(inputs: &mut [FieldElement]) { + // Montgomery’s Trick and Fast Implementation of Masked AES + // Genelle, Prouff and Quisquater + // Section 3.2 + + let n = inputs.len(); + let mut scratch = vec![FieldElement::one(); n]; + + // Keep an accumulator of all of the previous products + let mut acc = FieldElement::one(); + + // Pass through the input vector, recording the previous + // products in the scratch space + for (input, scratch) in inputs.iter().zip(scratch.iter_mut()) { + *scratch = acc; + acc = &acc * input; + } + + // acc is nonzero iff all inputs are nonzero + assert_eq!(acc.is_zero().unwrap_u8(), 0); + + // Compute the inverse of all products + acc = acc.invert(); + + // Pass through the vector backwards to compute the inverses + // in place + for (input, scratch) in inputs.iter_mut().rev().zip(scratch.into_iter().rev()) { + let tmp = &acc * input; + *input = &acc * &scratch; + acc = tmp; + } + } + + /// Given a nonzero field element, compute its inverse. + /// + /// The inverse is computed as self^(p-2), since + /// x^(p-2)x = x^(p-1) = 1 (mod p). + /// + /// This function returns zero on input zero. + pub fn invert(&self) -> FieldElement { + // The bits of p-2 = 2^255 -19 -2 are 11010111111...11. + // + // nonzero bits of exponent + let (t19, t3) = self.pow22501(); // t19: 249..0 ; t3: 3,1,0 + let t20 = t19.pow2k(5); // 254..5 + let t21 = &t20 * &t3; // 254..5,3,1,0 + + t21 + } + + /// Raise this field element to the power (p-5)/8 = 2^252 -3. + fn pow_p58(&self) -> FieldElement { + // The bits of (p-5)/8 are 101111.....11. + // + // nonzero bits of exponent + let (t19, _) = self.pow22501(); // 249..0 + let t20 = t19.pow2k(2); // 251..2 + let t21 = self * &t20; // 251..2,0 + + t21 + } + + /// Given `FieldElements` `u` and `v`, compute either `sqrt(u/v)` + /// or `sqrt(i*u/v)` in constant time. + /// + /// This function always returns the nonnegative square root. + /// + /// # Return + /// + /// - `(Choice(1), +sqrt(u/v)) ` if `v` is nonzero and `u/v` is square; + /// - `(Choice(1), zero) ` if `u` is zero; + /// - `(Choice(0), zero) ` if `v` is zero and `u` is nonzero; + /// - `(Choice(0), +sqrt(i*u/v))` if `u/v` is nonsquare (so `i*u/v` is square). + /// + pub fn sqrt_ratio_i(u: &FieldElement, v: &FieldElement) -> (Choice, FieldElement) { + // Using the same trick as in ed25519 decoding, we merge the + // inversion, the square root, and the square test as follows. + // + // To compute sqrt(α), we can compute β = α^((p+3)/8). + // Then β^2 = ±α, so multiplying β by sqrt(-1) if necessary + // gives sqrt(α). + // + // To compute 1/sqrt(α), we observe that + // 1/β = α^(p-1 - (p+3)/8) = α^((7p-11)/8) + // = α^3 * (α^7)^((p-5)/8). + // + // We can therefore compute sqrt(u/v) = sqrt(u)/sqrt(v) + // by first computing + // r = u^((p+3)/8) v^(p-1-(p+3)/8) + // = u u^((p-5)/8) v^3 (v^7)^((p-5)/8) + // = (uv^3) (uv^7)^((p-5)/8). + // + // If v is nonzero and u/v is square, then r^2 = ±u/v, + // so vr^2 = ±u. + // If vr^2 = u, then sqrt(u/v) = r. + // If vr^2 = -u, then sqrt(u/v) = r*sqrt(-1). + // + // If v is zero, r is also zero. + + let v3 = &v.square() * v; + let v7 = &v3.square() * v; + let mut r = &(u * &v3) * &(u * &v7).pow_p58(); + let check = v * &r.square(); + + let i = &constants::SQRT_M1; + + let correct_sign_sqrt = check.ct_eq( u); + let flipped_sign_sqrt = check.ct_eq( &(-u)); + let flipped_sign_sqrt_i = check.ct_eq(&(&(-u)*i)); + + let r_prime = &constants::SQRT_M1 * &r; + r.conditional_assign(&r_prime, flipped_sign_sqrt | flipped_sign_sqrt_i); + + // Choose the nonnegative square root. + let r_is_negative = r.is_negative(); + r.conditional_negate(r_is_negative); + + let was_nonzero_square = correct_sign_sqrt | flipped_sign_sqrt; + + (was_nonzero_square, r) + } + + /// Attempt to compute `sqrt(1/self)` in constant time. + /// + /// Convenience wrapper around `sqrt_ratio_i`. + /// + /// This function always returns the nonnegative square root. + /// + /// # Return + /// + /// - `(Choice(1), +sqrt(1/self)) ` if `self` is a nonzero square; + /// - `(Choice(0), zero) ` if `self` is zero; + /// - `(Choice(0), +sqrt(i/self)) ` if `self` is a nonzero nonsquare; + /// + pub fn invsqrt(&self) -> (Choice, FieldElement) { + FieldElement::sqrt_ratio_i(&FieldElement::one(), self) + } +} + +#[cfg(test)] +mod test { + use field::*; + use subtle::ConditionallyNegatable; + + /// Random element a of GF(2^255-19), from Sage + /// a = 1070314506888354081329385823235218444233221\ + /// 2228051251926706380353716438957572 + static A_BYTES: [u8; 32] = + [ 0x04, 0xfe, 0xdf, 0x98, 0xa7, 0xfa, 0x0a, 0x68, + 0x84, 0x92, 0xbd, 0x59, 0x08, 0x07, 0xa7, 0x03, + 0x9e, 0xd1, 0xf6, 0xf2, 0xe1, 0xd9, 0xe2, 0xa4, + 0xa4, 0x51, 0x47, 0x36, 0xf3, 0xc3, 0xa9, 0x17]; + + /// Byte representation of a**2 + static ASQ_BYTES: [u8; 32] = + [ 0x75, 0x97, 0x24, 0x9e, 0xe6, 0x06, 0xfe, 0xab, + 0x24, 0x04, 0x56, 0x68, 0x07, 0x91, 0x2d, 0x5d, + 0x0b, 0x0f, 0x3f, 0x1c, 0xb2, 0x6e, 0xf2, 0xe2, + 0x63, 0x9c, 0x12, 0xba, 0x73, 0x0b, 0xe3, 0x62]; + + /// Byte representation of 1/a + static AINV_BYTES: [u8; 32] = + [0x96, 0x1b, 0xcd, 0x8d, 0x4d, 0x5e, 0xa2, 0x3a, + 0xe9, 0x36, 0x37, 0x93, 0xdb, 0x7b, 0x4d, 0x70, + 0xb8, 0x0d, 0xc0, 0x55, 0xd0, 0x4c, 0x1d, 0x7b, + 0x90, 0x71, 0xd8, 0xe9, 0xb6, 0x18, 0xe6, 0x30]; + + /// Byte representation of a^((p-5)/8) + static AP58_BYTES: [u8; 32] = + [0x6a, 0x4f, 0x24, 0x89, 0x1f, 0x57, 0x60, 0x36, + 0xd0, 0xbe, 0x12, 0x3c, 0x8f, 0xf5, 0xb1, 0x59, + 0xe0, 0xf0, 0xb8, 0x1b, 0x20, 0xd2, 0xb5, 0x1f, + 0x15, 0x21, 0xf9, 0xe3, 0xe1, 0x61, 0x21, 0x55]; + + #[test] + fn a_mul_a_vs_a_squared_constant() { + let a = FieldElement::from_bytes(&A_BYTES); + let asq = FieldElement::from_bytes(&ASQ_BYTES); + assert_eq!(asq, &a * &a); + } + + #[test] + fn a_square_vs_a_squared_constant() { + let a = FieldElement::from_bytes(&A_BYTES); + let asq = FieldElement::from_bytes(&ASQ_BYTES); + assert_eq!(asq, a.square()); + } + + #[test] + fn a_square2_vs_a_squared_constant() { + let a = FieldElement::from_bytes(&A_BYTES); + let asq = FieldElement::from_bytes(&ASQ_BYTES); + assert_eq!(a.square2(), &asq+&asq); + } + + #[test] + fn a_invert_vs_inverse_of_a_constant() { + let a = FieldElement::from_bytes(&A_BYTES); + let ainv = FieldElement::from_bytes(&AINV_BYTES); + let should_be_inverse = a.invert(); + assert_eq!(ainv, should_be_inverse); + assert_eq!(FieldElement::one(), &a * &should_be_inverse); + } + + #[test] + fn batch_invert_a_matches_nonbatched() { + let a = FieldElement::from_bytes(&A_BYTES); + let ap58 = FieldElement::from_bytes(&AP58_BYTES); + let asq = FieldElement::from_bytes(&ASQ_BYTES); + let ainv = FieldElement::from_bytes(&AINV_BYTES); + let a2 = &a + &a; + let a_list = vec![a, ap58, asq, ainv, a2]; + let mut ainv_list = a_list.clone(); + FieldElement::batch_invert(&mut ainv_list[..]); + for i in 0..5 { + assert_eq!(a_list[i].invert(), ainv_list[i]); + } + } + + #[test] + fn sqrt_ratio_behavior() { + let zero = FieldElement::zero(); + let one = FieldElement::one(); + let i = constants::SQRT_M1; + let two = &one + &one; // 2 is nonsquare mod p. + let four = &two + &two; // 4 is square mod p. + + // 0/0 should return (1, 0) since u is 0 + let (choice, sqrt) = FieldElement::sqrt_ratio_i(&zero, &zero); + assert_eq!(choice.unwrap_u8(), 1); + assert_eq!(sqrt, zero); + assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + + // 1/0 should return (0, 0) since v is 0, u is nonzero + let (choice, sqrt) = FieldElement::sqrt_ratio_i(&one, &zero); + assert_eq!(choice.unwrap_u8(), 0); + assert_eq!(sqrt, zero); + assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + + // 2/1 is nonsquare, so we expect (0, sqrt(i*2)) + let (choice, sqrt) = FieldElement::sqrt_ratio_i(&two, &one); + assert_eq!(choice.unwrap_u8(), 0); + assert_eq!(sqrt.square(), &two * &i); + assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + + // 4/1 is square, so we expect (1, sqrt(4)) + let (choice, sqrt) = FieldElement::sqrt_ratio_i(&four, &one); + assert_eq!(choice.unwrap_u8(), 1); + assert_eq!(sqrt.square(), four); + assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + + // 1/4 is square, so we expect (1, 1/sqrt(4)) + let (choice, sqrt) = FieldElement::sqrt_ratio_i(&one, &four); + assert_eq!(choice.unwrap_u8(), 1); + assert_eq!(&sqrt.square() * &four, one); + assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + } + + #[test] + fn a_p58_vs_ap58_constant() { + let a = FieldElement::from_bytes(&A_BYTES); + let ap58 = FieldElement::from_bytes(&AP58_BYTES); + assert_eq!(ap58, a.pow_p58()); + } + + #[test] + fn equality() { + let a = FieldElement::from_bytes(&A_BYTES); + let ainv = FieldElement::from_bytes(&AINV_BYTES); + assert!(a == a); + assert!(a != ainv); + } + + /// Notice that the last element has the high bit set, which + /// should be ignored + static B_BYTES: [u8;32] = + [113, 191, 169, 143, 91, 234, 121, 15, + 241, 131, 217, 36, 230, 101, 92, 234, + 8, 208, 170, 251, 97, 127, 70, 210, + 58, 23, 166, 87, 240, 169, 184, 178]; + + #[test] + fn from_bytes_highbit_is_ignored() { + let mut cleared_bytes = B_BYTES; + cleared_bytes[31] &= 127u8; + let with_highbit_set = FieldElement::from_bytes(&B_BYTES); + let without_highbit_set = FieldElement::from_bytes(&cleared_bytes); + assert_eq!(without_highbit_set, with_highbit_set); + } + + #[test] + fn conditional_negate() { + let one = FieldElement::one(); + let minus_one = FieldElement::minus_one(); + let mut x = one; + x.conditional_negate(Choice::from(1)); + assert_eq!(x, minus_one); + x.conditional_negate(Choice::from(0)); + assert_eq!(x, minus_one); + x.conditional_negate(Choice::from(1)); + assert_eq!(x, one); + } + + #[test] + fn encoding_is_canonical() { + // Encode 1 wrongly as 1 + (2^255 - 19) = 2^255 - 18 + let one_encoded_wrongly_bytes: [u8;32] = [0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]; + // Decode to a field element + let one = FieldElement::from_bytes(&one_encoded_wrongly_bytes); + // .. then check that the encoding is correct + let one_bytes = one.to_bytes(); + assert_eq!(one_bytes[0], 1); + for i in 1..32 { + assert_eq!(one_bytes[i], 0); + } + } + + #[test] + fn batch_invert_empty() { + FieldElement::batch_invert(&mut []); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lib.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lib.rs new file mode 100644 index 0000000..605662a --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lib.rs @@ -0,0 +1,100 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +#![no_std] +#![cfg_attr(feature = "nightly", feature(test))] +#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))] +#![cfg_attr(feature = "nightly", feature(external_doc))] +#![cfg_attr(feature = "nightly", feature(doc_cfg))] +#![cfg_attr(feature = "simd_backend", feature(stdsimd))] +// Refuse to compile if documentation is missing, but only on nightly. +// +// This means that missing docs will still fail CI, but means we can use +// README.md as the crate documentation. +//#![cfg_attr(feature = "nightly", deny(missing_docs))] + +#![cfg_attr(feature = "nightly", doc(include = "../README.md"))] +#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] + +//! Note that docs will only build on nightly Rust until +//! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732). + +//------------------------------------------------------------------------ +// External dependencies: +//------------------------------------------------------------------------ + +#[cfg(all(feature = "alloc", not(feature = "std")))] +#[macro_use] +extern crate alloc; + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; + +#[cfg(all(feature = "nightly", feature = "packed_simd"))] +extern crate packed_simd; + +extern crate byteorder; +pub extern crate digest; +extern crate rand_core; +extern crate zeroize; + +// Used for traits related to constant-time code. +pub extern crate subtle; + +#[cfg(all(test, feature = "serde"))] +extern crate bincode; +#[cfg(feature = "serde")] +extern crate serde; + +// Internal macros. Must come first! +#[macro_use] +pub(crate) mod macros; + +//------------------------------------------------------------------------ +// curve25519-dalek public modules +//------------------------------------------------------------------------ + +// Scalar arithmetic mod l = 2^252 + ..., the order of the Ristretto group +pub mod scalar; + +// Point operations on the Montgomery form of Curve25519 +pub mod montgomery; + +// Point operations on the Edwards form of Curve25519 +pub mod edwards; + +// Group operations on the Ristretto group +pub mod ristretto; + +// Useful constants, like the Ed25519 basepoint +pub mod constants; + +// External (and internal) traits. +pub mod traits; + +// All the lizard code is here, for now +pub mod lizard; + +//------------------------------------------------------------------------ +// curve25519-dalek internal modules +//------------------------------------------------------------------------ + +// Finite field arithmetic mod p = 2^255 - 19 +pub mod field; + +// Arithmetic backends (using u32, u64, etc) live here +pub(crate) mod backend; + +// Crate-local prelude (for alloc-dependent features like `Vec`) +pub(crate) mod prelude; + +// Generic code for window lookups +pub(crate) mod window; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/LICENSE b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/LICENSE new file mode 100644 index 0000000..2df7c96 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Bas Westerbaan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/jacobi_quartic.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/jacobi_quartic.rs new file mode 100644 index 0000000..9ede5d3 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/jacobi_quartic.rs @@ -0,0 +1,74 @@ +//! Helper functions for use with Lizard + +#![allow(non_snake_case)] + +use subtle::Choice; +use subtle::ConstantTimeEq; +use subtle::ConditionallyNegatable; +use subtle::ConditionallySelectable; + +use constants; +use lizard::lizard_constants; + +use field::FieldElement; + + +/// Represents a point (s,t) on the the Jacobi quartic associated +/// to the Edwards curve. +#[derive(Copy, Clone)] +#[allow(missing_docs)] +pub struct JacobiPoint { + pub S: FieldElement, + pub T: FieldElement, +} + +impl JacobiPoint { + /// Elligator2 is defined in two steps: first a field element is converted + /// to a point (s,t) on the Jacobi quartic associated to the Edwards curve. + /// Then this point is mapped to a point on the Edwards curve. + /// This function computes a field element that is mapped to a given (s,t) + /// with Elligator2 if it exists. + pub(crate) fn elligator_inv(&self) -> (Choice, FieldElement) { + let mut out = FieldElement::zero(); + + // Special case: s = 0. If s is zero, either t = 1 or t = -1. + // If t=1, then sqrt(i*d) is the preimage. Otherwise it's 0. + let s_is_zero = self.S.is_zero(); + let t_equals_one = self.T.ct_eq(&FieldElement::one()); + out.conditional_assign(&lizard_constants::SQRT_ID, t_equals_one); + let mut ret = s_is_zero; + let mut done = s_is_zero; + + // a := (t+1) (d+1)/(d-1) + let a = &(&self.T + &FieldElement::one()) * &lizard_constants::DP1_OVER_DM1; + let a2 = a.square(); + + // y := 1/sqrt(i (s^4 - a^2)). + let s2 = self.S.square(); + let s4 = s2.square(); + let invSqY = &(&s4 - &a2) * &constants::SQRT_M1; + + // There is no preimage if the square root of i*(s^4-a^2) does not exist. + let (sq, y) = invSqY.invsqrt(); + ret |= sq; + done |= !sq; + + // x := (a + sign(s)*s^2) y + let mut pms2 = s2; + pms2.conditional_negate(self.S.is_negative()); + let mut x = &(&a + &pms2) * &y; + let x_is_negative = x.is_negative(); + x.conditional_negate(x_is_negative); + out.conditional_assign(&x, !done); + + (ret, out) + } + + pub(crate) fn dual(&self) -> JacobiPoint { + JacobiPoint { + S: -(&self.S), + T: -(&self.T), + } + } +} + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/lizard_constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/lizard_constants.rs new file mode 100644 index 0000000..beb8882 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/lizard_constants.rs @@ -0,0 +1,54 @@ +//! Constants for use in Lizard +//! +//! Could be moved into backend/serial/u??/constants.rs + +#[cfg(feature = "u64_backend")] +pub(crate) use lizard::u64_constants::*; + +#[cfg(feature = "u32_backend")] +pub(crate) use lizard::u32_constants::*; + + +// ------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------ + +#[cfg(all(test, feature = "stage2_build"))] +mod test { + + use super::*; + use constants; + use field::FieldElement; + + #[test] + fn test_lizard_constants() { + let (_, sqrt_id) = FieldElement::sqrt_ratio_i( + &(&constants::SQRT_M1 * &constants::EDWARDS_D), + &FieldElement::one() + ); + assert_eq!(sqrt_id, SQRT_ID); + + assert_eq!( + &(&constants::EDWARDS_D + &FieldElement::one()) + * &(&constants::EDWARDS_D - &FieldElement::one()).invert(), + DP1_OVER_DM1 + ); + + assert_eq!( + MDOUBLE_INVSQRT_A_MINUS_D, + -&(&constants::INVSQRT_A_MINUS_D + &constants::INVSQRT_A_MINUS_D) + ); + + assert_eq!( + MIDOUBLE_INVSQRT_A_MINUS_D, + &MDOUBLE_INVSQRT_A_MINUS_D * &constants::SQRT_M1 + ); + + let (_, invsqrt_one_plus_d) = ( + &constants::EDWARDS_D + &FieldElement::one()).invsqrt(); + assert_eq!( + -&invsqrt_one_plus_d, + MINVSQRT_ONE_PLUS_D + ); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/lizard_ristretto.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/lizard_ristretto.rs new file mode 100644 index 0000000..b240d0e --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/lizard_ristretto.rs @@ -0,0 +1,305 @@ +//! Defines additional methods on RistrettoPoint for Lizard + +#![allow(non_snake_case)] + +use digest::Digest; +use digest::generic_array::typenum::U32; + +use constants; +use field::FieldElement; + +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; +use subtle::Choice; + +use edwards::EdwardsPoint; + +use lizard::jacobi_quartic::JacobiPoint; +use lizard::lizard_constants; + +#[allow(unused_imports)] +use prelude::*; +use ristretto::RistrettoPoint; + + +impl RistrettoPoint { + + pub fn from_uniform_bytes_single_elligator(bytes: &[u8; 32]) -> RistrettoPoint { + RistrettoPoint::elligator_ristretto_flavor(&FieldElement::from_bytes(&bytes)) + } + + /// Encode 16 bytes of data to a RistrettoPoint, using the Lizard method + pub fn lizard_encode(data: &[u8; 16]) -> RistrettoPoint + where D: Digest + { + let mut fe_bytes: [u8;32] = Default::default(); + + let digest = D::digest(data); + fe_bytes[0..32].copy_from_slice(digest.as_slice()); + fe_bytes[8..24].copy_from_slice(data); + fe_bytes[0] &= 254; // make positive since Elligator on r and -r is the same + fe_bytes[31] &= 63; + let fe = FieldElement::from_bytes(&fe_bytes); + RistrettoPoint::elligator_ristretto_flavor(&fe) + } + + /// Decode 16 bytes of data from a RistrettoPoint, using the Lizard method + pub fn lizard_decode(&self) -> Option<[u8; 16]> + where D: Digest + { + let mut result: [u8; 16] = Default::default(); + let mut h: [u8;32] = Default::default(); + let (mask, fes) = self.elligator_ristretto_flavor_inverse(); + let mut n_found = 0; + for j in 0..8 { + let mut ok = Choice::from((mask >> j) & 1); + let buf2 = fes[j].to_bytes(); // array + h.copy_from_slice(&D::digest(&buf2[8..24])); // array + h[8..24].copy_from_slice(&buf2[8..24]); + h[0] &= 254; + h[31] &= 63; + ok &= h.ct_eq(&buf2); + for i in 0..16 { + result[i] = u8::conditional_select(&result[i], &buf2[8+i], ok); + } + n_found += ok.unwrap_u8(); + } + if n_found == 1 { + return Some(result); + } + else { + return None; + } + } + + pub fn encode_253_bits(data: &[u8; 32]) -> Option + { + if data.len() != 32 { + return None; + } + + let fe = FieldElement::from_bytes(data); + let p = RistrettoPoint::elligator_ristretto_flavor(&fe); + Some(p) + } + + + pub fn decode_253_bits(&self) -> (u8, [[u8; 32]; 8]) + { + let mut ret = [ [0u8; 32]; 8]; + let (mask, fes) = self.elligator_ristretto_flavor_inverse(); + + for j in 0..8 { + ret[j] = fes[j].to_bytes(); + } + (mask, ret) + } + + /// Return the coset self + E[4], for debugging. + pub fn xcoset4(&self) -> [EdwardsPoint; 4] { + [ self.0 + , &self.0 + &constants::EIGHT_TORSION[2] + , &self.0 + &constants::EIGHT_TORSION[4] + , &self.0 + &constants::EIGHT_TORSION[6] + ] + } + + /// Computes the at most 8 positive FieldElements f such that + /// self == elligator_ristretto_flavor(f). + /// Assumes self is even. + /// + /// Returns a bitmask of which elements in fes are set. + pub fn elligator_ristretto_flavor_inverse(&self) -> (u8, [FieldElement; 8]) { + // Elligator2 computes a Point from a FieldElement in two steps: first + // it computes a (s,t) on the Jacobi quartic and then computes the + // corresponding even point on the Edwards curve. + // + // We invert in three steps. Any Ristretto point has four representatives + // as even Edwards points. For each of those even Edwards points, + // there are two points on the Jacobi quartic that map to it. + // Each of those eight points on the Jacobi quartic might have an + // Elligator2 preimage. + // + // Essentially we first loop over the four representatives of our point, + // then for each of them consider both points on the Jacobi quartic and + // check whether they have an inverse under Elligator2. We take the + // following shortcut though. + // + // We can compute two Jacobi quartic points for (x,y) and (-x,-y) + // at the same time. The four Jacobi quartic points are two of + // such pairs. + + let mut mask : u8 = 0; + let jcs = self.to_jacobi_quartic_ristretto(); + let mut ret = [FieldElement::one(); 8]; + + for i in 0..4 { + let (ok, fe) = jcs[i].elligator_inv(); + let mut tmp : u8 = 0; + ret[2*i] = fe; + tmp.conditional_assign(&1, ok); + mask |= tmp << (2 * i); + + let jc = jcs[i].dual(); + let (ok, fe) = jc.elligator_inv(); + let mut tmp : u8 = 0; + ret[2*i+1] = fe; + tmp.conditional_assign(&1, ok); + mask |= tmp << (2 * i + 1); + } + + return (mask, ret) + } + + /// Find a point on the Jacobi quartic associated to each of the four + /// points Ristretto equivalent to p. + /// + /// There is one exception: for (0,-1) there is no point on the quartic and + /// so we repeat one on the quartic equivalent to (0,1). + fn to_jacobi_quartic_ristretto(&self) -> [JacobiPoint; 4] { + let x2 = self.0.X.square(); // X^2 + let y2 = self.0.Y.square(); // Y^2 + let y4 = y2.square(); // Y^4 + let z2 = self.0.Z.square(); // Z^2 + let z_min_y = &self.0.Z - &self.0.Y; // Z - Y + let z_pl_y = &self.0.Z + &self.0.Y; // Z + Y + let z2_min_y2 = &z2 - &y2; // Z^2 - Y^2 + + // gamma := 1/sqrt( Y^4 X^2 (Z^2 - Y^2) ) + let (_, gamma) = (&(&y4 * &x2) * &z2_min_y2).invsqrt(); + + let den = &gamma * &y2; + + let s_over_x = &den * &z_min_y; + let sp_over_xp = &den * &z_pl_y; + + let s0 = &s_over_x * &self.0.X; + let s1 = &(-(&sp_over_xp)) * &self.0.X; + + // t_0 := -2/sqrt(-d-1) * Z * sOverX + // t_1 := -2/sqrt(-d-1) * Z * spOverXp + let tmp = &lizard_constants::MDOUBLE_INVSQRT_A_MINUS_D * &self.0.Z; + let mut t0 = &tmp * &s_over_x; + let mut t1 = &tmp * &sp_over_xp; + + // den := -1/sqrt(1+d) (Y^2 - Z^2) gamma + let den = &(&(-(&z2_min_y2)) * &lizard_constants::MINVSQRT_ONE_PLUS_D) * γ + + // Same as before but with the substitution (X, Y, Z) = (Y, X, i*Z) + let iz = &constants::SQRT_M1 * &self.0.Z; // iZ + let iz_min_x = &iz - &self.0.X; // iZ - X + let iz_pl_x = &iz + &self.0.X; // iZ + X + + let s_over_y = &den * &iz_min_x; + let sp_over_yp = &den * &iz_pl_x; + + let mut s2 = &s_over_y * &self.0.Y; + let mut s3 = &(-(&sp_over_yp)) * &self.0.Y; + + // t_2 := -2/sqrt(-d-1) * i*Z * sOverY + // t_3 := -2/sqrt(-d-1) * i*Z * spOverYp + let tmp = &lizard_constants::MDOUBLE_INVSQRT_A_MINUS_D * &iz; + let mut t2 = &tmp * &s_over_y; + let mut t3 = &tmp * &sp_over_yp; + + // Special case: X=0 or Y=0. Then return + // + // (0,1) (1,-2i/sqrt(-d-1) (-1,-2i/sqrt(-d-1)) + // + // Note that if X=0 or Y=0, then s_i = t_i = 0. + let x_or_y_is_zero = self.0.X.is_zero() | self.0.Y.is_zero(); + t0.conditional_assign(&FieldElement::one(), x_or_y_is_zero); + t1.conditional_assign(&FieldElement::one(), x_or_y_is_zero); + t2.conditional_assign(&lizard_constants::MIDOUBLE_INVSQRT_A_MINUS_D, x_or_y_is_zero); + t3.conditional_assign(&lizard_constants::MIDOUBLE_INVSQRT_A_MINUS_D, x_or_y_is_zero); + s2.conditional_assign(&FieldElement::one(), x_or_y_is_zero); + s3.conditional_assign(&(-(&FieldElement::one())), x_or_y_is_zero); + + return [ + JacobiPoint{S: s0, T: t0}, + JacobiPoint{S: s1, T: t1}, + JacobiPoint{S: s2, T: t2}, + JacobiPoint{S: s3, T: t3}, + ] + } +} + +// ------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------ + +#[cfg(all(test, feature = "stage2_build"))] +mod test { + + extern crate sha2; + + #[cfg(feature = "rand")] + use rand_os::OsRng; + use rand_core::{RngCore}; + use self::sha2::{Sha256}; + use ristretto::CompressedRistretto; + use super::*; + + fn test_lizard_encode_helper(data: &[u8; 16], result: &[u8; 32]) { + let p = RistrettoPoint::lizard_encode::(data).unwrap(); + let p_bytes = p.compress().to_bytes(); + assert!(&p_bytes == result); + let p = CompressedRistretto::from_slice(&p_bytes).decompress().unwrap(); + let data_out = p.lizard_decode::().unwrap(); + assert!(&data_out == data); + } + + #[test] + fn test_lizard_encode() { + test_lizard_encode_helper(&[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + &[0xf0, 0xb7, 0xe3, 0x44, 0x84, 0xf7, 0x4c, 0xf0, 0xf, 0x15, 0x2, 0x4b, 0x73, 0x85, 0x39, 0x73, 0x86, 0x46, 0xbb, 0xbe, 0x1e, 0x9b, 0xc7, 0x50, 0x9a, 0x67, 0x68, 0x15, 0x22, 0x7e, 0x77, 0x4f]); + + test_lizard_encode_helper(&[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + &[0xcc, 0x92, 0xe8, 0x1f, 0x58, 0x5a, 0xfc, 0x5c, 0xaa, 0xc8, 0x86, 0x60, 0xd8, 0xd1, 0x7e, 0x90, 0x25, 0xa4, 0x44, 0x89, 0xa3, 0x63, 0x4, 0x21, 0x23, 0xf6, 0xaf, 0x7, 0x2, 0x15, 0x6e, 0x65]); + + test_lizard_encode_helper(&[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], + &[0xc8, 0x30, 0x57, 0x3f, 0x8a, 0x8e, 0x77, 0x78, 0x67, 0x1f, 0x76, 0xcd, 0xc7, 0x96, 0xdc, 0xa, 0x23, 0x5c, 0xf1, 0x77, 0xf1, 0x97, 0xd9, 0xfc, 0xba, 0x6, 0xe8, 0x4e, 0x96, 0x24, 0x74, 0x44]); + } + + #[test] + fn test_elligator_inv() { + let mut rng = rand::thread_rng(); + + for i in 0..100 { + let mut fe_bytes = [0u8; 32]; + + if i == 0 { + // Test for first corner-case: fe = 0 + fe_bytes = [0u8; 32]; + } else if i == 1 { + // Test for second corner-case: fe = +sqrt(i*d) + fe_bytes = [168, 27, 92, 74, 203, 42, 48, 117, 170, 109, 234, + 14, 45, 169, 188, 205, 21, 110, 235, 115, 153, 84, + 52, 117, 151, 235, 123, 244, 88, 85, 179, 5]; + } else { + // For the rest, just generate a random field element to test. + rng.fill_bytes(&mut fe_bytes); + } + fe_bytes[0] &= 254; // positive + fe_bytes[31] &= 127; // < 2^255-19 + let fe = FieldElement::from_bytes(&fe_bytes); + + let pt = RistrettoPoint::elligator_ristretto_flavor(&fe); + for pt2 in &pt.xcoset4() { + let (mask, fes) = RistrettoPoint(*pt2).elligator_ristretto_flavor_inverse(); + + let mut found = false; + for j in 0..8 { + if mask & (1 << j) != 0 { + assert_eq!(RistrettoPoint::elligator_ristretto_flavor(&fes[j]), pt); + if fes[j] == fe { + found = true; + } + } + } + assert!(found); + } + } + } +} + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/mod.rs new file mode 100644 index 0000000..ff3f950 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/mod.rs @@ -0,0 +1,13 @@ +//! The Lizard method for encoding/decoding 16 bytes into Ristretto points. + +#![allow(non_snake_case)] + +#[cfg(feature = "u32_backend")] +mod u32_constants; + +#[cfg(feature = "u64_backend")] +mod u64_constants; + +pub mod lizard_constants; +pub mod jacobi_quartic; +pub mod lizard_ristretto; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/u32_constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/u32_constants.rs new file mode 100644 index 0000000..388cf0d --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/u32_constants.rs @@ -0,0 +1,33 @@ +use backend::serial::u32::field::FieldElement2625; +use edwards::EdwardsPoint; + +/// `= sqrt(i*d)`, where `i = +sqrt(-1)` and `d` is the Edwards curve parameter. +pub const SQRT_ID: FieldElement2625 = FieldElement2625([ + 39590824, 701138, 28659366, 23623507, 53932708, + 32206357, 36326585, 24309414, 26167230, 1494357, +]); + +/// `= (d+1)/(d-1)`, where `d` is the Edwards curve parameter. +pub const DP1_OVER_DM1: FieldElement2625 = FieldElement2625([ + 58833708, 32184294, 62457071, 26110240, 19032991, + 27203620, 7122892, 18068959, 51019405, 3776288, +]); + +/// `= -2/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub const MDOUBLE_INVSQRT_A_MINUS_D: FieldElement2625 = FieldElement2625([ + 54885894, 25242303, 55597453, 9067496, 51808079, + 33312638, 25456129, 14121551, 54921728, 3972023, +]); + +/// `= -2i/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters +/// and `i = +sqrt(-1)`. +pub const MIDOUBLE_INVSQRT_A_MINUS_D: FieldElement2625 = FieldElement2625([ + 58178520, 23970840, 26444491, 29801899, 41064376, + 743696, 2900628, 27920316, 41968995, 5270573, +]); + +/// `= -1/sqrt(1+d)`, where `d` is the Edwards curve parameters. +pub const MINVSQRT_ONE_PLUS_D: FieldElement2625 = FieldElement2625([ + 38019585, 4791795, 20332186, 18653482, 46576675, + 33182583, 65658549, 2817057, 12569934, 30919145, +]); diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/u64_constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/u64_constants.rs new file mode 100644 index 0000000..31b0a95 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/lizard/u64_constants.rs @@ -0,0 +1,18 @@ +use backend::serial::u64::field::FieldElement51; + +/// `= sqrt(i*d)`, where `i = +sqrt(-1)` and `d` is the Edwards curve parameter. +pub const SQRT_ID: FieldElement51 = FieldElement51([2298852427963285, 3837146560810661, 4413131899466403, 3883177008057528, 2352084440532925]); + +/// `= (d+1)/(d-1)`, where `d` is the Edwards curve parameter. +pub const DP1_OVER_DM1: FieldElement51 = FieldElement51([2159851467815724, 1752228607624431, 1825604053920671, 1212587319275468, 253422448836237]); + +/// `= -2/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub const MDOUBLE_INVSQRT_A_MINUS_D: FieldElement51 = FieldElement51([1693982333959686, 608509411481997, 2235573344831311, 947681270984193, 266558006233600]); + +/// `= -2i/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters +/// and `i = +sqrt(-1)`. +pub const MIDOUBLE_INVSQRT_A_MINUS_D: FieldElement51 = FieldElement51([1608655899704280, 1999971613377227, 49908634785720, 1873700692181652, 353702208628067]); + +/// `= -1/sqrt(1+d)`, where `d` is the Edwards curve parameters. +pub const MINVSQRT_ONE_PLUS_D: FieldElement51 = FieldElement51([321571956990465, 1251814006996634, 2226845496292387, 189049560751797, 2074948709371214]); + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/macros.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/macros.rs new file mode 100644 index 0000000..5985a5f --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/macros.rs @@ -0,0 +1,123 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Internal macros. + +/// Define borrow and non-borrow variants of `Add`. +macro_rules! define_add_variants { + (LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => { + impl<'b> Add<&'b $rhs> for $lhs { + type Output = $out; + fn add(self, rhs: &'b $rhs) -> $out { + &self + rhs + } + } + + impl<'a> Add<$rhs> for &'a $lhs { + type Output = $out; + fn add(self, rhs: $rhs) -> $out { + self + &rhs + } + } + + impl Add<$rhs> for $lhs { + type Output = $out; + fn add(self, rhs: $rhs) -> $out { + &self + &rhs + } + } + } +} + +/// Define non-borrow variants of `AddAssign`. +macro_rules! define_add_assign_variants { + (LHS = $lhs:ty, RHS = $rhs:ty) => { + impl AddAssign<$rhs> for $lhs { + fn add_assign(&mut self, rhs: $rhs) { + *self += &rhs; + } + } + } +} + +/// Define borrow and non-borrow variants of `Sub`. +macro_rules! define_sub_variants { + (LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => { + impl<'b> Sub<&'b $rhs> for $lhs { + type Output = $out; + fn sub(self, rhs: &'b $rhs) -> $out { + &self - rhs + } + } + + impl<'a> Sub<$rhs> for &'a $lhs { + type Output = $out; + fn sub(self, rhs: $rhs) -> $out { + self - &rhs + } + } + + impl Sub<$rhs> for $lhs { + type Output = $out; + fn sub(self, rhs: $rhs) -> $out { + &self - &rhs + } + } + } +} + +/// Define non-borrow variants of `SubAssign`. +macro_rules! define_sub_assign_variants { + (LHS = $lhs:ty, RHS = $rhs:ty) => { + impl SubAssign<$rhs> for $lhs { + fn sub_assign(&mut self, rhs: $rhs) { + *self -= &rhs; + } + } + } +} + +/// Define borrow and non-borrow variants of `Mul`. +macro_rules! define_mul_variants { + (LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => { + impl<'b> Mul<&'b $rhs> for $lhs { + type Output = $out; + fn mul(self, rhs: &'b $rhs) -> $out { + &self * rhs + } + } + + impl<'a> Mul<$rhs> for &'a $lhs { + type Output = $out; + fn mul(self, rhs: $rhs) -> $out { + self * &rhs + } + } + + impl Mul<$rhs> for $lhs { + type Output = $out; + fn mul(self, rhs: $rhs) -> $out { + &self * &rhs + } + } + } +} + +/// Define non-borrow variants of `MulAssign`. +macro_rules! define_mul_assign_variants { + (LHS = $lhs:ty, RHS = $rhs:ty) => { + impl MulAssign<$rhs> for $lhs { + fn mul_assign(&mut self, rhs: $rhs) { + *self *= &rhs; + } + } + } +} + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/montgomery.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/montgomery.rs new file mode 100644 index 0000000..4768451 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/montgomery.rs @@ -0,0 +1,403 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Scalar multiplication on the Montgomery form of Curve25519. +//! +//! To avoid notational confusion with the Edwards code, we use +//! variables \\( u, v \\) for the Montgomery curve, so that “Montgomery +//! \\(u\\)” here corresponds to “Montgomery \\(x\\)” elsewhere. +//! +//! Montgomery arithmetic works not on the curve itself, but on the +//! \\(u\\)-line, which discards sign information and unifies the curve +//! and its quadratic twist. See [_Montgomery curves and their +//! arithmetic_][costello-smith] by Costello and Smith for more details. +//! +//! The `MontgomeryPoint` struct contains the affine \\(u\\)-coordinate +//! \\(u\_0(P)\\) of a point \\(P\\) on either the curve or the twist. +//! Here the map \\(u\_0 : \mathcal M \rightarrow \mathbb F\_p \\) is +//! defined by \\(u\_0((u,v)) = u\\); \\(u\_0(\mathcal O) = 0\\). See +//! section 5.4 of Costello-Smith for more details. +//! +//! # Scalar Multiplication +//! +//! Scalar multiplication on `MontgomeryPoint`s is provided by the `*` +//! operator, which implements the Montgomery ladder. +//! +//! # Edwards Conversion +//! +//! The \\(2\\)-to-\\(1\\) map from the Edwards model to the Montgomery +//! \\(u\\)-line is provided by `EdwardsPoint::to_montgomery()`. +//! +//! To lift a `MontgomeryPoint` to an `EdwardsPoint`, use +//! `MontgomeryPoint::to_edwards()`, which takes a sign parameter. +//! This function rejects `MontgomeryPoints` which correspond to points +//! on the twist. +//! +//! [costello-smith]: https://eprint.iacr.org/2017/212.pdf + +// We allow non snake_case names because coordinates in projective space are +// traditionally denoted by the capitalisation of their respective +// counterparts in affine space. Yeah, you heard me, rustc, I'm gonna have my +// affine and projective cakes and eat both of them too. +#![allow(non_snake_case)] + +use core::ops::{Mul, MulAssign}; + +use constants::APLUS2_OVER_FOUR; +use edwards::{CompressedEdwardsY, EdwardsPoint}; +use field::FieldElement; +use scalar::Scalar; + +use traits::Identity; + +use subtle::Choice; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; + +use zeroize::Zeroize; + +/// Holds the \\(u\\)-coordinate of a point on the Montgomery form of +/// Curve25519 or its twist. +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct MontgomeryPoint(pub [u8; 32]); + +/// Equality of `MontgomeryPoint`s is defined mod p. +impl ConstantTimeEq for MontgomeryPoint { + fn ct_eq(&self, other: &MontgomeryPoint) -> Choice { + let self_fe = FieldElement::from_bytes(&self.0); + let other_fe = FieldElement::from_bytes(&other.0); + + self_fe.ct_eq(&other_fe) + } +} + +impl Default for MontgomeryPoint { + fn default() -> MontgomeryPoint { + MontgomeryPoint([0u8; 32]) + } +} + +impl PartialEq for MontgomeryPoint { + fn eq(&self, other: &MontgomeryPoint) -> bool { + self.ct_eq(other).unwrap_u8() == 1u8 + } +} + +impl Eq for MontgomeryPoint {} + +impl Zeroize for MontgomeryPoint { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl MontgomeryPoint { + /// View this `MontgomeryPoint` as an array of bytes. + pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { + &self.0 + } + + /// Convert this `MontgomeryPoint` to an array of bytes. + pub fn to_bytes(&self) -> [u8; 32] { + self.0 + } + + /// Attempt to convert to an `EdwardsPoint`, using the supplied + /// choice of sign for the `EdwardsPoint`. + /// + /// # Inputs + /// + /// * `sign`: a `u8` donating the desired sign of the resulting + /// `EdwardsPoint`. `0` denotes positive and `1` negative. + /// + /// # Return + /// + /// * `Some(EdwardsPoint)` if `self` is the \\(u\\)-coordinate of a + /// point on (the Montgomery form of) Curve25519; + /// + /// * `None` if `self` is the \\(u\\)-coordinate of a point on the + /// twist of (the Montgomery form of) Curve25519; + /// + pub fn to_edwards(&self, sign: u8) -> Option { + // To decompress the Montgomery u coordinate to an + // `EdwardsPoint`, we apply the birational map to obtain the + // Edwards y coordinate, then do Edwards decompression. + // + // The birational map is y = (u-1)/(u+1). + // + // The exceptional points are the zeros of the denominator, + // i.e., u = -1. + // + // But when u = -1, v^2 = u*(u^2+486662*u+1) = 486660. + // + // Since this is nonsquare mod p, u = -1 corresponds to a point + // on the twist, not the curve, so we can reject it early. + + let u = FieldElement::from_bytes(&self.0); + + if u == FieldElement::minus_one() { return None; } + + let one = FieldElement::one(); + + let y = &(&u - &one) * &(&u + &one).invert(); + + let mut y_bytes = y.to_bytes(); + y_bytes[31] ^= sign << 7; + + CompressedEdwardsY(y_bytes).decompress() + } +} + +/// A `ProjectivePoint` holds a point on the projective line +/// \\( \mathbb P(\mathbb F\_p) \\), which we identify with the Kummer +/// line of the Montgomery curve. +#[derive(Copy, Clone, Debug)] +struct ProjectivePoint { + pub U: FieldElement, + pub W: FieldElement, +} + +impl Identity for ProjectivePoint { + fn identity() -> ProjectivePoint { + ProjectivePoint { + U: FieldElement::one(), + W: FieldElement::zero(), + } + } +} + +impl Default for ProjectivePoint { + fn default() -> ProjectivePoint { + ProjectivePoint::identity() + } +} + +impl ConditionallySelectable for ProjectivePoint { + fn conditional_select( + a: &ProjectivePoint, + b: &ProjectivePoint, + choice: Choice, + ) -> ProjectivePoint { + ProjectivePoint { + U: FieldElement::conditional_select(&a.U, &b.U, choice), + W: FieldElement::conditional_select(&a.W, &b.W, choice), + } + } +} + +impl ProjectivePoint { + /// Dehomogenize this point to affine coordinates. + /// + /// # Return + /// + /// * \\( u = U / W \\) if \\( W \neq 0 \\); + /// * \\( 0 \\) if \\( W \eq 0 \\); + pub fn to_affine(&self) -> MontgomeryPoint { + let u = &self.U * &self.W.invert(); + MontgomeryPoint(u.to_bytes()) + } +} + +/// Perform the double-and-add step of the Montgomery ladder. +/// +/// Given projective points +/// \\( (U\_P : W\_P) = u(P) \\), +/// \\( (U\_Q : W\_Q) = u(Q) \\), +/// and the affine difference +/// \\( u\_{P-Q} = u(P-Q) \\), set +/// $$ +/// (U\_P : W\_P) \gets u([2]P) +/// $$ +/// and +/// $$ +/// (U\_Q : W\_Q) \gets u(P + Q). +/// $$ +fn differential_add_and_double( + P: &mut ProjectivePoint, + Q: &mut ProjectivePoint, + affine_PmQ: &FieldElement, +) { + let t0 = &P.U + &P.W; + let t1 = &P.U - &P.W; + let t2 = &Q.U + &Q.W; + let t3 = &Q.U - &Q.W; + + let t4 = t0.square(); // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2 + let t5 = t1.square(); // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2 + + let t6 = &t4 - &t5; // 4 U_P W_P + + let t7 = &t0 * &t3; // (U_P + W_P) (U_Q - W_Q) = U_P U_Q + W_P U_Q - U_P W_Q - W_P W_Q + let t8 = &t1 * &t2; // (U_P - W_P) (U_Q + W_Q) = U_P U_Q - W_P U_Q + U_P W_Q - W_P W_Q + + let t9 = &t7 + &t8; // 2 (U_P U_Q - W_P W_Q) + let t10 = &t7 - &t8; // 2 (W_P U_Q - U_P W_Q) + + let t11 = t9.square(); // 4 (U_P U_Q - W_P W_Q)^2 + let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2 + + let t13 = &APLUS2_OVER_FOUR * &t6; // (A + 2) U_P U_Q + + let t14 = &t4 * &t5; // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2 + let t15 = &t13 + &t5; // (U_P - W_P)^2 + (A + 2) U_P W_P + + let t16 = &t6 * &t15; // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P) + + let t17 = affine_PmQ * &t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2 + let t18 = t11; // W_D * 4 (U_P U_Q - W_P W_Q)^2 + + P.U = t14; // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2 + P.W = t16; // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P) + Q.U = t18; // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2 + Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 +} + +define_mul_assign_variants!(LHS = MontgomeryPoint, RHS = Scalar); + +define_mul_variants!(LHS = MontgomeryPoint, RHS = Scalar, Output = MontgomeryPoint); +define_mul_variants!(LHS = Scalar, RHS = MontgomeryPoint, Output = MontgomeryPoint); + +/// Multiply this `MontgomeryPoint` by a `Scalar`. +impl<'a, 'b> Mul<&'b Scalar> for &'a MontgomeryPoint { + type Output = MontgomeryPoint; + + /// Given `self` \\( = u\_0(P) \\), and a `Scalar` \\(n\\), return \\( u\_0([n]P) \\). + fn mul(self, scalar: &'b Scalar) -> MontgomeryPoint { + // Algorithm 8 of Costello-Smith 2017 + let affine_u = FieldElement::from_bytes(&self.0); + let mut x0 = ProjectivePoint::identity(); + let mut x1 = ProjectivePoint { + U: affine_u, + W: FieldElement::one(), + }; + + let bits: [i8; 256] = scalar.bits(); + + for i in (0..255).rev() { + let choice: u8 = (bits[i + 1] ^ bits[i]) as u8; + + debug_assert!(choice == 0 || choice == 1); + + ProjectivePoint::conditional_swap(&mut x0, &mut x1, choice.into()); + differential_add_and_double(&mut x0, &mut x1, &affine_u); + } + ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(bits[0] as u8)); + + x0.to_affine() + } +} + +impl<'b> MulAssign<&'b Scalar> for MontgomeryPoint { + fn mul_assign(&mut self, scalar: &'b Scalar) { + *self = (self as &MontgomeryPoint) * scalar; + } +} + +impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar { + type Output = MontgomeryPoint; + + fn mul(self, point: &'b MontgomeryPoint) -> MontgomeryPoint { + point * self + } +} + +// ------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------ + +#[cfg(test)] +mod test { + use constants; + use super::*; + + use rand_core::OsRng; + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_basepoint_roundtrip() { + use bincode; + + let encoded = bincode::serialize(&constants::X25519_BASEPOINT).unwrap(); + let decoded: MontgomeryPoint = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(encoded.len(), 32); + assert_eq!(decoded, constants::X25519_BASEPOINT); + + let raw_bytes = constants::X25519_BASEPOINT.as_bytes(); + let bp: MontgomeryPoint = bincode::deserialize(raw_bytes).unwrap(); + assert_eq!(bp, constants::X25519_BASEPOINT); + } + + /// Test Montgomery -> Edwards on the X/Ed25519 basepoint + #[test] + fn basepoint_montgomery_to_edwards() { + // sign bit = 0 => basepoint + assert_eq!( + constants::ED25519_BASEPOINT_POINT, + constants::X25519_BASEPOINT.to_edwards(0).unwrap() + ); + // sign bit = 1 => minus basepoint + assert_eq!( + - constants::ED25519_BASEPOINT_POINT, + constants::X25519_BASEPOINT.to_edwards(1).unwrap() + ); + } + + /// Test Edwards -> Montgomery on the X/Ed25519 basepoint + #[test] + fn basepoint_edwards_to_montgomery() { + assert_eq!( + constants::ED25519_BASEPOINT_POINT.to_montgomery(), + constants::X25519_BASEPOINT + ); + } + + /// Check that Montgomery -> Edwards fails for points on the twist. + #[test] + fn montgomery_to_edwards_rejects_twist() { + let one = FieldElement::one(); + + // u = 2 corresponds to a point on the twist. + let two = MontgomeryPoint((&one+&one).to_bytes()); + + assert!(two.to_edwards(0).is_none()); + + // u = -1 corresponds to a point on the twist, but should be + // checked explicitly because it's an exceptional point for the + // birational map. For instance, libsignal will accept it. + let minus_one = MontgomeryPoint((-&one).to_bytes()); + + assert!(minus_one.to_edwards(0).is_none()); + } + + #[test] + fn eq_defined_mod_p() { + let mut u18_bytes = [0u8; 32]; u18_bytes[0] = 18; + let u18 = MontgomeryPoint(u18_bytes); + let u18_unred = MontgomeryPoint([255; 32]); + + assert_eq!(u18, u18_unred); + } + + #[test] + fn montgomery_ladder_matches_edwards_scalarmult() { + let mut csprng: OsRng = OsRng; + + let s: Scalar = Scalar::random(&mut csprng); + let p_edwards: EdwardsPoint = &constants::ED25519_BASEPOINT_TABLE * &s; + let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); + + let expected = s * p_edwards; + let result = s * p_montgomery; + + assert_eq!(result, expected.to_montgomery()) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/prelude.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/prelude.rs new file mode 100644 index 0000000..be2f600 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/prelude.rs @@ -0,0 +1,8 @@ +//! Crate-local prelude (for alloc-dependent features like `Vec`) + +// TODO: switch to alloc::prelude +#[cfg(all(feature = "alloc", not(feature = "std")))] +pub use alloc::vec::Vec; + +#[cfg(feature = "std")] +pub use std::vec::Vec; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/ristretto.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/ristretto.rs new file mode 100644 index 0000000..a37cb50 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/ristretto.rs @@ -0,0 +1,1365 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +// We allow non snake_case names because coordinates in projective space are +// traditionally denoted by the capitalisation of their respective +// counterparts in affine space. Yeah, you heard me, rustc, I'm gonna have my +// affine and projective cakes and eat both of them too. +#![allow(non_snake_case)] + +//! An implementation of [Ristretto][ristretto_main], which provides a +//! prime-order group. +//! +//! # The Ristretto Group +//! +//! Ristretto is a modification of Mike Hamburg's Decaf scheme to work +//! with cofactor-\\(8\\) curves, such as Curve25519. +//! +//! The introduction of the Decaf paper, [_Decaf: +//! Eliminating cofactors through point +//! compression_](https://eprint.iacr.org/2015/673.pdf), notes that while +//! most cryptographic systems require a group of prime order, most +//! concrete implementations using elliptic curve groups fall short – +//! they either provide a group of prime order, but with incomplete or +//! variable-time addition formulae (for instance, most Weierstrass +//! models), or else they provide a fast and safe implementation of a +//! group whose order is not quite a prime \\(q\\), but \\(hq\\) for a +//! small cofactor \\(h\\) (for instance, Edwards curves, which have +//! cofactor at least \\(4\\)). +//! +//! This abstraction mismatch is commonly “handled” by pushing the +//! complexity upwards, adding ad-hoc protocol modifications. But +//! these modifications require careful analysis and are a recurring +//! source of [vulnerabilities][cryptonote] and [design +//! complications][ed25519_hkd]. +//! +//! Instead, Decaf (and Ristretto) use a quotient group to implement a +//! prime-order group using a non-prime-order curve. This provides +//! the correct abstraction for cryptographic systems, while retaining +//! the speed and safety benefits of an Edwards curve. +//! +//! Decaf is named “after the procedure which divides the effect of +//! coffee by \\(4\\)”. However, Curve25519 has a cofactor of +//! \\(8\\). To eliminate its cofactor, Ristretto restricts further; +//! this [additional restriction][ristretto_coffee] gives the +//! _Ristretto_ encoding. +//! +//! More details on why Ristretto is necessary can be found in the +//! [Why Ristretto?][why_ristretto] section of the Ristretto website. +//! +//! Ristretto +//! points are provided in `curve25519-dalek` by the `RistrettoPoint` +//! struct. +//! +//! ## Encoding and Decoding +//! +//! Encoding is done by converting to and from a `CompressedRistretto` +//! struct, which is a typed wrapper around `[u8; 32]`. +//! +//! The encoding is not batchable, but it is possible to +//! double-and-encode in a batch using +//! `RistrettoPoint::double_and_compress_batch`. +//! +//! ## Equality Testing +//! +//! Testing equality of points on an Edwards curve in projective +//! coordinates requires an expensive inversion. By contrast, equality +//! checking in the Ristretto group can be done in projective +//! coordinates without requiring an inversion, so it is much faster. +//! +//! The `RistrettoPoint` struct implements the +//! `subtle::ConstantTimeEq` trait for constant-time equality +//! checking, and the Rust `Eq` trait for variable-time equality +//! checking. +//! +//! ## Scalars +//! +//! Scalars are represented by the `Scalar` struct. Each scalar has a +//! canonical representative mod the group order. To attempt to load +//! a supposedly-canonical scalar, use +//! `Scalar::from_canonical_bytes()`. To check whether a +//! representative is canonical, use `Scalar::is_canonical()`. +//! +//! ## Scalar Multiplication +//! +//! Scalar multiplication on Ristretto points is provided by: +//! +//! * the `*` operator between a `Scalar` and a `RistrettoPoint`, which +//! performs constant-time variable-base scalar multiplication; +//! +//! * the `*` operator between a `Scalar` and a +//! `RistrettoBasepointTable`, which performs constant-time fixed-base +//! scalar multiplication; +//! +//! * an implementation of the +//! [`MultiscalarMul`](../traits/trait.MultiscalarMul.html) trait for +//! constant-time variable-base multiscalar multiplication; +//! +//! * an implementation of the +//! [`VartimeMultiscalarMul`](../traits/trait.VartimeMultiscalarMul.html) +//! trait for variable-time variable-base multiscalar multiplication; +//! +//! ## Random Points and Hashing to Ristretto +//! +//! The Ristretto group comes equipped with an Elligator map. This is +//! used to implement +//! +//! * `RistrettoPoint::random()`, which generates random points from an +//! RNG; +//! +//! * `RistrettoPoint::from_hash()` and +//! `RistrettoPoint::hash_from_bytes()`, which perform hashing to the +//! group. +//! +//! The Elligator map itself is not currently exposed. +//! +//! ## Implementation +//! +//! The Decaf suggestion is to use a quotient group, such as \\(\mathcal +//! E / \mathcal E[4]\\) or \\(2 \mathcal E / \mathcal E[2] \\), to +//! implement a prime-order group using a non-prime-order curve. +//! +//! This requires only changing +//! +//! 1. the function for equality checking (so that two representatives +//! of the same coset are considered equal); +//! 2. the function for encoding (so that two representatives of the +//! same coset are encoded as identical bitstrings); +//! 3. the function for decoding (so that only the canonical encoding of +//! a coset is accepted). +//! +//! Internally, each coset is represented by a curve point; two points +//! \\( P, Q \\) may represent the same coset in the same way that two +//! points with different \\(X,Y,Z\\) coordinates may represent the +//! same point. The group operations are carried out with no overhead +//! using Edwards formulas. +//! +//! Notes on the details of the encoding can be found in the +//! [Details][ristretto_notes] section of the Ristretto website. +//! +//! [cryptonote]: +//! https://moderncrypto.org/mail-archive/curves/2017/000898.html +//! [ed25519_hkd]: +//! https://moderncrypto.org/mail-archive/curves/2017/000858.html +//! [ristretto_coffee]: +//! https://en.wikipedia.org/wiki/Ristretto +//! [ristretto_notes]: +//! https://ristretto.group/details/index.html +//! [why_ristretto]: +//! https://ristretto.group/why_ristretto.html +//! [ristretto_main]: +//! https://ristretto.group/ + +use core::borrow::Borrow; +use core::fmt::Debug; +use core::iter::Sum; +use core::ops::{Add, Neg, Sub}; +use core::ops::{AddAssign, SubAssign}; +use core::ops::{Mul, MulAssign}; + +use rand_core::{CryptoRng, RngCore}; + +use digest::generic_array::typenum::U64; +use digest::Digest; + +use constants; +use field::FieldElement; + +use subtle::Choice; +use subtle::ConditionallySelectable; +use subtle::ConditionallyNegatable; +use subtle::ConstantTimeEq; + +use edwards::EdwardsBasepointTable; +use edwards::EdwardsPoint; + +#[allow(unused_imports)] +use prelude::*; + +use scalar::Scalar; + +use traits::Identity; +#[cfg(any(feature = "alloc", feature = "std"))] +use traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; + +#[cfg(not(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +)))] +use backend::serial::scalar_mul; +#[cfg(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +))] +use backend::vector::scalar_mul; + +// ------------------------------------------------------------------------ +// Compressed points +// ------------------------------------------------------------------------ + +/// A Ristretto point, in compressed wire format. +/// +/// The Ristretto encoding is canonical, so two points are equal if and +/// only if their encodings are equal. +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct CompressedRistretto(pub [u8; 32]); + +impl ConstantTimeEq for CompressedRistretto { + fn ct_eq(&self, other: &CompressedRistretto) -> Choice { + self.as_bytes().ct_eq(other.as_bytes()) + } +} + +impl CompressedRistretto { + /// Copy the bytes of this `CompressedRistretto`. + pub fn to_bytes(&self) -> [u8; 32] { + self.0 + } + + /// View this `CompressedRistretto` as an array of bytes. + pub fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } + + /// Construct a `CompressedRistretto` from a slice of bytes. + /// + /// # Panics + /// + /// If the input `bytes` slice does not have a length of 32. + pub fn from_slice(bytes: &[u8]) -> CompressedRistretto { + let mut tmp = [0u8; 32]; + + tmp.copy_from_slice(bytes); + + CompressedRistretto(tmp) + } + + /// Attempt to decompress to an `RistrettoPoint`. + /// + /// # Return + /// + /// - `Some(RistrettoPoint)` if `self` was the canonical encoding of a point; + /// + /// - `None` if `self` was not the canonical encoding of a point. + pub fn decompress(&self) -> Option { + // Step 1. Check s for validity: + // 1.a) s must be 32 bytes (we get this from the type system) + // 1.b) s < p + // 1.c) s is nonnegative + // + // Our decoding routine ignores the high bit, so the only + // possible failure for 1.b) is if someone encodes s in 0..18 + // as s+p in 2^255-19..2^255-1. We can check this by + // converting back to bytes, and checking that we get the + // original input, since our encoding routine is canonical. + + let s = FieldElement::from_bytes(self.as_bytes()); + let s_bytes_check = s.to_bytes(); + let s_encoding_is_canonical = + &s_bytes_check[..].ct_eq(self.as_bytes()); + let s_is_negative = s.is_negative(); + + if s_encoding_is_canonical.unwrap_u8() == 0u8 || s_is_negative.unwrap_u8() == 1u8 { + return None; + } + + // Step 2. Compute (X:Y:Z:T). + let one = FieldElement::one(); + let ss = s.square(); + let u1 = &one - &ss; // 1 + as² + let u2 = &one + &ss; // 1 - as² where a=-1 + let u2_sqr = u2.square(); // (1 - as²)² + + // v == ad(1+as²)² - (1-as²)² where d=-121665/121666 + let v = &(&(-&constants::EDWARDS_D) * &u1.square()) - &u2_sqr; + + let (ok, I) = (&v * &u2_sqr).invsqrt(); // 1/sqrt(v*u_2²) + + let Dx = &I * &u2; // 1/sqrt(v) + let Dy = &I * &(&Dx * &v); // 1/u2 + + // x == | 2s/sqrt(v) | == + sqrt(4s²/(ad(1+as²)² - (1-as²)²)) + let mut x = &(&s + &s) * &Dx; + let x_neg = x.is_negative(); + x.conditional_negate(x_neg); + + // y == (1-as²)/(1+as²) + let y = &u1 * &Dy; + + // t == ((1+as²) sqrt(4s²/(ad(1+as²)² - (1-as²)²)))/(1-as²) + let t = &x * &y; + + if ok.unwrap_u8() == 0u8 || t.is_negative().unwrap_u8() == 1u8 || y.is_zero().unwrap_u8() == 1u8 { + None + } else { + Some(RistrettoPoint(EdwardsPoint{X: x, Y: y, Z: one, T: t})) + } + } +} + +impl Identity for CompressedRistretto { + fn identity() -> CompressedRistretto { + CompressedRistretto([0u8; 32]) + } +} + +impl Default for CompressedRistretto { + fn default() -> CompressedRistretto { + CompressedRistretto::identity() + } +} + +// ------------------------------------------------------------------------ +// Serde support +// ------------------------------------------------------------------------ +// Serializes to and from `RistrettoPoint` directly, doing compression +// and decompression internally. This means that users can create +// structs containing `RistrettoPoint`s and use Serde's derived +// serializers to serialize those structures. + +#[cfg(feature = "serde")] +use serde::{self, Serialize, Deserialize, Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +#[cfg(feature = "serde")] +impl Serialize for RistrettoPoint { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + use serde::ser::SerializeTuple; + let mut tup = serializer.serialize_tuple(32)?; + for byte in self.compress().as_bytes().iter() { + tup.serialize_element(byte)?; + } + tup.end() + } +} + +#[cfg(feature = "serde")] +impl Serialize for CompressedRistretto { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + use serde::ser::SerializeTuple; + let mut tup = serializer.serialize_tuple(32)?; + for byte in self.as_bytes().iter() { + tup.serialize_element(byte)?; + } + tup.end() + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for RistrettoPoint { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + struct RistrettoPointVisitor; + + impl<'de> Visitor<'de> for RistrettoPointVisitor { + type Value = RistrettoPoint; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("a valid point in Ristretto format") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de> + { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = seq.next_element()? + .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + CompressedRistretto(bytes) + .decompress() + .ok_or(serde::de::Error::custom("decompression failed")) + } + } + + deserializer.deserialize_tuple(32, RistrettoPointVisitor) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for CompressedRistretto { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + struct CompressedRistrettoVisitor; + + impl<'de> Visitor<'de> for CompressedRistrettoVisitor { + type Value = CompressedRistretto; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("32 bytes of data") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de> + { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = seq.next_element()? + .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + Ok(CompressedRistretto(bytes)) + } + } + + deserializer.deserialize_tuple(32, CompressedRistrettoVisitor) + } +} + +// ------------------------------------------------------------------------ +// Internal point representations +// ------------------------------------------------------------------------ + +/// A `RistrettoPoint` represents a point in the Ristretto group for +/// Curve25519. Ristretto, a variant of Decaf, constructs a +/// prime-order group as a quotient group of a subgroup of (the +/// Edwards form of) Curve25519. +/// +/// Internally, a `RistrettoPoint` is implemented as a wrapper type +/// around `EdwardsPoint`, with custom equality, compression, and +/// decompression routines to account for the quotient. This means that +/// operations on `RistrettoPoint`s are exactly as fast as operations on +/// `EdwardsPoint`s. +/// +#[derive(Copy, Clone)] +pub struct RistrettoPoint(pub(crate) EdwardsPoint); + +impl RistrettoPoint { + /// Compress this point using the Ristretto encoding. + pub fn compress(&self) -> CompressedRistretto { + let mut X = self.0.X; + let mut Y = self.0.Y; + let Z = &self.0.Z; + let T = &self.0.T; + + let u1 = &(Z + &Y) * &(Z - &Y); + let u2 = &X * &Y; + // Ignore return value since this is always square + let (_, invsqrt) = (&u1 * &u2.square()).invsqrt(); + let i1 = &invsqrt * &u1; + let i2 = &invsqrt * &u2; + let z_inv = &i1 * &(&i2 * T); + let mut den_inv = i2; + + let iX = &X * &constants::SQRT_M1; + let iY = &Y * &constants::SQRT_M1; + let ristretto_magic = &constants::INVSQRT_A_MINUS_D; + let enchanted_denominator = &i1 * ristretto_magic; + + let rotate = (T * &z_inv).is_negative(); + + X.conditional_assign(&iY, rotate); + Y.conditional_assign(&iX, rotate); + den_inv.conditional_assign(&enchanted_denominator, rotate); + + Y.conditional_negate((&X * &z_inv).is_negative()); + + let mut s = &den_inv * &(Z - &Y); + let s_is_negative = s.is_negative(); + s.conditional_negate(s_is_negative); + + CompressedRistretto(s.to_bytes()) + } + + /// Double-and-compress a batch of points. The Ristretto encoding + /// is not batchable, since it requires an inverse square root. + /// + /// However, given input points \\( P\_1, \ldots, P\_n, \\) + /// it is possible to compute the encodings of their doubles \\( + /// \mathrm{enc}( [2]P\_1), \ldots, \mathrm{enc}( [2]P\_n ) \\) + /// in a batch. + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # use curve25519_dalek::ristretto::RistrettoPoint; + /// extern crate rand_core; + /// use rand_core::OsRng; + /// + /// # // Need fn main() here in comment so the doctest compiles + /// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests + /// # fn main() { + /// let mut rng = OsRng; + /// let points: Vec = + /// (0..32).map(|_| RistrettoPoint::random(&mut rng)).collect(); + /// + /// let compressed = RistrettoPoint::double_and_compress_batch(&points); + /// + /// for (P, P2_compressed) in points.iter().zip(compressed.iter()) { + /// assert_eq!(*P2_compressed, (P + P).compress()); + /// } + /// # } + /// ``` + #[cfg(feature = "alloc")] + pub fn double_and_compress_batch<'a, I>(points: I) -> Vec + where I: IntoIterator + { + #[derive(Copy, Clone, Debug)] + struct BatchCompressState { + e: FieldElement, + f: FieldElement, + g: FieldElement, + h: FieldElement, + eg: FieldElement, + fh: FieldElement, + } + + impl BatchCompressState { + fn efgh(&self) -> FieldElement { + &self.eg * &self.fh + } + } + + impl<'a> From<&'a RistrettoPoint> for BatchCompressState { + fn from(P: &'a RistrettoPoint) -> BatchCompressState { + let XX = P.0.X.square(); + let YY = P.0.Y.square(); + let ZZ = P.0.Z.square(); + let dTT = &P.0.T.square() * &constants::EDWARDS_D; + + let e = &P.0.X * &(&P.0.Y + &P.0.Y); // = 2*X*Y + let f = &ZZ + &dTT; // = Z^2 + d*T^2 + let g = &YY + &XX; // = Y^2 - a*X^2 + let h = &ZZ - &dTT; // = Z^2 - d*T^2 + + let eg = &e * &g; + let fh = &f * &h; + + BatchCompressState{ e, f, g, h, eg, fh } + } + } + + let states: Vec = points.into_iter().map(BatchCompressState::from).collect(); + + let mut invs: Vec = states.iter().map(|state| state.efgh()).collect(); + + FieldElement::batch_invert(&mut invs[..]); + + states.iter().zip(invs.iter()).map(|(state, inv): (&BatchCompressState, &FieldElement)| { + let Zinv = &state.eg * &inv; + let Tinv = &state.fh * &inv; + + let mut magic = constants::INVSQRT_A_MINUS_D; + + let negcheck1 = (&state.eg * &Zinv).is_negative(); + + let mut e = state.e; + let mut g = state.g; + let mut h = state.h; + + let minus_e = -&e; + let f_times_sqrta = &state.f * &constants::SQRT_M1; + + e.conditional_assign(&state.g, negcheck1); + g.conditional_assign(&minus_e, negcheck1); + h.conditional_assign(&f_times_sqrta, negcheck1); + + magic.conditional_assign(&constants::SQRT_M1, negcheck1); + + let negcheck2 = (&(&h * &e) * &Zinv).is_negative(); + + g.conditional_negate(negcheck2); + + let mut s = &(&h - &g) * &(&magic * &(&g * &Tinv)); + + let s_is_negative = s.is_negative(); + s.conditional_negate(s_is_negative); + + CompressedRistretto(s.to_bytes()) + }).collect() + } + + + /// Return the coset self + E[4], for debugging. + fn coset4(&self) -> [EdwardsPoint; 4] { + [ self.0 + , &self.0 + &constants::EIGHT_TORSION[2] + , &self.0 + &constants::EIGHT_TORSION[4] + , &self.0 + &constants::EIGHT_TORSION[6] + ] + } + + /// Computes the Ristretto Elligator map. + /// + /// # Note + /// + /// This method is not public because it's just used for hashing + /// to a point -- proper elligator support is deferred for now. + pub fn elligator_ristretto_flavor(r_0: &FieldElement) -> RistrettoPoint { + let i = &constants::SQRT_M1; + let d = &constants::EDWARDS_D; + let one_minus_d_sq = &constants::ONE_MINUS_EDWARDS_D_SQUARED; + let d_minus_one_sq = &constants::EDWARDS_D_MINUS_ONE_SQUARED; + let mut c = constants::MINUS_ONE; + + let one = FieldElement::one(); + + let r = i * &r_0.square(); + let N_s = &(&r + &one) * &one_minus_d_sq; + let D = &(&c - &(d * &r)) * &(&r + d); + + let (Ns_D_is_sq, mut s) = FieldElement::sqrt_ratio_i(&N_s, &D); + let mut s_prime = &s * r_0; + let s_prime_is_pos = !s_prime.is_negative(); + s_prime.conditional_negate(s_prime_is_pos); + + s.conditional_assign(&s_prime, !Ns_D_is_sq); + c.conditional_assign(&r, !Ns_D_is_sq); + + let N_t = &(&(&c * &(&r - &one)) * &d_minus_one_sq) - &D; + let s_sq = s.square(); + + use backend::serial::curve_models::CompletedPoint; + + // The conversion from W_i is exactly the conversion from P1xP1. + RistrettoPoint(CompletedPoint{ + X: &(&s + &s) * &D, + Z: &N_t * &constants::SQRT_AD_MINUS_ONE, + Y: &FieldElement::one() - &s_sq, + T: &FieldElement::one() + &s_sq, + }.to_extended()) + } + + /// Return a `RistrettoPoint` chosen uniformly at random using a user-provided RNG. + /// + /// # Inputs + /// + /// * `rng`: any RNG which implements the `RngCore + CryptoRng` interface. + /// + /// # Returns + /// + /// A random element of the Ristretto group. + /// + /// # Implementation + /// + /// Uses the Ristretto-flavoured Elligator 2 map, so that the + /// discrete log of the output point with respect to any other + /// point should be unknown. The map is applied twice and the + /// results are added, to ensure a uniform distribution. + pub fn random(rng: &mut R) -> Self { + let mut uniform_bytes = [0u8; 64]; + rng.fill_bytes(&mut uniform_bytes); + + RistrettoPoint::from_uniform_bytes(&uniform_bytes) + } + + /// Hash a slice of bytes into a `RistrettoPoint`. + /// + /// Takes a type parameter `D`, which is any `Digest` producing 64 + /// bytes of output. + /// + /// Convenience wrapper around `from_hash`. + /// + /// # Implementation + /// + /// Uses the Ristretto-flavoured Elligator 2 map, so that the + /// discrete log of the output point with respect to any other + /// point should be unknown. The map is applied twice and the + /// results are added, to ensure a uniform distribution. + /// + /// # Example + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # use curve25519_dalek::ristretto::RistrettoPoint; + /// extern crate sha2; + /// use sha2::Sha512; + /// + /// # // Need fn main() here in comment so the doctest compiles + /// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests + /// # fn main() { + /// let msg = "To really appreciate architecture, you may even need to commit a murder"; + /// let P = RistrettoPoint::hash_from_bytes::(msg.as_bytes()); + /// # } + /// ``` + /// + pub fn hash_from_bytes(input: &[u8]) -> RistrettoPoint + where D: Digest + Default + { + let mut hash = D::default(); + hash.input(input); + RistrettoPoint::from_hash(hash) + } + + /// Construct a `RistrettoPoint` from an existing `Digest` instance. + /// + /// Use this instead of `hash_from_bytes` if it is more convenient + /// to stream data into the `Digest` than to pass a single byte + /// slice. + pub fn from_hash(hash: D) -> RistrettoPoint + where D: Digest + Default + { + // dealing with generic arrays is clumsy, until const generics land + let output = hash.result(); + let mut output_bytes = [0u8; 64]; + output_bytes.copy_from_slice(&output.as_slice()); + + RistrettoPoint::from_uniform_bytes(&output_bytes) + } + + /// Construct a `RistrettoPoint` from 64 bytes of data. + /// + /// If the input bytes are uniformly distributed, the resulting + /// point will be uniformly distributed over the group, and its + /// discrete log with respect to other points should be unknown. + /// + /// # Implementation + /// + /// This function splits the input array into two 32-byte halves, + /// takes the low 255 bits of each half mod p, applies the + /// Ristretto-flavored Elligator map to each, and adds the results. + pub fn from_uniform_bytes(bytes: &[u8; 64]) -> RistrettoPoint { + let mut r_1_bytes = [0u8; 32]; + r_1_bytes.copy_from_slice(&bytes[0..32]); + let r_1 = FieldElement::from_bytes(&r_1_bytes); + let R_1 = RistrettoPoint::elligator_ristretto_flavor(&r_1); + + let mut r_2_bytes = [0u8; 32]; + r_2_bytes.copy_from_slice(&bytes[32..64]); + let r_2 = FieldElement::from_bytes(&r_2_bytes); + let R_2 = RistrettoPoint::elligator_ristretto_flavor(&r_2); + + // Applying Elligator twice and adding the results ensures a + // uniform distribution. + &R_1 + &R_2 + } +} + +impl Identity for RistrettoPoint { + fn identity() -> RistrettoPoint { + RistrettoPoint(EdwardsPoint::identity()) + } +} + +impl Default for RistrettoPoint { + fn default() -> RistrettoPoint { + RistrettoPoint::identity() + } +} + +// ------------------------------------------------------------------------ +// Equality +// ------------------------------------------------------------------------ + +impl PartialEq for RistrettoPoint { + fn eq(&self, other: &RistrettoPoint) -> bool { + self.ct_eq(other).unwrap_u8() == 1u8 + } +} + +impl ConstantTimeEq for RistrettoPoint { + /// Test equality between two `RistrettoPoint`s. + /// + /// # Returns + /// + /// * `Choice(1)` if the two `RistrettoPoint`s are equal; + /// * `Choice(0)` otherwise. + fn ct_eq(&self, other: &RistrettoPoint) -> Choice { + let X1Y2 = &self.0.X * &other.0.Y; + let Y1X2 = &self.0.Y * &other.0.X; + let X1X2 = &self.0.X * &other.0.X; + let Y1Y2 = &self.0.Y * &other.0.Y; + + X1Y2.ct_eq(&Y1X2) | X1X2.ct_eq(&Y1Y2) + } +} + +impl Eq for RistrettoPoint {} + +// ------------------------------------------------------------------------ +// Arithmetic +// ------------------------------------------------------------------------ + +impl<'a, 'b> Add<&'b RistrettoPoint> for &'a RistrettoPoint { + type Output = RistrettoPoint; + + fn add(self, other: &'b RistrettoPoint) -> RistrettoPoint { + RistrettoPoint(&self.0 + &other.0) + } +} + +define_add_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint, Output = RistrettoPoint); + +impl<'b> AddAssign<&'b RistrettoPoint> for RistrettoPoint { + fn add_assign(&mut self, _rhs: &RistrettoPoint) { + *self = (self as &RistrettoPoint) + _rhs; + } +} + +define_add_assign_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint); + +impl<'a, 'b> Sub<&'b RistrettoPoint> for &'a RistrettoPoint { + type Output = RistrettoPoint; + + fn sub(self, other: &'b RistrettoPoint) -> RistrettoPoint { + RistrettoPoint(&self.0 - &other.0) + } +} + +define_sub_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint, Output = RistrettoPoint); + +impl<'b> SubAssign<&'b RistrettoPoint> for RistrettoPoint { + fn sub_assign(&mut self, _rhs: &RistrettoPoint) { + *self = (self as &RistrettoPoint) - _rhs; + } +} + +define_sub_assign_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint); + +impl Sum for RistrettoPoint +where + T: Borrow +{ + fn sum(iter: I) -> Self + where + I: Iterator + { + iter.fold(RistrettoPoint::identity(), |acc, item| acc + item.borrow()) + } +} + +impl<'a> Neg for &'a RistrettoPoint { + type Output = RistrettoPoint; + + fn neg(self) -> RistrettoPoint { + RistrettoPoint(-&self.0) + } +} + +impl Neg for RistrettoPoint { + type Output = RistrettoPoint; + + fn neg(self) -> RistrettoPoint { + -&self + } +} + +impl<'b> MulAssign<&'b Scalar> for RistrettoPoint { + fn mul_assign(&mut self, scalar: &'b Scalar) { + let result = (self as &RistrettoPoint) * scalar; + *self = result; + } +} + +impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoPoint { + type Output = RistrettoPoint; + /// Scalar multiplication: compute `scalar * self`. + fn mul(self, scalar: &'b Scalar) -> RistrettoPoint { + RistrettoPoint(self.0 * scalar) + } +} + +impl<'a, 'b> Mul<&'b RistrettoPoint> for &'a Scalar { + type Output = RistrettoPoint; + + /// Scalar multiplication: compute `self * scalar`. + fn mul(self, point: &'b RistrettoPoint) -> RistrettoPoint { + RistrettoPoint(self * point.0) + } +} + +define_mul_assign_variants!(LHS = RistrettoPoint, RHS = Scalar); + +define_mul_variants!(LHS = RistrettoPoint, RHS = Scalar, Output = RistrettoPoint); +define_mul_variants!(LHS = Scalar, RHS = RistrettoPoint, Output = RistrettoPoint); + +// ------------------------------------------------------------------------ +// Multiscalar Multiplication impls +// ------------------------------------------------------------------------ + +// These use iterator combinators to unwrap the underlying points and +// forward to the EdwardsPoint implementations. + +#[cfg(feature = "alloc")] +impl MultiscalarMul for RistrettoPoint { + type Point = RistrettoPoint; + + fn multiscalar_mul(scalars: I, points: J) -> RistrettoPoint + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + { + let extended_points = points.into_iter().map(|P| P.borrow().0); + RistrettoPoint( + EdwardsPoint::multiscalar_mul(scalars, extended_points) + ) + } +} + +#[cfg(feature = "alloc")] +impl VartimeMultiscalarMul for RistrettoPoint { + type Point = RistrettoPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + let extended_points = points.into_iter().map(|opt_P| opt_P.map(|P| P.borrow().0)); + + EdwardsPoint::optional_multiscalar_mul(scalars, extended_points).map(RistrettoPoint) + } +} + +/// Precomputation for variable-time multiscalar multiplication with `RistrettoPoint`s. +// This wraps the inner implementation in a facade type so that we can +// decouple stability of the inner type from the stability of the +// outer type. +#[cfg(feature = "alloc")] +pub struct VartimeRistrettoPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); + +#[cfg(feature = "alloc")] +impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation { + type Point = RistrettoPoint; + + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + Self( + scalar_mul::precomputed_straus::VartimePrecomputedStraus::new( + static_points.into_iter().map(|P| P.borrow().0), + ), + ) + } + + fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator>, + { + self.0 + .optional_mixed_multiscalar_mul( + static_scalars, + dynamic_scalars, + dynamic_points.into_iter().map(|P_opt| P_opt.map(|P| P.0)), + ) + .map(RistrettoPoint) + } +} + +impl RistrettoPoint { + /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the + /// Ristretto basepoint. + pub fn vartime_double_scalar_mul_basepoint( + a: &Scalar, + A: &RistrettoPoint, + b: &Scalar, + ) -> RistrettoPoint { + RistrettoPoint( + EdwardsPoint::vartime_double_scalar_mul_basepoint(a, &A.0, b) + ) + } +} + +/// A precomputed table of multiples of a basepoint, used to accelerate +/// scalar multiplication. +/// +/// A precomputed table of multiples of the Ristretto basepoint is +/// available in the `constants` module: +/// ``` +/// use curve25519_dalek::constants; +/// use curve25519_dalek::scalar::Scalar; +/// +/// let a = Scalar::from(87329482u64); +/// let P = &a * &constants::RISTRETTO_BASEPOINT_TABLE; +/// ``` +#[derive(Clone)] +pub struct RistrettoBasepointTable(pub(crate) EdwardsBasepointTable); + +impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable { + type Output = RistrettoPoint; + + fn mul(self, scalar: &'b Scalar) -> RistrettoPoint { + RistrettoPoint(&self.0 * scalar) + } +} + +impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar { + type Output = RistrettoPoint; + + fn mul(self, basepoint_table: &'a RistrettoBasepointTable) -> RistrettoPoint { + RistrettoPoint(self * &basepoint_table.0) + } +} + +impl RistrettoBasepointTable { + /// Create a precomputed table of multiples of the given `basepoint`. + pub fn create(basepoint: &RistrettoPoint) -> RistrettoBasepointTable { + RistrettoBasepointTable(EdwardsBasepointTable::create(&basepoint.0)) + } + + /// Get the basepoint for this table as a `RistrettoPoint`. + pub fn basepoint(&self) -> RistrettoPoint { + RistrettoPoint(self.0.basepoint()) + } +} + +// ------------------------------------------------------------------------ +// Constant-time conditional selection +// ------------------------------------------------------------------------ + +impl ConditionallySelectable for RistrettoPoint { + /// Conditionally select between `self` and `other`. + /// + /// # Example + /// + /// ``` + /// # extern crate subtle; + /// # extern crate curve25519_dalek; + /// # + /// use subtle::ConditionallySelectable; + /// use subtle::Choice; + /// # + /// # use curve25519_dalek::traits::Identity; + /// # use curve25519_dalek::ristretto::RistrettoPoint; + /// # use curve25519_dalek::constants; + /// # fn main() { + /// + /// let A = RistrettoPoint::identity(); + /// let B = constants::RISTRETTO_BASEPOINT_POINT; + /// + /// let mut P = A; + /// + /// P = RistrettoPoint::conditional_select(&A, &B, Choice::from(0)); + /// assert_eq!(P, A); + /// P = RistrettoPoint::conditional_select(&A, &B, Choice::from(1)); + /// assert_eq!(P, B); + /// # } + /// ``` + fn conditional_select( + a: &RistrettoPoint, + b: &RistrettoPoint, + choice: Choice, + ) -> RistrettoPoint { + RistrettoPoint(EdwardsPoint::conditional_select(&a.0, &b.0, choice)) + } +} + +// ------------------------------------------------------------------------ +// Debug traits +// ------------------------------------------------------------------------ + +impl Debug for CompressedRistretto { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "CompressedRistretto: {:?}", self.as_bytes()) + } +} + +impl Debug for RistrettoPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + let coset = self.coset4(); + write!(f, "RistrettoPoint: coset \n{:?}\n{:?}\n{:?}\n{:?}", + coset[0], coset[1], coset[2], coset[3]) + } +} + +// ------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------ + +#[cfg(test)] +mod test { + use rand_core::OsRng; + + use scalar::Scalar; + use constants; + use edwards::CompressedEdwardsY; + use traits::{Identity}; + use super::*; + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_basepoint_roundtrip() { + use bincode; + + let encoded = bincode::serialize(&constants::RISTRETTO_BASEPOINT_POINT).unwrap(); + let enc_compressed = bincode::serialize(&constants::RISTRETTO_BASEPOINT_COMPRESSED).unwrap(); + assert_eq!(encoded, enc_compressed); + + // Check that the encoding is 32 bytes exactly + assert_eq!(encoded.len(), 32); + + let dec_uncompressed: RistrettoPoint = bincode::deserialize(&encoded).unwrap(); + let dec_compressed: CompressedRistretto = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(dec_uncompressed, constants::RISTRETTO_BASEPOINT_POINT); + assert_eq!(dec_compressed, constants::RISTRETTO_BASEPOINT_COMPRESSED); + + // Check that the encoding itself matches the usual one + let raw_bytes = constants::RISTRETTO_BASEPOINT_COMPRESSED.as_bytes(); + let bp: RistrettoPoint = bincode::deserialize(raw_bytes).unwrap(); + assert_eq!(bp, constants::RISTRETTO_BASEPOINT_POINT); + } + + #[test] + fn scalarmult_ristrettopoint_works_both_ways() { + let P = constants::RISTRETTO_BASEPOINT_POINT; + let s = Scalar::from(999u64); + + let P1 = &P * &s; + let P2 = &s * &P; + + assert!(P1.compress().as_bytes() == P2.compress().as_bytes()); + } + + #[test] + fn impl_sum() { + + // Test that sum works for non-empty iterators + let BASE = constants::RISTRETTO_BASEPOINT_POINT; + + let s1 = Scalar::from(999u64); + let P1 = &BASE * &s1; + + let s2 = Scalar::from(333u64); + let P2 = &BASE * &s2; + + let vec = vec![P1.clone(), P2.clone()]; + let sum: RistrettoPoint = vec.iter().sum(); + + assert_eq!(sum, P1 + P2); + + // Test that sum works for the empty iterator + let empty_vector: Vec = vec![]; + let sum: RistrettoPoint = empty_vector.iter().sum(); + + assert_eq!(sum, RistrettoPoint::identity()); + + // Test that sum works on owning iterators + let s = Scalar::from(2u64); + let mapped = vec.iter().map(|x| x * s); + let sum: RistrettoPoint = mapped.sum(); + + assert_eq!(sum, &P1 * &s + &P2 * &s); + } + + #[test] + fn decompress_negative_s_fails() { + // constants::d is neg, so decompression should fail as |d| != d. + let bad_compressed = CompressedRistretto(constants::EDWARDS_D.to_bytes()); + assert!(bad_compressed.decompress().is_none()); + } + + #[test] + fn decompress_id() { + let compressed_id = CompressedRistretto::identity(); + let id = compressed_id.decompress().unwrap(); + let mut identity_in_coset = false; + for P in &id.coset4() { + if P.compress() == CompressedEdwardsY::identity() { + identity_in_coset = true; + } + } + assert!(identity_in_coset); + } + + #[test] + fn compress_id() { + let id = RistrettoPoint::identity(); + assert_eq!(id.compress(), CompressedRistretto::identity()); + } + + #[test] + fn basepoint_roundtrip() { + let bp_compressed_ristretto = constants::RISTRETTO_BASEPOINT_POINT.compress(); + let bp_recaf = bp_compressed_ristretto.decompress().unwrap().0; + // Check that bp_recaf differs from bp by a point of order 4 + let diff = &constants::RISTRETTO_BASEPOINT_POINT.0 - &bp_recaf; + let diff4 = diff.mul_by_pow_2(2); + assert_eq!(diff4.compress(), CompressedEdwardsY::identity()); + } + + #[test] + fn encodings_of_small_multiples_of_basepoint() { + // Table of encodings of i*basepoint + // Generated using ristretto.sage + let compressed = [ + CompressedRistretto([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + CompressedRistretto([226, 242, 174, 10, 106, 188, 78, 113, 168, 132, 169, 97, 197, 0, 81, 95, 88, 227, 11, 106, 165, 130, 221, 141, 182, 166, 89, 69, 224, 141, 45, 118]), + CompressedRistretto([106, 73, 50, 16, 247, 73, 156, 209, 127, 236, 181, 16, 174, 12, 234, 35, 161, 16, 232, 213, 185, 1, 248, 172, 173, 211, 9, 92, 115, 163, 185, 25]), + CompressedRistretto([148, 116, 31, 93, 93, 82, 117, 94, 206, 79, 35, 240, 68, 238, 39, 213, 209, 234, 30, 43, 209, 150, 180, 98, 22, 107, 22, 21, 42, 157, 2, 89]), + CompressedRistretto([218, 128, 134, 39, 115, 53, 139, 70, 111, 250, 223, 224, 179, 41, 58, 179, 217, 253, 83, 197, 234, 108, 149, 83, 88, 245, 104, 50, 45, 175, 106, 87]), + CompressedRistretto([232, 130, 177, 49, 1, 107, 82, 193, 211, 51, 112, 128, 24, 124, 247, 104, 66, 62, 252, 203, 181, 23, 187, 73, 90, 184, 18, 196, 22, 15, 244, 78]), + CompressedRistretto([246, 71, 70, 211, 201, 43, 19, 5, 14, 216, 216, 2, 54, 167, 240, 0, 124, 59, 63, 150, 47, 91, 167, 147, 209, 154, 96, 30, 187, 29, 244, 3]), + CompressedRistretto([68, 245, 53, 32, 146, 110, 200, 31, 189, 90, 56, 120, 69, 190, 183, 223, 133, 169, 106, 36, 236, 225, 135, 56, 189, 207, 166, 167, 130, 42, 23, 109]), + CompressedRistretto([144, 50, 147, 216, 242, 40, 126, 190, 16, 226, 55, 77, 193, 165, 62, 11, 200, 135, 229, 146, 105, 159, 2, 208, 119, 213, 38, 60, 221, 85, 96, 28]), + CompressedRistretto([2, 98, 42, 206, 143, 115, 3, 163, 28, 175, 198, 63, 143, 196, 143, 220, 22, 225, 200, 200, 210, 52, 178, 240, 214, 104, 82, 130, 169, 7, 96, 49]), + CompressedRistretto([32, 112, 111, 215, 136, 178, 114, 10, 30, 210, 165, 218, 212, 149, 43, 1, 244, 19, 188, 240, 231, 86, 77, 232, 205, 200, 22, 104, 158, 45, 185, 95]), + CompressedRistretto([188, 232, 63, 139, 165, 221, 47, 165, 114, 134, 76, 36, 186, 24, 16, 249, 82, 43, 198, 0, 74, 254, 149, 135, 122, 199, 50, 65, 202, 253, 171, 66]), + CompressedRistretto([228, 84, 158, 225, 107, 154, 160, 48, 153, 202, 32, 140, 103, 173, 175, 202, 250, 76, 63, 62, 78, 83, 3, 222, 96, 38, 227, 202, 143, 248, 68, 96]), + CompressedRistretto([170, 82, 224, 0, 223, 46, 22, 245, 95, 177, 3, 47, 195, 59, 196, 39, 66, 218, 214, 189, 90, 143, 192, 190, 1, 103, 67, 108, 89, 72, 80, 31]), + CompressedRistretto([70, 55, 107, 128, 244, 9, 178, 157, 194, 181, 246, 240, 197, 37, 145, 153, 8, 150, 229, 113, 111, 65, 71, 124, 211, 0, 133, 171, 127, 16, 48, 30]), + CompressedRistretto([224, 196, 24, 247, 200, 217, 196, 205, 215, 57, 91, 147, 234, 18, 79, 58, 217, 144, 33, 187, 104, 29, 252, 51, 2, 169, 217, 154, 46, 83, 230, 78]), + ]; + let mut bp = RistrettoPoint::identity(); + for i in 0..16 { + assert_eq!(bp.compress(), compressed[i]); + bp = &bp + &constants::RISTRETTO_BASEPOINT_POINT; + } + } + + #[test] + fn four_torsion_basepoint() { + let bp = constants::RISTRETTO_BASEPOINT_POINT; + let bp_coset = bp.coset4(); + for i in 0..4 { + assert_eq!(bp, RistrettoPoint(bp_coset[i])); + } + } + + #[test] + fn four_torsion_random() { + let mut rng = OsRng; + let B = &constants::RISTRETTO_BASEPOINT_TABLE; + let P = B * &Scalar::random(&mut rng); + let P_coset = P.coset4(); + for i in 0..4 { + assert_eq!(P, RistrettoPoint(P_coset[i])); + } + } + + #[test] + fn elligator_vs_ristretto_sage() { + // Test vectors extracted from ristretto.sage. + // + // Notice that all of the byte sequences have bit 255 set to 0; this is because + // ristretto.sage does not mask the high bit of a field element. When the high bit is set, + // the ristretto.sage elligator implementation gives different results, since it takes a + // different field element as input. + let bytes: [[u8;32]; 16] = [ + [184, 249, 135, 49, 253, 123, 89, 113, 67, 160, 6, 239, 7, 105, 211, 41, 192, 249, 185, 57, 9, 102, 70, 198, 15, 127, 7, 26, 160, 102, 134, 71], + [229, 14, 241, 227, 75, 9, 118, 60, 128, 153, 226, 21, 183, 217, 91, 136, 98, 0, 231, 156, 124, 77, 82, 139, 142, 134, 164, 169, 169, 62, 250, 52], + [115, 109, 36, 220, 180, 223, 99, 6, 204, 169, 19, 29, 169, 68, 84, 23, 21, 109, 189, 149, 127, 205, 91, 102, 172, 35, 112, 35, 134, 69, 186, 34], + [16, 49, 96, 107, 171, 199, 164, 9, 129, 16, 64, 62, 241, 63, 132, 173, 209, 160, 112, 215, 105, 50, 157, 81, 253, 105, 1, 154, 229, 25, 120, 83], + [156, 131, 161, 162, 236, 251, 5, 187, 167, 171, 17, 178, 148, 210, 90, 207, 86, 21, 79, 161, 167, 215, 234, 1, 136, 242, 182, 248, 38, 85, 79, 86], + [251, 177, 124, 54, 18, 101, 75, 235, 245, 186, 19, 46, 133, 157, 229, 64, 10, 136, 181, 185, 78, 144, 254, 167, 137, 49, 107, 10, 61, 10, 21, 25], + [232, 193, 20, 68, 240, 77, 186, 77, 183, 40, 44, 86, 150, 31, 198, 212, 76, 81, 3, 217, 197, 8, 126, 128, 126, 152, 164, 208, 153, 44, 189, 77], + [173, 229, 149, 177, 37, 230, 30, 69, 61, 56, 172, 190, 219, 115, 167, 194, 71, 134, 59, 75, 28, 244, 118, 26, 162, 97, 64, 16, 15, 189, 30, 64], + [106, 71, 61, 107, 250, 117, 42, 151, 91, 202, 212, 100, 52, 188, 190, 21, 125, 218, 31, 18, 253, 241, 160, 133, 57, 242, 3, 164, 189, 68, 111, 75], + [112, 204, 182, 90, 220, 198, 120, 73, 173, 107, 193, 17, 227, 40, 162, 36, 150, 141, 235, 55, 172, 183, 12, 39, 194, 136, 43, 153, 244, 118, 91, 89], + [111, 24, 203, 123, 254, 189, 11, 162, 51, 196, 163, 136, 204, 143, 10, 222, 33, 112, 81, 205, 34, 35, 8, 66, 90, 6, 164, 58, 170, 177, 34, 25], + [225, 183, 30, 52, 236, 82, 6, 183, 109, 25, 227, 181, 25, 82, 41, 193, 80, 77, 161, 80, 242, 203, 79, 204, 136, 245, 131, 110, 237, 106, 3, 58], + [207, 246, 38, 56, 30, 86, 176, 90, 27, 200, 61, 42, 221, 27, 56, 210, 79, 178, 189, 120, 68, 193, 120, 167, 77, 185, 53, 197, 124, 128, 191, 126], + [1, 136, 215, 80, 240, 46, 63, 147, 16, 244, 230, 207, 82, 189, 74, 50, 106, 169, 138, 86, 30, 131, 214, 202, 166, 125, 251, 228, 98, 24, 36, 21], + [210, 207, 228, 56, 155, 116, 207, 54, 84, 195, 251, 215, 249, 199, 116, 75, 109, 239, 196, 251, 194, 246, 252, 228, 70, 146, 156, 35, 25, 39, 241, 4], + [34, 116, 123, 9, 8, 40, 93, 189, 9, 103, 57, 103, 66, 227, 3, 2, 157, 107, 134, 219, 202, 74, 230, 154, 78, 107, 219, 195, 214, 14, 84, 80], + ]; + let encoded_images: [CompressedRistretto; 16] = [ + CompressedRistretto([176, 157, 237, 97, 66, 29, 140, 166, 168, 94, 26, 157, 212, 216, 229, 160, 195, 246, 232, 239, 169, 112, 63, 193, 64, 32, 152, 69, 11, 190, 246, 86]), + CompressedRistretto([234, 141, 77, 203, 181, 225, 250, 74, 171, 62, 15, 118, 78, 212, 150, 19, 131, 14, 188, 238, 194, 244, 141, 138, 166, 162, 83, 122, 228, 201, 19, 26]), + CompressedRistretto([232, 231, 51, 92, 5, 168, 80, 36, 173, 179, 104, 68, 186, 149, 68, 40, 140, 170, 27, 103, 99, 140, 21, 242, 43, 62, 250, 134, 208, 255, 61, 89]), + CompressedRistretto([208, 120, 140, 129, 177, 179, 237, 159, 252, 160, 28, 13, 206, 5, 211, 241, 192, 218, 1, 97, 130, 241, 20, 169, 119, 46, 246, 29, 79, 80, 77, 84]), + CompressedRistretto([202, 11, 236, 145, 58, 12, 181, 157, 209, 6, 213, 88, 75, 147, 11, 119, 191, 139, 47, 142, 33, 36, 153, 193, 223, 183, 178, 8, 205, 120, 248, 110]), + CompressedRistretto([26, 66, 231, 67, 203, 175, 116, 130, 32, 136, 62, 253, 215, 46, 5, 214, 166, 248, 108, 237, 216, 71, 244, 173, 72, 133, 82, 6, 143, 240, 104, 41]), + CompressedRistretto([40, 157, 102, 96, 201, 223, 200, 197, 150, 181, 106, 83, 103, 126, 143, 33, 145, 230, 78, 6, 171, 146, 210, 143, 112, 5, 245, 23, 183, 138, 18, 120]), + CompressedRistretto([220, 37, 27, 203, 239, 196, 176, 131, 37, 66, 188, 243, 185, 250, 113, 23, 167, 211, 154, 243, 168, 215, 54, 171, 159, 36, 195, 81, 13, 150, 43, 43]), + CompressedRistretto([232, 121, 176, 222, 183, 196, 159, 90, 238, 193, 105, 52, 101, 167, 244, 170, 121, 114, 196, 6, 67, 152, 80, 185, 221, 7, 83, 105, 176, 208, 224, 121]), + CompressedRistretto([226, 181, 183, 52, 241, 163, 61, 179, 221, 207, 220, 73, 245, 242, 25, 236, 67, 84, 179, 222, 167, 62, 167, 182, 32, 9, 92, 30, 165, 127, 204, 68]), + CompressedRistretto([226, 119, 16, 242, 200, 139, 240, 87, 11, 222, 92, 146, 156, 243, 46, 119, 65, 59, 1, 248, 92, 183, 50, 175, 87, 40, 206, 53, 208, 220, 148, 13]), + CompressedRistretto([70, 240, 79, 112, 54, 157, 228, 146, 74, 122, 216, 88, 232, 62, 158, 13, 14, 146, 115, 117, 176, 222, 90, 225, 244, 23, 94, 190, 150, 7, 136, 96]), + CompressedRistretto([22, 71, 241, 103, 45, 193, 195, 144, 183, 101, 154, 50, 39, 68, 49, 110, 51, 44, 62, 0, 229, 113, 72, 81, 168, 29, 73, 106, 102, 40, 132, 24]), + CompressedRistretto([196, 133, 107, 11, 130, 105, 74, 33, 204, 171, 133, 221, 174, 193, 241, 36, 38, 179, 196, 107, 219, 185, 181, 253, 228, 47, 155, 42, 231, 73, 41, 78]), + CompressedRistretto([58, 255, 225, 197, 115, 208, 160, 143, 39, 197, 82, 69, 143, 235, 92, 170, 74, 40, 57, 11, 171, 227, 26, 185, 217, 207, 90, 185, 197, 190, 35, 60]), + CompressedRistretto([88, 43, 92, 118, 223, 136, 105, 145, 238, 186, 115, 8, 214, 112, 153, 253, 38, 108, 205, 230, 157, 130, 11, 66, 101, 85, 253, 110, 110, 14, 148, 112]), + ]; + for i in 0..16 { + let r_0 = FieldElement::from_bytes(&bytes[i]); + let Q = RistrettoPoint::elligator_ristretto_flavor(&r_0); + assert_eq!(Q.compress(), encoded_images[i]); + } + } + + #[test] + fn random_roundtrip() { + let mut rng = OsRng; + let B = &constants::RISTRETTO_BASEPOINT_TABLE; + for _ in 0..100 { + let P = B * &Scalar::random(&mut rng); + let compressed_P = P.compress(); + let Q = compressed_P.decompress().unwrap(); + assert_eq!(P, Q); + } + } + + #[test] + fn double_and_compress_1024_random_points() { + let mut rng = OsRng; + + let points: Vec = + (0..1024).map(|_| RistrettoPoint::random(&mut rng)).collect(); + + let compressed = RistrettoPoint::double_and_compress_batch(&points); + + for (P, P2_compressed) in points.iter().zip(compressed.iter()) { + assert_eq!(*P2_compressed, (P + P).compress()); + } + } + + #[test] + fn vartime_precomputed_vs_nonprecomputed_multiscalar() { + let mut rng = rand::thread_rng(); + + let B = &::constants::RISTRETTO_BASEPOINT_TABLE; + + let static_scalars = (0..128) + .map(|_| Scalar::random(&mut rng)) + .collect::>(); + + let dynamic_scalars = (0..128) + .map(|_| Scalar::random(&mut rng)) + .collect::>(); + + let check_scalar: Scalar = static_scalars + .iter() + .chain(dynamic_scalars.iter()) + .map(|s| s * s) + .sum(); + + let static_points = static_scalars.iter().map(|s| s * B).collect::>(); + let dynamic_points = dynamic_scalars.iter().map(|s| s * B).collect::>(); + + let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter()); + + let P = precomputation.vartime_mixed_multiscalar_mul( + &static_scalars, + &dynamic_scalars, + &dynamic_points, + ); + + use traits::VartimeMultiscalarMul; + let Q = RistrettoPoint::vartime_multiscalar_mul( + static_scalars.iter().chain(dynamic_scalars.iter()), + static_points.iter().chain(dynamic_points.iter()), + ); + + let R = &check_scalar * B; + + assert_eq!(P.compress(), R.compress()); + assert_eq!(Q.compress(), R.compress()); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/scalar.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/scalar.rs new file mode 100644 index 0000000..d365d25 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/scalar.rs @@ -0,0 +1,1739 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// Portions Copyright 2017 Brian Smith +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence +// - Brian Smith + +//! Arithmetic on scalars (integers mod the group order). +//! +//! Both the Ristretto group and the Ed25519 basepoint have prime order +//! \\( \ell = 2\^{252} + 27742317777372353535851937790883648493 \\). +//! +//! This code is intended to be useful with both the Ristretto group +//! (where everything is done modulo \\( \ell \\)), and the X/Ed25519 +//! setting, which mandates specific bit-twiddles that are not +//! well-defined modulo \\( \ell \\). +//! +//! All arithmetic on `Scalars` is done modulo \\( \ell \\). +//! +//! # Constructing a scalar +//! +//! To create a [`Scalar`](struct.Scalar.html) from a supposedly canonical encoding, use +//! [`Scalar::from_canonical_bytes`](struct.Scalar.html#method.from_canonical_bytes). +//! +//! This function does input validation, ensuring that the input bytes +//! are the canonical encoding of a `Scalar`. +//! If they are, we'll get +//! `Some(Scalar)` in return: +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let one_as_bytes: [u8; 32] = Scalar::one().to_bytes(); +//! let a: Option = Scalar::from_canonical_bytes(one_as_bytes); +//! +//! assert!(a.is_some()); +//! ``` +//! +//! However, if we give it bytes representing a scalar larger than \\( \ell \\) +//! (in this case, \\( \ell + 2 \\)), we'll get `None` back: +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let l_plus_two_bytes: [u8; 32] = [ +//! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, +//! 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, +//! ]; +//! let a: Option = Scalar::from_canonical_bytes(l_plus_two_bytes); +//! +//! assert!(a.is_none()); +//! ``` +//! +//! Another way to create a `Scalar` is by reducing a \\(256\\)-bit integer mod +//! \\( \ell \\), for which one may use the +//! [`Scalar::from_bytes_mod_order`](struct.Scalar.html#method.from_bytes_mod_order) +//! method. In the case of the second example above, this would reduce the +//! resultant scalar \\( \mod \ell \\), producing \\( 2 \\): +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let l_plus_two_bytes: [u8; 32] = [ +//! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, +//! 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, +//! ]; +//! let a: Scalar = Scalar::from_bytes_mod_order(l_plus_two_bytes); +//! +//! let two: Scalar = Scalar::one() + Scalar::one(); +//! +//! assert!(a == two); +//! ``` +//! +//! There is also a constructor that reduces a \\(512\\)-bit integer, +//! [`Scalar::from_bytes_mod_order_wide`](struct.Scalar.html#method.from_bytes_mod_order_wide). +//! +//! To construct a `Scalar` as the hash of some input data, use +//! [`Scalar::hash_from_bytes`](struct.Scalar.html#method.hash_from_bytes), +//! which takes a buffer, or +//! [`Scalar::from_hash`](struct.Scalar.html#method.from_hash), +//! which allows an IUF API. +//! +//! ``` +//! # extern crate curve25519_dalek; +//! # extern crate sha2; +//! # +//! # fn main() { +//! use sha2::{Digest, Sha512}; +//! use curve25519_dalek::scalar::Scalar; +//! +//! // Hashing a single byte slice +//! let a = Scalar::hash_from_bytes::(b"Abolish ICE"); +//! +//! // Streaming data into a hash object +//! let mut hasher = Sha512::default(); +//! hasher.input(b"Abolish "); +//! hasher.input(b"ICE"); +//! let a2 = Scalar::from_hash(hasher); +//! +//! assert_eq!(a, a2); +//! # } +//! ``` +//! +//! Finally, to create a `Scalar` with a specific bit-pattern +//! (e.g., for compatibility with X/Ed25519 +//! ["clamping"](https://github.com/isislovecruft/ed25519-dalek/blob/f790bd2ce/src/ed25519.rs#L349)), +//! use [`Scalar::from_bits`](struct.Scalar.html#method.from_bits). This +//! constructs a scalar with exactly the bit pattern given, without any +//! assurances as to reduction modulo the group order: +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let l_plus_two_bytes: [u8; 32] = [ +//! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, +//! 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, +//! ]; +//! let a: Scalar = Scalar::from_bits(l_plus_two_bytes); +//! +//! let two: Scalar = Scalar::one() + Scalar::one(); +//! +//! assert!(a != two); // the scalar is not reduced (mod l)… +//! assert!(! a.is_canonical()); // …and therefore is not canonical. +//! assert!(a.reduce() == two); // if we were to reduce it manually, it would be. +//! ``` +//! +//! The resulting `Scalar` has exactly the specified bit pattern, +//! **except for the highest bit, which will be set to 0**. + +use core::borrow::Borrow; +use core::cmp::{Eq, PartialEq}; +use core::fmt::Debug; +use core::iter::{Product, Sum}; +use core::ops::Index; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Sub, SubAssign}; + +#[allow(unused_imports)] +use prelude::*; + +use rand_core::{CryptoRng, RngCore}; + +use digest::generic_array::typenum::U64; +use digest::Digest; + +use subtle::Choice; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; + +use zeroize::Zeroize; + +use backend; +use constants; + +/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. +/// +/// This is a type alias for one of the scalar types in the `backend` +/// module. +#[cfg(feature = "u64_backend")] +type UnpackedScalar = backend::serial::u64::scalar::Scalar52; + +/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. +/// +/// This is a type alias for one of the scalar types in the `backend` +/// module. +#[cfg(feature = "u32_backend")] +type UnpackedScalar = backend::serial::u32::scalar::Scalar29; + + +/// The `Scalar` struct holds an integer \\(s < 2\^{255} \\) which +/// represents an element of \\(\mathbb Z / \ell\\). +#[derive(Copy, Clone)] +pub struct Scalar { + /// `bytes` is a little-endian byte encoding of an integer representing a scalar modulo the + /// group order. + /// + /// # Invariant + /// + /// The integer representing this scalar must be bounded above by \\(2\^{255}\\), or + /// equivalently the high bit of `bytes[31]` must be zero. + /// + /// This ensures that there is room for a carry bit when computing a NAF representation. + // + // XXX This is pub(crate) so we can write literal constants. If const fns were stable, we could + // make the Scalar constructors const fns and use those instead. + pub(crate) bytes: [u8; 32], +} + +impl Scalar { + /// Construct a `Scalar` by reducing a 256-bit little-endian integer + /// modulo the group order \\( \ell \\). + pub fn from_bytes_mod_order(bytes: [u8; 32]) -> Scalar { + // Temporarily allow s_unreduced.bytes > 2^255 ... + let s_unreduced = Scalar{bytes}; + + // Then reduce mod the group order and return the reduced representative. + let s = s_unreduced.reduce(); + debug_assert_eq!(0u8, s[31] >> 7); + + s + } + + /// Construct a `Scalar` by reducing a 512-bit little-endian integer + /// modulo the group order \\( \ell \\). + pub fn from_bytes_mod_order_wide(input: &[u8; 64]) -> Scalar { + UnpackedScalar::from_bytes_wide(input).pack() + } + + /// Attempt to construct a `Scalar` from a canonical byte representation. + /// + /// # Return + /// + /// - `Some(s)`, where `s` is the `Scalar` corresponding to `bytes`, + /// if `bytes` is a canonical byte representation; + /// - `None` if `bytes` is not a canonical byte representation. + pub fn from_canonical_bytes(bytes: [u8; 32]) -> Option { + // Check that the high bit is not set + if (bytes[31] >> 7) != 0u8 { return None; } + let candidate = Scalar::from_bits(bytes); + + if candidate.is_canonical() { + Some(candidate) + } else { + None + } + } + + /// Construct a `Scalar` from the low 255 bits of a 256-bit integer. + /// + /// This function is intended for applications like X25519 which + /// require specific bit-patterns when performing scalar + /// multiplication. + pub fn from_bits(bytes: [u8; 32]) -> Scalar { + let mut s = Scalar{bytes}; + // Ensure that s < 2^255 by masking the high bit + s.bytes[31] &= 0b0111_1111; + + s + } +} + +impl Debug for Scalar { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "Scalar{{\n\tbytes: {:?},\n}}", &self.bytes) + } +} + +impl Eq for Scalar {} +impl PartialEq for Scalar { + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).unwrap_u8() == 1u8 + } +} + +impl ConstantTimeEq for Scalar { + fn ct_eq(&self, other: &Self) -> Choice { + self.bytes.ct_eq(&other.bytes) + } +} + +impl Index for Scalar { + type Output = u8; + + /// Index the bytes of the representative for this `Scalar`. Mutation is not permitted. + fn index(&self, _index: usize) -> &u8 { + &(self.bytes[_index]) + } +} + +impl<'b> MulAssign<&'b Scalar> for Scalar { + fn mul_assign(&mut self, _rhs: &'b Scalar) { + *self = UnpackedScalar::mul(&self.unpack(), &_rhs.unpack()).pack(); + } +} + +define_mul_assign_variants!(LHS = Scalar, RHS = Scalar); + +impl<'a, 'b> Mul<&'b Scalar> for &'a Scalar { + type Output = Scalar; + fn mul(self, _rhs: &'b Scalar) -> Scalar { + UnpackedScalar::mul(&self.unpack(), &_rhs.unpack()).pack() + } +} + +define_mul_variants!(LHS = Scalar, RHS = Scalar, Output = Scalar); + +impl<'b> AddAssign<&'b Scalar> for Scalar { + fn add_assign(&mut self, _rhs: &'b Scalar) { + *self = *self + _rhs; + } +} + +define_add_assign_variants!(LHS = Scalar, RHS = Scalar); + +impl<'a, 'b> Add<&'b Scalar> for &'a Scalar { + type Output = Scalar; + #[allow(non_snake_case)] + fn add(self, _rhs: &'b Scalar) -> Scalar { + // The UnpackedScalar::add function produces reduced outputs + // if the inputs are reduced. However, these inputs may not + // be reduced -- they might come from Scalar::from_bits. So + // after computing the sum, we explicitly reduce it mod l + // before repacking. + let sum = UnpackedScalar::add(&self.unpack(), &_rhs.unpack()); + let sum_R = UnpackedScalar::mul_internal(&sum, &constants::R); + let sum_mod_l = UnpackedScalar::montgomery_reduce(&sum_R); + sum_mod_l.pack() + } +} + +define_add_variants!(LHS = Scalar, RHS = Scalar, Output = Scalar); + +impl<'b> SubAssign<&'b Scalar> for Scalar { + fn sub_assign(&mut self, _rhs: &'b Scalar) { + *self = *self - _rhs; + } +} + +define_sub_assign_variants!(LHS = Scalar, RHS = Scalar); + +impl<'a, 'b> Sub<&'b Scalar> for &'a Scalar { + type Output = Scalar; + #[allow(non_snake_case)] + fn sub(self, rhs: &'b Scalar) -> Scalar { + // The UnpackedScalar::sub function requires reduced inputs + // and produces reduced output. However, these inputs may not + // be reduced -- they might come from Scalar::from_bits. So + // we explicitly reduce the inputs. + let self_R = UnpackedScalar::mul_internal(&self.unpack(), &constants::R); + let self_mod_l = UnpackedScalar::montgomery_reduce(&self_R); + let rhs_R = UnpackedScalar::mul_internal(&rhs.unpack(), &constants::R); + let rhs_mod_l = UnpackedScalar::montgomery_reduce(&rhs_R); + + UnpackedScalar::sub(&self_mod_l, &rhs_mod_l).pack() + } +} + +define_sub_variants!(LHS = Scalar, RHS = Scalar, Output = Scalar); + +impl<'a> Neg for &'a Scalar { + type Output = Scalar; + #[allow(non_snake_case)] + fn neg(self) -> Scalar { + let self_R = UnpackedScalar::mul_internal(&self.unpack(), &constants::R); + let self_mod_l = UnpackedScalar::montgomery_reduce(&self_R); + UnpackedScalar::sub(&UnpackedScalar::zero(), &self_mod_l).pack() + } +} + +impl<'a> Neg for Scalar { + type Output = Scalar; + fn neg(self) -> Scalar { + -&self + } +} + +impl ConditionallySelectable for Scalar { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = u8::conditional_select(&a.bytes[i], &b.bytes[i], choice); + } + Scalar { bytes } + } +} + +#[cfg(feature = "serde")] +use serde::{self, Serialize, Deserialize, Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +#[cfg(feature = "serde")] +impl Serialize for Scalar { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + use serde::ser::SerializeTuple; + let mut tup = serializer.serialize_tuple(32)?; + for byte in self.as_bytes().iter() { + tup.serialize_element(byte)?; + } + tup.end() + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Scalar { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + struct ScalarVisitor; + + impl<'de> Visitor<'de> for ScalarVisitor { + type Value = Scalar; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("a valid point in Edwards y + sign format") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de> + { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = seq.next_element()? + .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + Scalar::from_canonical_bytes(bytes) + .ok_or(serde::de::Error::custom( + &"scalar was not canonically encoded" + )) + } + } + + deserializer.deserialize_tuple(32, ScalarVisitor) + } +} + +impl Product for Scalar +where + T: Borrow +{ + fn product(iter: I) -> Self + where + I: Iterator + { + iter.fold(Scalar::one(), |acc, item| acc * item.borrow()) + } +} + +impl Sum for Scalar +where + T: Borrow +{ + fn sum(iter: I) -> Self + where + I: Iterator + { + iter.fold(Scalar::zero(), |acc, item| acc + item.borrow()) + } +} + +impl Default for Scalar { + fn default() -> Scalar { + Scalar::zero() + } +} + +impl From for Scalar { + fn from(x: u8) -> Scalar { + let mut s_bytes = [0u8; 32]; + s_bytes[0] = x; + Scalar{ bytes: s_bytes } + } +} + +impl From for Scalar { + fn from(x: u16) -> Scalar { + use byteorder::{ByteOrder, LittleEndian}; + let mut s_bytes = [0u8; 32]; + LittleEndian::write_u16(&mut s_bytes, x); + Scalar{ bytes: s_bytes } + } +} + +impl From for Scalar { + fn from(x: u32) -> Scalar { + use byteorder::{ByteOrder, LittleEndian}; + let mut s_bytes = [0u8; 32]; + LittleEndian::write_u32(&mut s_bytes, x); + Scalar{ bytes: s_bytes } + } +} + +impl From for Scalar { + /// Construct a scalar from the given `u64`. + /// + /// # Inputs + /// + /// An `u64` to convert to a `Scalar`. + /// + /// # Returns + /// + /// A `Scalar` corresponding to the input `u64`. + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::scalar::Scalar; + /// + /// let fourtytwo = Scalar::from(42u64); + /// let six = Scalar::from(6u64); + /// let seven = Scalar::from(7u64); + /// + /// assert!(fourtytwo == six * seven); + /// ``` + fn from(x: u64) -> Scalar { + use byteorder::{ByteOrder, LittleEndian}; + let mut s_bytes = [0u8; 32]; + LittleEndian::write_u64(&mut s_bytes, x); + Scalar{ bytes: s_bytes } + } +} + +impl From for Scalar { + fn from(x: u128) -> Scalar { + use byteorder::{ByteOrder, LittleEndian}; + let mut s_bytes = [0u8; 32]; + LittleEndian::write_u128(&mut s_bytes, x); + Scalar{ bytes: s_bytes } + } +} + +impl Zeroize for Scalar { + fn zeroize(&mut self) { + self.bytes.zeroize(); + } +} + +impl Scalar { + /// Return a `Scalar` chosen uniformly at random using a user-provided RNG. + /// + /// # Inputs + /// + /// * `rng`: any RNG which implements the `RngCore + CryptoRng` interface. + /// + /// # Returns + /// + /// A random scalar within ℤ/lℤ. + /// + /// # Example + /// + /// ``` + /// extern crate rand_core; + /// # extern crate curve25519_dalek; + /// # + /// # fn main() { + /// use curve25519_dalek::scalar::Scalar; + /// + /// use rand_core::OsRng; + /// + /// let mut csprng = OsRng; + /// let a: Scalar = Scalar::random(&mut csprng); + /// # } + pub fn random(rng: &mut R) -> Self { + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + Scalar::from_bytes_mod_order_wide(&scalar_bytes) + } + + /// Hash a slice of bytes into a scalar. + /// + /// Takes a type parameter `D`, which is any `Digest` producing 64 + /// bytes (512 bits) of output. + /// + /// Convenience wrapper around `from_hash`. + /// + /// # Example + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # use curve25519_dalek::scalar::Scalar; + /// extern crate sha2; + /// + /// use sha2::Sha512; + /// + /// # // Need fn main() here in comment so the doctest compiles + /// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests + /// # fn main() { + /// let msg = "To really appreciate architecture, you may even need to commit a murder"; + /// let s = Scalar::hash_from_bytes::(msg.as_bytes()); + /// # } + /// ``` + pub fn hash_from_bytes(input: &[u8]) -> Scalar + where D: Digest + Default + { + let mut hash = D::default(); + hash.input(input); + Scalar::from_hash(hash) + } + + /// Construct a scalar from an existing `Digest` instance. + /// + /// Use this instead of `hash_from_bytes` if it is more convenient + /// to stream data into the `Digest` than to pass a single byte + /// slice. + /// + /// # Example + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # use curve25519_dalek::scalar::Scalar; + /// extern crate sha2; + /// + /// use sha2::Digest; + /// use sha2::Sha512; + /// + /// # fn main() { + /// let mut h = Sha512::new() + /// .chain("To really appreciate architecture, you may even need to commit a murder.") + /// .chain("While the programs used for The Manhattan Transcripts are of the most extreme") + /// .chain("nature, they also parallel the most common formula plot: the archetype of") + /// .chain("murder. Other phantasms were occasionally used to underline the fact that") + /// .chain("perhaps all architecture, rather than being about functional standards, is") + /// .chain("about love and death."); + /// + /// let s = Scalar::from_hash(h); + /// + /// println!("{:?}", s.to_bytes()); + /// assert!(s == Scalar::from_bits([ 21, 88, 208, 252, 63, 122, 210, 152, + /// 154, 38, 15, 23, 16, 167, 80, 150, + /// 192, 221, 77, 226, 62, 25, 224, 148, + /// 239, 48, 176, 10, 185, 69, 168, 11, ])); + /// # } + /// ``` + pub fn from_hash(hash: D) -> Scalar + where D: Digest + { + let mut output = [0u8; 64]; + output.copy_from_slice(hash.result().as_slice()); + Scalar::from_bytes_mod_order_wide(&output) + } + + /// Convert this `Scalar` to its underlying sequence of bytes. + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::scalar::Scalar; + /// + /// let s: Scalar = Scalar::zero(); + /// + /// assert!(s.to_bytes() == [0u8; 32]); + /// ``` + pub fn to_bytes(&self) -> [u8; 32] { + self.bytes + } + + /// View the little-endian byte encoding of the integer representing this Scalar. + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::scalar::Scalar; + /// + /// let s: Scalar = Scalar::zero(); + /// + /// assert!(s.as_bytes() == &[0u8; 32]); + /// ``` + pub fn as_bytes(&self) -> &[u8; 32] { + &self.bytes + } + + /// Construct the scalar \\( 0 \\). + pub fn zero() -> Self { + Scalar { bytes: [0u8; 32]} + } + + /// Construct the scalar \\( 1 \\). + pub fn one() -> Self { + Scalar { + bytes: [ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + } + } + + /// Given a nonzero `Scalar`, compute its multiplicative inverse. + /// + /// # Warning + /// + /// `self` **MUST** be nonzero. If you cannot + /// *prove* that this is the case, you **SHOULD NOT USE THIS + /// FUNCTION**. + /// + /// # Returns + /// + /// The multiplicative inverse of the this `Scalar`. + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::scalar::Scalar; + /// + /// // x = 2238329342913194256032495932344128051776374960164957527413114840482143558222 + /// let X: Scalar = Scalar::from_bytes_mod_order([ + /// 0x4e, 0x5a, 0xb4, 0x34, 0x5d, 0x47, 0x08, 0x84, + /// 0x59, 0x13, 0xb4, 0x64, 0x1b, 0xc2, 0x7d, 0x52, + /// 0x52, 0xa5, 0x85, 0x10, 0x1b, 0xcc, 0x42, 0x44, + /// 0xd4, 0x49, 0xf4, 0xa8, 0x79, 0xd9, 0xf2, 0x04, + /// ]); + /// // 1/x = 6859937278830797291664592131120606308688036382723378951768035303146619657244 + /// let XINV: Scalar = Scalar::from_bytes_mod_order([ + /// 0x1c, 0xdc, 0x17, 0xfc, 0xe0, 0xe9, 0xa5, 0xbb, + /// 0xd9, 0x24, 0x7e, 0x56, 0xbb, 0x01, 0x63, 0x47, + /// 0xbb, 0xba, 0x31, 0xed, 0xd5, 0xa9, 0xbb, 0x96, + /// 0xd5, 0x0b, 0xcd, 0x7a, 0x3f, 0x96, 0x2a, 0x0f, + /// ]); + /// + /// let inv_X: Scalar = X.invert(); + /// assert!(XINV == inv_X); + /// let should_be_one: Scalar = &inv_X * &X; + /// assert!(should_be_one == Scalar::one()); + /// ``` + pub fn invert(&self) -> Scalar { + self.unpack().invert().pack() + } + + /// Given a slice of nonzero (possibly secret) `Scalar`s, + /// compute their inverses in a batch. + /// + /// # Return + /// + /// Each element of `inputs` is replaced by its inverse. + /// + /// The product of all inverses is returned. + /// + /// # Warning + /// + /// All input `Scalars` **MUST** be nonzero. If you cannot + /// *prove* that this is the case, you **SHOULD NOT USE THIS + /// FUNCTION**. + /// + /// # Example + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # use curve25519_dalek::scalar::Scalar; + /// # fn main() { + /// let mut scalars = [ + /// Scalar::from(3u64), + /// Scalar::from(5u64), + /// Scalar::from(7u64), + /// Scalar::from(11u64), + /// ]; + /// + /// let allinv = Scalar::batch_invert(&mut scalars); + /// + /// assert_eq!(allinv, Scalar::from(3*5*7*11u64).invert()); + /// assert_eq!(scalars[0], Scalar::from(3u64).invert()); + /// assert_eq!(scalars[1], Scalar::from(5u64).invert()); + /// assert_eq!(scalars[2], Scalar::from(7u64).invert()); + /// assert_eq!(scalars[3], Scalar::from(11u64).invert()); + /// # } + /// ``` + #[cfg(feature = "alloc")] + pub fn batch_invert(inputs: &mut [Scalar]) -> Scalar { + // This code is essentially identical to the FieldElement + // implementation, and is documented there. Unfortunately, + // it's not easy to write it generically, since here we want + // to use `UnpackedScalar`s internally, and `Scalar`s + // externally, but there's no corresponding distinction for + // field elements. + + use zeroize::Zeroizing; + + let n = inputs.len(); + let one: UnpackedScalar = Scalar::one().unpack().to_montgomery(); + + // Place scratch storage in a Zeroizing wrapper to wipe it when + // we pass out of scope. + let scratch_vec = vec![one; n]; + let mut scratch = Zeroizing::new(scratch_vec); + + // Keep an accumulator of all of the previous products + let mut acc = Scalar::one().unpack().to_montgomery(); + + // Pass through the input vector, recording the previous + // products in the scratch space + for (input, scratch) in inputs.iter_mut().zip(scratch.iter_mut()) { + *scratch = acc; + + // Avoid unnecessary Montgomery multiplication in second pass by + // keeping inputs in Montgomery form + let tmp = input.unpack().to_montgomery(); + *input = tmp.pack(); + acc = UnpackedScalar::montgomery_mul(&acc, &tmp); + } + + // acc is nonzero iff all inputs are nonzero + debug_assert!(acc.pack() != Scalar::zero()); + + // Compute the inverse of all products + acc = acc.montgomery_invert().from_montgomery(); + + // We need to return the product of all inverses later + let ret = acc.pack(); + + // Pass through the vector backwards to compute the inverses + // in place + for (input, scratch) in inputs.iter_mut().rev().zip(scratch.iter().rev()) { + let tmp = UnpackedScalar::montgomery_mul(&acc, &input.unpack()); + *input = UnpackedScalar::montgomery_mul(&acc, &scratch).pack(); + acc = tmp; + } + + ret + } + + /// Get the bits of the scalar. + pub(crate) fn bits(&self) -> [i8; 256] { + let mut bits = [0i8; 256]; + for i in 0..256 { + // As i runs from 0..256, the bottom 3 bits index the bit, + // while the upper bits index the byte. + bits[i] = ((self.bytes[i>>3] >> (i&7)) & 1u8) as i8; + } + bits + } + + /// Compute a width-\\(w\\) "Non-Adjacent Form" of this scalar. + /// + /// A width-\\(w\\) NAF of a positive integer \\(k\\) is an expression + /// $$ + /// k = \sum_{i=0}\^m n\_i 2\^i, + /// $$ + /// where each nonzero + /// coefficient \\(n\_i\\) is odd and bounded by \\(|n\_i| < 2\^{w-1}\\), + /// \\(n\_{m-1}\\) is nonzero, and at most one of any \\(w\\) consecutive + /// coefficients is nonzero. (Hankerson, Menezes, Vanstone; def 3.32). + /// + /// The length of the NAF is at most one more than the length of + /// the binary representation of \\(k\\). This is why the + /// `Scalar` type maintains an invariant that the top bit is + /// \\(0\\), so that the NAF of a scalar has at most 256 digits. + /// + /// Intuitively, this is like a binary expansion, except that we + /// allow some coefficients to grow in magnitude up to + /// \\(2\^{w-1}\\) so that the nonzero coefficients are as sparse + /// as possible. + /// + /// When doing scalar multiplication, we can then use a lookup + /// table of precomputed multiples of a point to add the nonzero + /// terms \\( k_i P \\). Using signed digits cuts the table size + /// in half, and using odd digits cuts the table size in half + /// again. + /// + /// To compute a \\(w\\)-NAF, we use a modification of Algorithm 3.35 of HMV: + /// + /// 1. \\( i \gets 0 \\) + /// 2. While \\( k \ge 1 \\): + /// 1. If \\(k\\) is odd, \\( n_i \gets k \operatorname{mods} 2^w \\), \\( k \gets k - n_i \\). + /// 2. If \\(k\\) is even, \\( n_i \gets 0 \\). + /// 3. \\( k \gets k / 2 \\), \\( i \gets i + 1 \\). + /// 3. Return \\( n_0, n_1, ... , \\) + /// + /// Here \\( \bar x = x \operatorname{mods} 2^w \\) means the + /// \\( \bar x \\) with \\( \bar x \equiv x \pmod{2^w} \\) and + /// \\( -2^{w-1} \leq \bar x < 2^w \\). + /// + /// We implement this by scanning across the bits of \\(k\\) from + /// least-significant bit to most-significant-bit. + /// Write the bits of \\(k\\) as + /// $$ + /// k = \sum\_{i=0}\^m k\_i 2^i, + /// $$ + /// and split the sum as + /// $$ + /// k = \sum\_{i=0}^{w-1} k\_i 2^i + 2^w \sum\_{i=0} k\_{i+w} 2^i + /// $$ + /// where the first part is \\( k \mod 2^w \\). + /// + /// If \\( k \mod 2^w\\) is odd, and \\( k \mod 2^w < 2^{w-1} \\), then we emit + /// \\( n_0 = k \mod 2^w \\). Instead of computing + /// \\( k - n_0 \\), we just advance \\(w\\) bits and reindex. + /// + /// If \\( k \mod 2^w\\) is odd, and \\( k \mod 2^w \ge 2^{w-1} \\), then + /// \\( n_0 = k \operatorname{mods} 2^w = k \mod 2^w - 2^w \\). + /// The quantity \\( k - n_0 \\) is + /// $$ + /// \begin{aligned} + /// k - n_0 &= \sum\_{i=0}^{w-1} k\_i 2^i + 2^w \sum\_{i=0} k\_{i+w} 2^i + /// - \sum\_{i=0}^{w-1} k\_i 2^i + 2^w \\\\ + /// &= 2^w + 2^w \sum\_{i=0} k\_{i+w} 2^i + /// \end{aligned} + /// $$ + /// so instead of computing the subtraction, we can set a carry + /// bit, advance \\(w\\) bits, and reindex. + /// + /// If \\( k \mod 2^w\\) is even, we emit \\(0\\), advance 1 bit + /// and reindex. In fact, by setting all digits to \\(0\\) + /// initially, we don't need to emit anything. + pub(crate) fn non_adjacent_form(&self, w: usize) -> [i8; 256] { + // required by the NAF definition + debug_assert!( w >= 2 ); + // required so that the NAF digits fit in i8 + debug_assert!( w <= 8 ); + + use byteorder::{ByteOrder, LittleEndian}; + + let mut naf = [0i8; 256]; + + let mut x_u64 = [0u64; 5]; + LittleEndian::read_u64_into(&self.bytes, &mut x_u64[0..4]); + + let width = 1 << w; + let window_mask = width - 1; + + let mut pos = 0; + let mut carry = 0; + while pos < 256 { + // Construct a buffer of bits of the scalar, starting at bit `pos` + let u64_idx = pos / 64; + let bit_idx = pos % 64; + let bit_buf: u64; + if bit_idx < 64 - w { + // This window's bits are contained in a single u64 + bit_buf = x_u64[u64_idx] >> bit_idx; + } else { + // Combine the current u64's bits with the bits from the next u64 + bit_buf = (x_u64[u64_idx] >> bit_idx) | (x_u64[1+u64_idx] << (64 - bit_idx)); + } + + // Add the carry into the current window + let window = carry + (bit_buf & window_mask); + + if window & 1 == 0 { + // If the window value is even, preserve the carry and continue. + // Why is the carry preserved? + // If carry == 0 and window & 1 == 0, then the next carry should be 0 + // If carry == 1 and window & 1 == 0, then bit_buf & 1 == 1 so the next carry should be 1 + pos += 1; + continue; + } + + if window < width/2 { + carry = 0; + naf[pos] = window as i8; + } else { + carry = 1; + naf[pos] = (window as i8).wrapping_sub(width as i8); + } + + pos += w; + } + + naf + } + + /// Write this scalar in radix 16, with coefficients in \\([-8,8)\\), + /// i.e., compute \\(a\_i\\) such that + /// $$ + /// a = a\_0 + a\_1 16\^1 + \cdots + a_{63} 16\^{63}, + /// $$ + /// with \\(-8 \leq a_i < 8\\) for \\(0 \leq i < 63\\) and \\(-8 \leq a_{63} \leq 8\\). + pub(crate) fn to_radix_16(&self) -> [i8; 64] { + debug_assert!(self[31] <= 127); + let mut output = [0i8; 64]; + + // Step 1: change radix. + // Convert from radix 256 (bytes) to radix 16 (nibbles) + #[inline(always)] + fn bot_half(x: u8) -> u8 { (x >> 0) & 15 } + #[inline(always)] + fn top_half(x: u8) -> u8 { (x >> 4) & 15 } + + for i in 0..32 { + output[2*i ] = bot_half(self[i]) as i8; + output[2*i+1] = top_half(self[i]) as i8; + } + // Precondition note: since self[31] <= 127, output[63] <= 7 + + // Step 2: recenter coefficients from [0,16) to [-8,8) + for i in 0..63 { + let carry = (output[i] + 8) >> 4; + output[i ] -= carry << 4; + output[i+1] += carry; + } + // Precondition note: output[63] is not recentered. It + // increases by carry <= 1. Thus output[63] <= 8. + + output + } + + /// Returns a size hint indicating how many entries of the return + /// value of `to_radix_2w` are nonzero. + pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize { + debug_assert!(w >= 6); + debug_assert!(w <= 8); + + let digits_count = match w { + 6 => (256 + w - 1)/w as usize, + 7 => (256 + w - 1)/w as usize, + // See comment in to_radix_2w on handling the terminal carry. + 8 => (256 + w - 1)/w + 1 as usize, + _ => panic!("invalid radix parameter"), + }; + + debug_assert!(digits_count <= 43); + digits_count + } + + /// Creates a representation of a Scalar in radix 64, 128 or 256 for use with the Pippenger algorithm. + /// For lower radix, use `to_radix_16`, which is used by the Straus multi-scalar multiplication. + /// Higher radixes are not supported to save cache space. Radix 256 is near-optimal even for very + /// large inputs. + /// + /// Radix below 64 or above 256 is prohibited. + /// This method returns digits in a fixed-sized array, excess digits are zeroes. + /// The second returned value is the number of digits. + /// + /// ## Scalar representation + /// + /// Radix \\(2\^w\\), with \\(n = ceil(256/w)\\) coefficients in \\([-(2\^w)/2,(2\^w)/2)\\), + /// i.e., scalar is represented using digits \\(a\_i\\) such that + /// $$ + /// a = a\_0 + a\_1 2\^1w + \cdots + a_{n-1} 2\^{w*(n-1)}, + /// $$ + /// with \\(-2\^w/2 \leq a_i < 2\^w/2\\) for \\(0 \leq i < (n-1)\\) and \\(-2\^w/2 \leq a_{n-1} \leq 2\^w/2\\). + /// + pub(crate) fn to_radix_2w(&self, w: usize) -> [i8; 43] { + debug_assert!(w >= 6); + debug_assert!(w <= 8); + + use byteorder::{ByteOrder, LittleEndian}; + + // Scalar formatted as four `u64`s with carry bit packed into the highest bit. + let mut scalar64x4 = [0u64; 4]; + LittleEndian::read_u64_into(&self.bytes, &mut scalar64x4[0..4]); + + let radix: u64 = 1 << w; + let window_mask: u64 = radix - 1; + + let mut carry = 0u64; + let mut digits = [0i8; 43]; + let digits_count = (256 + w - 1)/w as usize; + for i in 0..digits_count { + // Construct a buffer of bits of the scalar, starting at `bit_offset`. + let bit_offset = i*w; + let u64_idx = bit_offset / 64; + let bit_idx = bit_offset % 64; + + // Read the bits from the scalar + let bit_buf: u64; + if bit_idx < 64 - w || u64_idx == 3 { + // This window's bits are contained in a single u64, + // or it's the last u64 anyway. + bit_buf = scalar64x4[u64_idx] >> bit_idx; + } else { + // Combine the current u64's bits with the bits from the next u64 + bit_buf = (scalar64x4[u64_idx] >> bit_idx) | (scalar64x4[1+u64_idx] << (64 - bit_idx)); + } + + // Read the actual coefficient value from the window + let coef = carry + (bit_buf & window_mask); // coef = [0, 2^r) + + // Recenter coefficients from [0,2^w) to [-2^w/2, 2^w/2) + carry = (coef + (radix/2) as u64) >> w; + digits[i] = ((coef as i64) - (carry << w) as i64) as i8; + } + + // When w < 8, we can fold the final carry onto the last digit d, + // because d < 2^w/2 so d + carry*2^w = d + 1*2^w < 2^(w+1) < 2^8. + // + // When w = 8, we can't fit carry*2^w into an i8. This should + // not happen anyways, because the final carry will be 0 for + // reduced scalars, but the Scalar invariant allows 255-bit scalars. + // To handle this, we expand the size_hint by 1 when w=8, + // and accumulate the final carry onto another digit. + match w { + 8 => digits[digits_count] += carry as i8, + _ => digits[digits_count-1] += (carry << w) as i8, + } + + digits + } + + /// Unpack this `Scalar` to an `UnpackedScalar` for faster arithmetic. + pub(crate) fn unpack(&self) -> UnpackedScalar { + UnpackedScalar::from_bytes(&self.bytes) + } + + /// Reduce this `Scalar` modulo \\(\ell\\). + #[allow(non_snake_case)] + pub fn reduce(&self) -> Scalar { + let x = self.unpack(); + let xR = UnpackedScalar::mul_internal(&x, &constants::R); + let x_mod_l = UnpackedScalar::montgomery_reduce(&xR); + x_mod_l.pack() + } + + /// Check whether this `Scalar` is the canonical representative mod \\(\ell\\). + /// + /// This is intended for uses like input validation, where variable-time code is acceptable. + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # extern crate subtle; + /// # use curve25519_dalek::scalar::Scalar; + /// # use subtle::ConditionallySelectable; + /// # fn main() { + /// // 2^255 - 1, since `from_bits` clears the high bit + /// let _2_255_minus_1 = Scalar::from_bits([0xff;32]); + /// assert!(!_2_255_minus_1.is_canonical()); + /// + /// let reduced = _2_255_minus_1.reduce(); + /// assert!(reduced.is_canonical()); + /// # } + /// ``` + pub fn is_canonical(&self) -> bool { + *self == self.reduce() + } +} + +impl UnpackedScalar { + /// Pack the limbs of this `UnpackedScalar` into a `Scalar`. + fn pack(&self) -> Scalar { + Scalar{ bytes: self.to_bytes() } + } + + /// Inverts an UnpackedScalar in Montgomery form. + pub fn montgomery_invert(&self) -> UnpackedScalar { + // Uses the addition chain from + // https://briansmith.org/ecc-inversion-addition-chains-01#curve25519_scalar_inversion + let _1 = self; + let _10 = _1.montgomery_square(); + let _100 = _10.montgomery_square(); + let _11 = UnpackedScalar::montgomery_mul(&_10, &_1); + let _101 = UnpackedScalar::montgomery_mul(&_10, &_11); + let _111 = UnpackedScalar::montgomery_mul(&_10, &_101); + let _1001 = UnpackedScalar::montgomery_mul(&_10, &_111); + let _1011 = UnpackedScalar::montgomery_mul(&_10, &_1001); + let _1111 = UnpackedScalar::montgomery_mul(&_100, &_1011); + + // _10000 + let mut y = UnpackedScalar::montgomery_mul(&_1111, &_1); + + #[inline] + fn square_multiply(y: &mut UnpackedScalar, squarings: usize, x: &UnpackedScalar) { + for _ in 0..squarings { + *y = y.montgomery_square(); + } + *y = UnpackedScalar::montgomery_mul(y, x); + } + + square_multiply(&mut y, 123 + 3, &_101); + square_multiply(&mut y, 2 + 2, &_11); + square_multiply(&mut y, 1 + 4, &_1111); + square_multiply(&mut y, 1 + 4, &_1111); + square_multiply(&mut y, 4, &_1001); + square_multiply(&mut y, 2, &_11); + square_multiply(&mut y, 1 + 4, &_1111); + square_multiply(&mut y, 1 + 3, &_101); + square_multiply(&mut y, 3 + 3, &_101); + square_multiply(&mut y, 3, &_111); + square_multiply(&mut y, 1 + 4, &_1111); + square_multiply(&mut y, 2 + 3, &_111); + square_multiply(&mut y, 2 + 2, &_11); + square_multiply(&mut y, 1 + 4, &_1011); + square_multiply(&mut y, 2 + 4, &_1011); + square_multiply(&mut y, 6 + 4, &_1001); + square_multiply(&mut y, 2 + 2, &_11); + square_multiply(&mut y, 3 + 2, &_11); + square_multiply(&mut y, 3 + 2, &_11); + square_multiply(&mut y, 1 + 4, &_1001); + square_multiply(&mut y, 1 + 3, &_111); + square_multiply(&mut y, 2 + 4, &_1111); + square_multiply(&mut y, 1 + 4, &_1011); + square_multiply(&mut y, 3, &_101); + square_multiply(&mut y, 2 + 4, &_1111); + square_multiply(&mut y, 3, &_101); + square_multiply(&mut y, 1 + 2, &_11); + + y + } + + /// Inverts an UnpackedScalar not in Montgomery form. + pub fn invert(&self) -> UnpackedScalar { + self.to_montgomery().montgomery_invert().from_montgomery() + } +} + +#[cfg(test)] +mod test { + use super::*; + use constants; + + /// x = 2238329342913194256032495932344128051776374960164957527413114840482143558222 + pub static X: Scalar = Scalar{ + bytes: [ + 0x4e, 0x5a, 0xb4, 0x34, 0x5d, 0x47, 0x08, 0x84, + 0x59, 0x13, 0xb4, 0x64, 0x1b, 0xc2, 0x7d, 0x52, + 0x52, 0xa5, 0x85, 0x10, 0x1b, 0xcc, 0x42, 0x44, + 0xd4, 0x49, 0xf4, 0xa8, 0x79, 0xd9, 0xf2, 0x04, + ], + }; + /// 1/x = 6859937278830797291664592131120606308688036382723378951768035303146619657244 + pub static XINV: Scalar = Scalar{ + bytes: [ + 0x1c, 0xdc, 0x17, 0xfc, 0xe0, 0xe9, 0xa5, 0xbb, + 0xd9, 0x24, 0x7e, 0x56, 0xbb, 0x01, 0x63, 0x47, + 0xbb, 0xba, 0x31, 0xed, 0xd5, 0xa9, 0xbb, 0x96, + 0xd5, 0x0b, 0xcd, 0x7a, 0x3f, 0x96, 0x2a, 0x0f, + ], + }; + /// y = 2592331292931086675770238855846338635550719849568364935475441891787804997264 + pub static Y: Scalar = Scalar{ + bytes: [ + 0x90, 0x76, 0x33, 0xfe, 0x1c, 0x4b, 0x66, 0xa4, + 0xa2, 0x8d, 0x2d, 0xd7, 0x67, 0x83, 0x86, 0xc3, + 0x53, 0xd0, 0xde, 0x54, 0x55, 0xd4, 0xfc, 0x9d, + 0xe8, 0xef, 0x7a, 0xc3, 0x1f, 0x35, 0xbb, 0x05, + ], + }; + + /// x*y = 5690045403673944803228348699031245560686958845067437804563560795922180092780 + static X_TIMES_Y: Scalar = Scalar{ + bytes: [ + 0x6c, 0x33, 0x74, 0xa1, 0x89, 0x4f, 0x62, 0x21, + 0x0a, 0xaa, 0x2f, 0xe1, 0x86, 0xa6, 0xf9, 0x2c, + 0xe0, 0xaa, 0x75, 0xc2, 0x77, 0x95, 0x81, 0xc2, + 0x95, 0xfc, 0x08, 0x17, 0x9a, 0x73, 0x94, 0x0c, + ], + }; + + /// sage: l = 2^252 + 27742317777372353535851937790883648493 + /// sage: big = 2^256 - 1 + /// sage: repr((big % l).digits(256)) + static CANONICAL_2_256_MINUS_1: Scalar = Scalar{ + bytes: [ + 28, 149, 152, 141, 116, 49, 236, 214, + 112, 207, 125, 115, 244, 91, 239, 198, + 254, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 15, + ], + }; + + static A_SCALAR: Scalar = Scalar{ + bytes: [ + 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, + 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d, + 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, + 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09, + ], + }; + + static A_NAF: [i8; 256] = + [0,13,0,0,0,0,0,0,0,7,0,0,0,0,0,0,-9,0,0,0,0,-11,0,0,0,0,3,0,0,0,0,1, + 0,0,0,0,9,0,0,0,0,-5,0,0,0,0,0,0,3,0,0,0,0,11,0,0,0,0,11,0,0,0,0,0, + -9,0,0,0,0,0,-3,0,0,0,0,9,0,0,0,0,0,1,0,0,0,0,0,0,-1,0,0,0,0,0,9,0, + 0,0,0,-15,0,0,0,0,-7,0,0,0,0,-9,0,0,0,0,0,5,0,0,0,0,13,0,0,0,0,0,-3,0, + 0,0,0,-11,0,0,0,0,-7,0,0,0,0,-13,0,0,0,0,11,0,0,0,0,-9,0,0,0,0,0,1,0,0, + 0,0,0,-15,0,0,0,0,1,0,0,0,0,7,0,0,0,0,0,0,0,0,5,0,0,0,0,0,13,0,0,0, + 0,0,0,11,0,0,0,0,0,15,0,0,0,0,0,-9,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,7, + 0,0,0,0,0,-15,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,15,0,0,0,0,0,1,0,0,0,0]; + + static LARGEST_ED25519_S: Scalar = Scalar { + bytes: [ + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + ], + }; + + static CANONICAL_LARGEST_ED25519_S_PLUS_ONE: Scalar = Scalar { + bytes: [ + 0x7e, 0x34, 0x47, 0x75, 0x47, 0x4a, 0x7f, 0x97, + 0x23, 0xb6, 0x3a, 0x8b, 0xe9, 0x2a, 0xe7, 0x6d, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + ], + }; + + static CANONICAL_LARGEST_ED25519_S_MINUS_ONE: Scalar = Scalar { + bytes: [ + 0x7c, 0x34, 0x47, 0x75, 0x47, 0x4a, 0x7f, 0x97, + 0x23, 0xb6, 0x3a, 0x8b, 0xe9, 0x2a, 0xe7, 0x6d, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + ], + }; + + #[test] + fn fuzzer_testcase_reduction() { + // LE bytes of 24519928653854221733733552434404946937899825954937634815 + let a_bytes = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + // LE bytes of 4975441334397345751130612518500927154628011511324180036903450236863266160640 + let b_bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 210, 210, 210, 255, 255, 255, 255, 10]; + // LE bytes of 6432735165214683820902750800207468552549813371247423777071615116673864412038 + let c_bytes = [134, 171, 119, 216, 180, 128, 178, 62, 171, 132, 32, 62, 34, 119, 104, 193, 47, 215, 181, 250, 14, 207, 172, 93, 75, 207, 211, 103, 144, 204, 56, 14]; + + let a = Scalar::from_bytes_mod_order(a_bytes); + let b = Scalar::from_bytes_mod_order(b_bytes); + let c = Scalar::from_bytes_mod_order(c_bytes); + + let mut tmp = [0u8; 64]; + + // also_a = (a mod l) + tmp[0..32].copy_from_slice(&a_bytes[..]); + let also_a = Scalar::from_bytes_mod_order_wide(&tmp); + + // also_b = (b mod l) + tmp[0..32].copy_from_slice(&b_bytes[..]); + let also_b = Scalar::from_bytes_mod_order_wide(&tmp); + + let expected_c = &a * &b; + let also_expected_c = &also_a * &also_b; + + assert_eq!(c, expected_c); + assert_eq!(c, also_expected_c); + } + + #[test] + fn non_adjacent_form_test_vector() { + let naf = A_SCALAR.non_adjacent_form(5); + for i in 0..256 { + assert_eq!(naf[i], A_NAF[i]); + } + } + + fn non_adjacent_form_iter(w: usize, x: &Scalar) { + let naf = x.non_adjacent_form(w); + + // Reconstruct the scalar from the computed NAF + let mut y = Scalar::zero(); + for i in (0..256).rev() { + y += y; + let digit = if naf[i] < 0 { + -Scalar::from((-naf[i]) as u64) + } else { + Scalar::from(naf[i] as u64) + }; + y += digit; + } + + assert_eq!(*x, y); + } + + #[test] + fn non_adjacent_form_random() { + let mut rng = rand::thread_rng(); + for _ in 0..1_000 { + let x = Scalar::random(&mut rng); + for w in &[5, 6, 7, 8] { + non_adjacent_form_iter(*w, &x); + } + } + } + + #[test] + fn from_u64() { + let val: u64 = 0xdeadbeefdeadbeef; + let s = Scalar::from(val); + assert_eq!(s[7], 0xde); + assert_eq!(s[6], 0xad); + assert_eq!(s[5], 0xbe); + assert_eq!(s[4], 0xef); + assert_eq!(s[3], 0xde); + assert_eq!(s[2], 0xad); + assert_eq!(s[1], 0xbe); + assert_eq!(s[0], 0xef); + } + + #[test] + fn scalar_mul_by_one() { + let test_scalar = &X * &Scalar::one(); + for i in 0..32 { + assert!(test_scalar[i] == X[i]); + } + } + + #[test] + fn add_reduces() { + // Check that the addition works + assert_eq!( + (LARGEST_ED25519_S + Scalar::one()).reduce(), + CANONICAL_LARGEST_ED25519_S_PLUS_ONE + ); + // Check that the addition reduces + assert_eq!( + LARGEST_ED25519_S + Scalar::one(), + CANONICAL_LARGEST_ED25519_S_PLUS_ONE + ); + } + + #[test] + fn sub_reduces() { + // Check that the subtraction works + assert_eq!( + (LARGEST_ED25519_S - Scalar::one()).reduce(), + CANONICAL_LARGEST_ED25519_S_MINUS_ONE + ); + // Check that the subtraction reduces + assert_eq!( + LARGEST_ED25519_S - Scalar::one(), + CANONICAL_LARGEST_ED25519_S_MINUS_ONE + ); + } + + #[test] + fn quarkslab_scalar_overflow_does_not_occur() { + // Check that manually-constructing large Scalars with + // from_bits cannot produce incorrect results. + // + // The from_bits function is required to implement X/Ed25519, + // while all other methods of constructing a Scalar produce + // reduced Scalars. However, this "invariant loophole" allows + // constructing large scalars which are not reduced mod l. + // + // This issue was discovered independently by both Jack + // "str4d" Grigg (issue #238), who noted that reduction was + // not performed on addition, and Laurent Grémy & Nicolas + // Surbayrole of Quarkslab, who noted that it was possible to + // cause an overflow and compute incorrect results. + // + // This test is adapted from the one suggested by Quarkslab. + + let large_bytes = [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + ]; + + let a = Scalar::from_bytes_mod_order(large_bytes); + let b = Scalar::from_bits(large_bytes); + + assert_eq!(a, b.reduce()); + + let a_3 = a + a + a; + let b_3 = b + b + b; + + assert_eq!(a_3, b_3); + + let neg_a = -a; + let neg_b = -b; + + assert_eq!(neg_a, neg_b); + + let minus_a_3 = Scalar::zero() - a - a - a; + let minus_b_3 = Scalar::zero() - b - b - b; + + assert_eq!(minus_a_3, minus_b_3); + assert_eq!(minus_a_3, -a_3); + assert_eq!(minus_b_3, -b_3); + } + + #[test] + fn impl_add() { + let two = Scalar::from(2u64); + let one = Scalar::one(); + let should_be_two = &one + &one; + assert_eq!(should_be_two, two); + } + + #[allow(non_snake_case)] + #[test] + fn impl_mul() { + let should_be_X_times_Y = &X * &Y; + assert_eq!(should_be_X_times_Y, X_TIMES_Y); + } + + #[allow(non_snake_case)] + #[test] + fn impl_product() { + // Test that product works for non-empty iterators + let X_Y_vector = vec![X, Y]; + let should_be_X_times_Y: Scalar = X_Y_vector.iter().product(); + assert_eq!(should_be_X_times_Y, X_TIMES_Y); + + // Test that product works for the empty iterator + let one = Scalar::one(); + let empty_vector = vec![]; + let should_be_one: Scalar = empty_vector.iter().product(); + assert_eq!(should_be_one, one); + + // Test that product works for iterators where Item = Scalar + let xs = [Scalar::from(2u64); 10]; + let ys = [Scalar::from(3u64); 10]; + // now zs is an iterator with Item = Scalar + let zs = xs.iter().zip(ys.iter()).map(|(x,y)| x * y); + + let x_prod: Scalar = xs.iter().product(); + let y_prod: Scalar = ys.iter().product(); + let z_prod: Scalar = zs.product(); + + assert_eq!(x_prod, Scalar::from(1024u64)); + assert_eq!(y_prod, Scalar::from(59049u64)); + assert_eq!(z_prod, Scalar::from(60466176u64)); + assert_eq!(x_prod * y_prod, z_prod); + + } + + #[test] + fn impl_sum() { + + // Test that sum works for non-empty iterators + let two = Scalar::from(2u64); + let one_vector = vec![Scalar::one(), Scalar::one()]; + let should_be_two: Scalar = one_vector.iter().sum(); + assert_eq!(should_be_two, two); + + // Test that sum works for the empty iterator + let zero = Scalar::zero(); + let empty_vector = vec![]; + let should_be_zero: Scalar = empty_vector.iter().sum(); + assert_eq!(should_be_zero, zero); + + // Test that sum works for owned types + let xs = [Scalar::from(1u64); 10]; + let ys = [Scalar::from(2u64); 10]; + // now zs is an iterator with Item = Scalar + let zs = xs.iter().zip(ys.iter()).map(|(x,y)| x + y); + + let x_sum: Scalar = xs.iter().sum(); + let y_sum: Scalar = ys.iter().sum(); + let z_sum: Scalar = zs.sum(); + + assert_eq!(x_sum, Scalar::from(10u64)); + assert_eq!(y_sum, Scalar::from(20u64)); + assert_eq!(z_sum, Scalar::from(30u64)); + assert_eq!(x_sum + y_sum, z_sum); + } + + #[test] + fn square() { + let expected = &X * &X; + let actual = X.unpack().square().pack(); + for i in 0..32 { + assert!(expected[i] == actual[i]); + } + } + + #[test] + fn reduce() { + let biggest = Scalar::from_bytes_mod_order([0xff; 32]); + assert_eq!(biggest, CANONICAL_2_256_MINUS_1); + } + + #[test] + fn from_bytes_mod_order_wide() { + let mut bignum = [0u8; 64]; + // set bignum = x + 2^256x + for i in 0..32 { + bignum[ i] = X[i]; + bignum[32+i] = X[i]; + } + // 3958878930004874126169954872055634648693766179881526445624823978500314864344 + // = x + 2^256x (mod l) + let reduced = Scalar{ + bytes: [ + 216, 154, 179, 139, 210, 121, 2, 71, + 69, 99, 158, 216, 23, 173, 63, 100, + 204, 0, 91, 50, 219, 153, 57, 249, + 28, 82, 31, 197, 100, 165, 192, 8, + ], + }; + let test_red = Scalar::from_bytes_mod_order_wide(&bignum); + for i in 0..32 { + assert!(test_red[i] == reduced[i]); + } + } + + #[allow(non_snake_case)] + #[test] + fn invert() { + let inv_X = X.invert(); + assert_eq!(inv_X, XINV); + let should_be_one = &inv_X * &X; + assert_eq!(should_be_one, Scalar::one()); + } + + // Negating a scalar twice should result in the original scalar. + #[allow(non_snake_case)] + #[test] + fn neg_twice_is_identity() { + let negative_X = -&X; + let should_be_X = -&negative_X; + + assert_eq!(should_be_X, X); + } + + #[test] + fn to_bytes_from_bytes_roundtrips() { + let unpacked = X.unpack(); + let bytes = unpacked.to_bytes(); + let should_be_unpacked = UnpackedScalar::from_bytes(&bytes); + + assert_eq!(should_be_unpacked.0, unpacked.0); + } + + #[test] + fn montgomery_reduce_matches_from_bytes_mod_order_wide() { + let mut bignum = [0u8; 64]; + + // set bignum = x + 2^256x + for i in 0..32 { + bignum[ i] = X[i]; + bignum[32+i] = X[i]; + } + // x + 2^256x (mod l) + // = 3958878930004874126169954872055634648693766179881526445624823978500314864344 + let expected = Scalar{ + bytes: [ + 216, 154, 179, 139, 210, 121, 2, 71, + 69, 99, 158, 216, 23, 173, 63, 100, + 204, 0, 91, 50, 219, 153, 57, 249, + 28, 82, 31, 197, 100, 165, 192, 8 + ], + }; + let reduced = Scalar::from_bytes_mod_order_wide(&bignum); + + // The reduced scalar should match the expected + assert_eq!(reduced.bytes, expected.bytes); + + // (x + 2^256x) * R + let interim = UnpackedScalar::mul_internal(&UnpackedScalar::from_bytes_wide(&bignum), + &constants::R); + // ((x + 2^256x) * R) / R (mod l) + let montgomery_reduced = UnpackedScalar::montgomery_reduce(&interim); + + // The Montgomery reduced scalar should match the reduced one, as well as the expected + assert_eq!(montgomery_reduced.0, reduced.unpack().0); + assert_eq!(montgomery_reduced.0, expected.unpack().0) + } + + #[test] + fn canonical_decoding() { + // canonical encoding of 1667457891 + let canonical_bytes = [99, 99, 99, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,]; + + // encoding of + // 7265385991361016183439748078976496179028704920197054998554201349516117938192 + // = 28380414028753969466561515933501938171588560817147392552250411230663687203 (mod l) + // non_canonical because unreduced mod l + let non_canonical_bytes_because_unreduced = [16; 32]; + + // encoding with high bit set, to check that the parser isn't pre-masking the high bit + let non_canonical_bytes_because_highbit = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128]; + + assert!( Scalar::from_canonical_bytes(canonical_bytes).is_some() ); + assert!( Scalar::from_canonical_bytes(non_canonical_bytes_because_unreduced).is_none() ); + assert!( Scalar::from_canonical_bytes(non_canonical_bytes_because_highbit).is_none() ); + } + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_scalar_roundtrip() { + use bincode; + let encoded = bincode::serialize(&X).unwrap(); + let parsed: Scalar = bincode::deserialize(&encoded).unwrap(); + assert_eq!(parsed, X); + + // Check that the encoding is 32 bytes exactly + assert_eq!(encoded.len(), 32); + + // Check that the encoding itself matches the usual one + assert_eq!( + X, + bincode::deserialize(X.as_bytes()).unwrap(), + ); + } + + #[cfg(debug_assertions)] + #[test] + #[should_panic] + fn batch_invert_with_a_zero_input_panics() { + let mut xs = vec![Scalar::one(); 16]; + xs[3] = Scalar::zero(); + // This should panic in debug mode. + Scalar::batch_invert(&mut xs); + } + + #[test] + fn batch_invert_empty() { + assert_eq!(Scalar::one(), Scalar::batch_invert(&mut [])); + } + + #[test] + fn batch_invert_consistency() { + let mut x = Scalar::from(1u64); + let mut v1: Vec<_> = (0..16).map(|_| {let tmp = x; x = x + x; tmp}).collect(); + let v2 = v1.clone(); + + let expected: Scalar = v1.iter().product(); + let expected = expected.invert(); + let ret = Scalar::batch_invert(&mut v1); + assert_eq!(ret, expected); + + for (a, b) in v1.iter().zip(v2.iter()) { + assert_eq!(a * b, Scalar::one()); + } + } + + fn test_pippenger_radix_iter(scalar: Scalar, w: usize) { + let digits_count = Scalar::to_radix_2w_size_hint(w); + let digits = scalar.to_radix_2w(w); + + let radix = Scalar::from((1< +// - Henry de Valence + +//! Module for common traits. + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use subtle; + +use scalar::Scalar; + +// ------------------------------------------------------------------------ +// Public Traits +// ------------------------------------------------------------------------ + +/// Trait for getting the identity element of a point type. +pub trait Identity { + /// Returns the identity element of the curve. + /// Can be used as a constructor. + fn identity() -> Self; +} + +/// Trait for testing if a curve point is equivalent to the identity point. +pub trait IsIdentity { + /// Return true if this element is the identity element of the curve. + fn is_identity(&self) -> bool; +} + +/// Implement generic identity equality testing for a point representations +/// which have constant-time equality testing and a defined identity +/// constructor. +impl IsIdentity for T +where + T: subtle::ConstantTimeEq + Identity, +{ + fn is_identity(&self) -> bool { + self.ct_eq(&T::identity()).unwrap_u8() == 1u8 + } +} + +/// A trait for constant-time multiscalar multiplication without precomputation. +pub trait MultiscalarMul { + /// The type of point being multiplied, e.g., `RistrettoPoint`. + type Point; + + /// Given an iterator of (possibly secret) scalars and an iterator of + /// public points, compute + /// $$ + /// Q = c\_1 P\_1 + \cdots + c\_n P\_n. + /// $$ + /// + /// It is an error to call this function with two iterators of different lengths. + /// + /// # Examples + /// + /// The trait bound aims for maximum flexibility: the inputs must be + /// convertable to iterators (`I: IntoIter`), and the iterator's items + /// must be `Borrow` (or `Borrow`), to allow + /// iterators returning either `Scalar`s or `&Scalar`s. + /// + /// ``` + /// use curve25519_dalek::constants; + /// use curve25519_dalek::traits::MultiscalarMul; + /// use curve25519_dalek::ristretto::RistrettoPoint; + /// use curve25519_dalek::scalar::Scalar; + /// + /// // Some scalars + /// let a = Scalar::from(87329482u64); + /// let b = Scalar::from(37264829u64); + /// let c = Scalar::from(98098098u64); + /// + /// // Some points + /// let P = constants::RISTRETTO_BASEPOINT_POINT; + /// let Q = P + P; + /// let R = P + Q; + /// + /// // A1 = a*P + b*Q + c*R + /// let abc = [a,b,c]; + /// let A1 = RistrettoPoint::multiscalar_mul(&abc, &[P,Q,R]); + /// // Note: (&abc).into_iter(): Iterator + /// + /// // A2 = (-a)*P + (-b)*Q + (-c)*R + /// let minus_abc = abc.iter().map(|x| -x); + /// let A2 = RistrettoPoint::multiscalar_mul(minus_abc, &[P,Q,R]); + /// // Note: minus_abc.into_iter(): Iterator + /// + /// assert_eq!(A1.compress(), (-A2).compress()); + /// ``` + fn multiscalar_mul(scalars: I, points: J) -> Self::Point + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow; +} + +/// A trait for variable-time multiscalar multiplication without precomputation. +pub trait VartimeMultiscalarMul { + /// The type of point being multiplied, e.g., `RistrettoPoint`. + type Point; + + /// Given an iterator of public scalars and an iterator of + /// `Option`s of points, compute either `Some(Q)`, where + /// $$ + /// Q = c\_1 P\_1 + \cdots + c\_n P\_n, + /// $$ + /// if all points were `Some(P_i)`, or else return `None`. + /// + /// This function is particularly useful when verifying statements + /// involving compressed points. Accepting `Option` allows + /// inlining point decompression into the multiscalar call, + /// avoiding the need for temporary buffers. + /// ``` + /// use curve25519_dalek::constants; + /// use curve25519_dalek::traits::VartimeMultiscalarMul; + /// use curve25519_dalek::ristretto::RistrettoPoint; + /// use curve25519_dalek::scalar::Scalar; + /// + /// // Some scalars + /// let a = Scalar::from(87329482u64); + /// let b = Scalar::from(37264829u64); + /// let c = Scalar::from(98098098u64); + /// let abc = [a,b,c]; + /// + /// // Some points + /// let P = constants::RISTRETTO_BASEPOINT_POINT; + /// let Q = P + P; + /// let R = P + Q; + /// let PQR = [P, Q, R]; + /// + /// let compressed = [P.compress(), Q.compress(), R.compress()]; + /// + /// // Now we can compute A1 = a*P + b*Q + c*R using P, Q, R: + /// let A1 = RistrettoPoint::vartime_multiscalar_mul(&abc, &PQR); + /// + /// // Or using the compressed points: + /// let A2 = RistrettoPoint::optional_multiscalar_mul( + /// &abc, + /// compressed.iter().map(|pt| pt.decompress()), + /// ); + /// + /// assert_eq!(A2, Some(A1)); + /// + /// // It's also possible to mix compressed and uncompressed points: + /// let A3 = RistrettoPoint::optional_multiscalar_mul( + /// abc.iter() + /// .chain(abc.iter()), + /// compressed.iter().map(|pt| pt.decompress()) + /// .chain(PQR.iter().map(|&pt| Some(pt))), + /// ); + /// + /// assert_eq!(A3, Some(A1+A1)); + /// ``` + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>; + + /// Given an iterator of public scalars and an iterator of + /// public points, compute + /// $$ + /// Q = c\_1 P\_1 + \cdots + c\_n P\_n, + /// $$ + /// using variable-time operations. + /// + /// It is an error to call this function with two iterators of different lengths. + /// + /// # Examples + /// + /// The trait bound aims for maximum flexibility: the inputs must be + /// convertable to iterators (`I: IntoIter`), and the iterator's items + /// must be `Borrow` (or `Borrow`), to allow + /// iterators returning either `Scalar`s or `&Scalar`s. + /// + /// ``` + /// use curve25519_dalek::constants; + /// use curve25519_dalek::traits::VartimeMultiscalarMul; + /// use curve25519_dalek::ristretto::RistrettoPoint; + /// use curve25519_dalek::scalar::Scalar; + /// + /// // Some scalars + /// let a = Scalar::from(87329482u64); + /// let b = Scalar::from(37264829u64); + /// let c = Scalar::from(98098098u64); + /// + /// // Some points + /// let P = constants::RISTRETTO_BASEPOINT_POINT; + /// let Q = P + P; + /// let R = P + Q; + /// + /// // A1 = a*P + b*Q + c*R + /// let abc = [a,b,c]; + /// let A1 = RistrettoPoint::vartime_multiscalar_mul(&abc, &[P,Q,R]); + /// // Note: (&abc).into_iter(): Iterator + /// + /// // A2 = (-a)*P + (-b)*Q + (-c)*R + /// let minus_abc = abc.iter().map(|x| -x); + /// let A2 = RistrettoPoint::vartime_multiscalar_mul(minus_abc, &[P,Q,R]); + /// // Note: minus_abc.into_iter(): Iterator + /// + /// assert_eq!(A1.compress(), (-A2).compress()); + /// ``` + fn vartime_multiscalar_mul(scalars: I, points: J) -> Self::Point + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + Self::Point: Clone, + { + Self::optional_multiscalar_mul( + scalars, + points.into_iter().map(|P| Some(P.borrow().clone())), + ) + .unwrap() + } +} + +/// A trait for variable-time multiscalar multiplication with precomputation. +/// +/// A general multiscalar multiplication with precomputation can be written as +/// $$ +/// Q = a_1 A_1 + \cdots + a_n A_n + b_1 B_1 + \cdots + b_m B_m, +/// $$ +/// where the \\(B_i\\) are *static* points, for which precomputation +/// is possible, and the \\(A_j\\) are *dynamic* points, for which +/// precomputation is not possible. +/// +/// This trait has three methods for performing this computation: +/// +/// * [`vartime_multiscalar_mul`], which handles the special case +/// where \\(n = 0\\) and there are no dynamic points; +/// +/// * [`vartime_mixed_multiscalar_mul`], which takes the dynamic +/// points as already-validated `Point`s and is infallible; +/// +/// * [`optional_mixed_multiscalar_mul`], which takes the dynamic +/// points as `Option`s and returns an `Option`, +/// allowing decompression to be composed into the input iterators. +/// +/// All methods require that the lengths of the input iterators be +/// known and matching, as if they were `ExactSizeIterator`s. (It +/// does not require `ExactSizeIterator` only because that trait is +/// broken). +pub trait VartimePrecomputedMultiscalarMul: Sized { + /// The type of point to be multiplied, e.g., `RistrettoPoint`. + type Point: Clone; + + /// Given the static points \\( B_i \\), perform precomputation + /// and return the precomputation data. + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow; + + /// Given `static_scalars`, an iterator of public scalars + /// \\(b_i\\), compute + /// $$ + /// Q = b_1 B_1 + \cdots + b_m B_m, + /// $$ + /// where the \\(B_j\\) are the points that were supplied to `new`. + /// + /// It is an error to call this function with iterators of + /// inconsistent lengths. + /// + /// The trait bound aims for maximum flexibility: the input must + /// be convertable to iterators (`I: IntoIter`), and the + /// iterator's items must be `Borrow`, to allow iterators + /// returning either `Scalar`s or `&Scalar`s. + fn vartime_multiscalar_mul(&self, static_scalars: I) -> Self::Point + where + I: IntoIterator, + I::Item: Borrow, + { + use core::iter; + + Self::vartime_mixed_multiscalar_mul( + self, + static_scalars, + iter::empty::(), + iter::empty::(), + ) + } + + /// Given `static_scalars`, an iterator of public scalars + /// \\(b_i\\), `dynamic_scalars`, an iterator of public scalars + /// \\(a_i\\), and `dynamic_points`, an iterator of points + /// \\(A_i\\), compute + /// $$ + /// Q = a_1 A_1 + \cdots + a_n A_n + b_1 B_1 + \cdots + b_m B_m, + /// $$ + /// where the \\(B_j\\) are the points that were supplied to `new`. + /// + /// It is an error to call this function with iterators of + /// inconsistent lengths. + /// + /// The trait bound aims for maximum flexibility: the inputs must be + /// convertable to iterators (`I: IntoIter`), and the iterator's items + /// must be `Borrow` (or `Borrow`), to allow + /// iterators returning either `Scalar`s or `&Scalar`s. + fn vartime_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Self::Point + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator, + K::Item: Borrow, + { + Self::optional_mixed_multiscalar_mul( + self, + static_scalars, + dynamic_scalars, + dynamic_points.into_iter().map(|P| Some(P.borrow().clone())), + ) + .unwrap() + } + + /// Given `static_scalars`, an iterator of public scalars + /// \\(b_i\\), `dynamic_scalars`, an iterator of public scalars + /// \\(a_i\\), and `dynamic_points`, an iterator of points + /// \\(A_i\\), compute + /// $$ + /// Q = a_1 A_1 + \cdots + a_n A_n + b_1 B_1 + \cdots + b_m B_m, + /// $$ + /// where the \\(B_j\\) are the points that were supplied to `new`. + /// + /// If any of the dynamic points were `None`, return `None`. + /// + /// It is an error to call this function with iterators of + /// inconsistent lengths. + /// + /// This function is particularly useful when verifying statements + /// involving compressed points. Accepting `Option` allows + /// inlining point decompression into the multiscalar call, + /// avoiding the need for temporary buffers. + fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator>; +} + +// ------------------------------------------------------------------------ +// Private Traits +// ------------------------------------------------------------------------ + +/// Trait for checking whether a point is on the curve. +/// +/// This trait is only for debugging/testing, since it should be +/// impossible for a `curve25519-dalek` user to construct an invalid +/// point. +pub(crate) trait ValidityCheck { + /// Checks whether the point is on the curve. Not CT. + fn is_valid(&self) -> bool; +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/window.rs b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/window.rs new file mode 100644 index 0000000..3b01422 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/src/window.rs @@ -0,0 +1,206 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2019 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Code for fixed- and sliding-window functionality + +#![allow(non_snake_case)] + +use core::fmt::Debug; + +use subtle::ConditionallyNegatable; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; +use subtle::Choice; + +use traits::Identity; + +use edwards::EdwardsPoint; +use backend::serial::curve_models::ProjectiveNielsPoint; +use backend::serial::curve_models::AffineNielsPoint; + +use zeroize::Zeroize; + +/// A lookup table of precomputed multiples of a point \\(P\\), used to +/// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\). +/// +/// The computation of \\( xP \\) is done in constant time by the `select` function. +/// +/// Since `LookupTable` does not implement `Index`, it's more difficult +/// to accidentally use the table directly. Unfortunately the table is +/// only `pub(crate)` so that we can write hardcoded constants, so it's +/// still technically possible. It would be nice to prevent direct +/// access to the table. +/// +/// XXX make this generic with respect to table size +#[derive(Copy, Clone)] +pub struct LookupTable(pub(crate) [T; 8]); + +impl LookupTable +where + T: Identity + ConditionallySelectable + ConditionallyNegatable, +{ + /// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time. + pub fn select(&self, x: i8) -> T { + debug_assert!(x >= -8); + debug_assert!(x <= 8); + + // Compute xabs = |x| + let xmask = x >> 7; + let xabs = (x + xmask) ^ xmask; + + // Set t = 0 * P = identity + let mut t = T::identity(); + for j in 1..9 { + // Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`. + let c = (xabs as u8).ct_eq(&(j as u8)); + t.conditional_assign(&self.0[j - 1], c); + } + // Now t == |x| * P. + + let neg_mask = Choice::from((xmask & 1) as u8); + t.conditional_negate(neg_mask); + // Now t == x * P. + + t + } +} + +impl Default for LookupTable { + fn default() -> LookupTable { + LookupTable([T::default(); 8]) + } +} + +impl Debug for LookupTable { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "LookupTable({:?})", self.0) + } +} + +impl<'a> From<&'a EdwardsPoint> for LookupTable { + fn from(P: &'a EdwardsPoint) -> Self { + let mut points = [P.to_projective_niels(); 8]; + for j in 0..7 { + points[j + 1] = (P + &points[j]).to_extended().to_projective_niels(); + } + LookupTable(points) + } +} + +impl<'a> From<&'a EdwardsPoint> for LookupTable { + fn from(P: &'a EdwardsPoint) -> Self { + let mut points = [P.to_affine_niels(); 8]; + // XXX batch inversion would be good if perf mattered here + for j in 0..7 { + points[j + 1] = (P + &points[j]).to_extended().to_affine_niels() + } + LookupTable(points) + } +} + +impl Zeroize for LookupTable +where + T: Copy + Default + Zeroize +{ + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +/// Holds odd multiples 1A, 3A, ..., 15A of a point A. +#[derive(Copy, Clone)] +pub(crate) struct NafLookupTable5(pub(crate) [T; 8]); + +impl NafLookupTable5 { + /// Given public, odd \\( x \\) with \\( 0 < x < 2^4 \\), return \\(xA\\). + pub fn select(&self, x: usize) -> T { + debug_assert_eq!(x & 1, 1); + debug_assert!(x < 16); + + self.0[x / 2] + } +} + +impl Debug for NafLookupTable5 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "NafLookupTable5({:?})", self.0) + } +} + +impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.to_projective_niels(); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + NafLookupTable5(Ai) + } +} + +impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.to_affine_niels(); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_affine_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + NafLookupTable5(Ai) + } +} + +/// Holds stuff up to 8. +#[derive(Copy, Clone)] +pub(crate) struct NafLookupTable8(pub(crate) [T; 64]); + +impl NafLookupTable8 { + pub fn select(&self, x: usize) -> T { + debug_assert_eq!(x & 1, 1); + debug_assert!(x < 128); + + self.0[x / 2] + } +} + +impl Debug for NafLookupTable8 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "NafLookupTable8([\n")?; + for i in 0..64 { + write!(f, "\t{:?},\n", &self.0[i])?; + } + write!(f, "])") + } +} + +impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.to_projective_niels(); 64]; + let A2 = A.double(); + for i in 0..63 { + Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] + NafLookupTable8(Ai) + } +} + +impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.to_affine_niels(); 64]; + let A2 = A.double(); + for i in 0..63 { + Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_affine_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] + NafLookupTable8(Ai) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/vendor/ristretto.sage b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/vendor/ristretto.sage new file mode 100644 index 0000000..04cf4f9 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek-2.0.0/vendor/ristretto.sage @@ -0,0 +1,857 @@ +import binascii +class InvalidEncodingException(Exception): pass +class NotOnCurveException(Exception): pass +class SpecException(Exception): pass + +def lobit(x): return int(x) & 1 +def hibit(x): return lobit(2*x) +def negative(x): return lobit(x) +def enc_le(x,n): return bytearray([int(x)>>(8*i) & 0xFF for i in xrange(n)]) +def dec_le(x): return sum(b<<(8*i) for i,b in enumerate(x)) +def randombytes(n): return bytearray([randint(0,255) for _ in range(n)]) + +def optimized_version_of(spec): + """Decorator: This function is an optimized version of some specification""" + def decorator(f): + def wrapper(self,*args,**kwargs): + def pr(x): + if isinstance(x,bytearray): return binascii.hexlify(x) + else: return str(x) + try: spec_ans = getattr(self,spec,spec)(*args,**kwargs),None + except Exception as e: spec_ans = None,e + try: opt_ans = f(self,*args,**kwargs),None + except Exception as e: opt_ans = None,e + if spec_ans[1] is None and opt_ans[1] is not None: + raise + #raise SpecException("Mismatch in %s: spec returned %s but opt threw %s" + # % (f.__name__,str(spec_ans[0]),str(opt_ans[1]))) + if spec_ans[1] is not None and opt_ans[1] is None: + raise + #raise SpecException("Mismatch in %s: spec threw %s but opt returned %s" + # % (f.__name__,str(spec_ans[1]),str(opt_ans[0]))) + if spec_ans[0] != opt_ans[0]: + raise SpecException("Mismatch in %s: %s != %s" + % (f.__name__,pr(spec_ans[0]),pr(opt_ans[0]))) + if opt_ans[1] is not None: raise + else: return opt_ans[0] + wrapper.__name__ = f.__name__ + return wrapper + return decorator + +def xsqrt(x,exn=InvalidEncodingException("Not on curve")): + """Return sqrt(x)""" + if not is_square(x): raise exn + s = sqrt(x) + if negative(s): s=-s + return s + +def isqrt(x,exn=InvalidEncodingException("Not on curve")): + """Return 1/sqrt(x)""" + if x==0: return 0 + if not is_square(x): raise exn + s = sqrt(x) + #if negative(s): s=-s + return 1/s + +def inv0(x): return 1/x if x != 0 else 0 + +def isqrt_i(x): + """Return 1/sqrt(x) or 1/sqrt(zeta * x)""" + if x==0: return True,0 + gen = x.parent(-1) + while is_square(gen): gen = sqrt(gen) + if is_square(x): return True,1/sqrt(x) + else: return False,1/sqrt(x*gen) + +class QuotientEdwardsPoint(object): + """Abstract class for point an a quotiented Edwards curve; needs F,a,d,cofactor to work""" + def __init__(self,x=0,y=1): + x = self.x = self.F(x) + y = self.y = self.F(y) + if y^2 + self.a*x^2 != 1 + self.d*x^2*y^2: + raise NotOnCurveException(str(self)) + + def __repr__(self): + return "%s(0x%x,0x%x)" % (self.__class__.__name__, self.x, self.y) + + def __iter__(self): + yield self.x + yield self.y + + def __add__(self,other): + x,y = self + X,Y = other + a,d = self.a,self.d + return self.__class__( + (x*Y+y*X)/(1+d*x*y*X*Y), + (y*Y-a*x*X)/(1-d*x*y*X*Y) + ) + + def __neg__(self): return self.__class__(-self.x,self.y) + def __sub__(self,other): return self + (-other) + def __rmul__(self,other): return self*other + def __eq__(self,other): + """NB: this is the only method that is different from the usual one""" + x,y = self + X,Y = other + return x*Y == X*y or (self.cofactor==8 and -self.a*x*X == y*Y) + def __ne__(self,other): return not (self==other) + + def __mul__(self,exp): + exp = int(exp) + if exp < 0: exp,self = -exp,-self + total = self.__class__() + work = self + while exp != 0: + if exp & 1: total += work + work += work + exp >>= 1 + return total + + def xyzt(self): + x,y = self + z = self.F.random_element() + return x*z,y*z,z,x*y*z + + def torque(self): + """Apply cofactor group, except keeping the point even""" + if self.cofactor == 8: + if self.a == -1: return self.__class__(self.y*self.i, self.x*self.i) + if self.a == 1: return self.__class__(-self.y, self.x) + else: + return self.__class__(-self.x, -self.y) + + def doubleAndEncodeSpec(self): + return (self+self).encode() + + # Utility functions + @classmethod + def bytesToGf(cls,bytes,mustBeProper=True,mustBePositive=False,maskHiBits=False): + """Convert little-endian bytes to field element, sanity check length""" + if len(bytes) != cls.encLen: + raise InvalidEncodingException("wrong length %d" % len(bytes)) + s = dec_le(bytes) + if mustBeProper and s >= cls.F.order(): + raise InvalidEncodingException("%d out of range!" % s) + bitlen = int(ceil(log(cls.F.order())/log(2))) + if maskHiBits: s &= 2^bitlen-1 + s = cls.F(s) + if mustBePositive and negative(s): + raise InvalidEncodingException("%d is negative!" % s) + return s + + @classmethod + def gfToBytes(cls,x,mustBePositive=False): + """Convert little-endian bytes to field element, sanity check length""" + if negative(x) and mustBePositive: x = -x + return enc_le(x,cls.encLen) + +class RistrettoPoint(QuotientEdwardsPoint): + """The new Ristretto group""" + def encodeSpec(self): + """Unoptimized specification for encoding""" + x,y = self + if self.cofactor==8 and (negative(x*y) or y==0): (x,y) = self.torque() + if y == -1: y = 1 # Avoid divide by 0; doesn't affect impl + + if negative(x): x,y = -x,-y + s = xsqrt(self.mneg*(1-y)/(1+y),exn=Exception("Unimplemented: point is odd: " + str(self))) + return self.gfToBytes(s) + + @classmethod + def decodeSpec(cls,s): + """Unoptimized specification for decoding""" + s = cls.bytesToGf(s,mustBePositive=True) + + a,d = cls.a,cls.d + x = xsqrt(4*s^2 / (a*d*(1+a*s^2)^2 - (1-a*s^2)^2)) + y = (1+a*s^2) / (1-a*s^2) + + if cls.cofactor==8 and (negative(x*y) or y==0): + raise InvalidEncodingException("x*y has high bit") + + return cls(x,y) + + @optimized_version_of("encodeSpec") + def encode(self): + """Encode, optimized version""" + a,d,mneg = self.a,self.d,self.mneg + x,y,z,t = self.xyzt() + + if self.cofactor==8: + u1 = mneg*(z+y)*(z-y) + u2 = x*y # = t*z + isr = isqrt(u1*u2^2) + i1 = isr*u1 # sqrt(mneg*(z+y)*(z-y))/(x*y) + i2 = isr*u2 # 1/sqrt(a*(y+z)*(y-z)) + z_inv = i1*i2*t # 1/z + + if negative(t*z_inv): + if a==-1: + x,y = y*self.i,x*self.i + den_inv = self.magic * i1 + else: + x,y = -y,x + den_inv = self.i * self.magic * i1 + + else: + den_inv = i2 + + if negative(x*z_inv): y = -y + s = (z-y) * den_inv + else: + num = mneg*(z+y)*(z-y) + isr = isqrt(num*y^2) + if negative(isr^2*num*y*t): y = -y + s = isr*y*(z-y) + + return self.gfToBytes(s,mustBePositive=True) + + @optimized_version_of("doubleAndEncodeSpec") + def doubleAndEncode(self): + X,Y,Z,T = self.xyzt() + a,d,mneg = self.a,self.d,self.mneg + + if self.cofactor==8: + e = 2*X*Y + f = Z^2+d*T^2 + g = Y^2-a*X^2 + h = Z^2-d*T^2 + + inv1 = 1/(e*f*g*h) + z_inv = inv1*e*g # 1 / (f*h) + t_inv = inv1*f*h + + if negative(e*g*z_inv): + if a==-1: sqrta = self.i + else: sqrta = -1 + e,f,g,h = g,h,-e,f*sqrta + factor = self.i + else: + factor = self.magic + + if negative(h*e*z_inv): g=-g + s = (h-g)*factor*g*t_inv + + else: + foo = Y^2+a*X^2 + bar = X*Y + den = 1/(foo*bar) + if negative(2*bar^2*den): tmp = a*X^2 + else: tmp = Y^2 + s = self.magic*(Z^2-tmp)*foo*den + + return self.gfToBytes(s,mustBePositive=True) + + @classmethod + @optimized_version_of("decodeSpec") + def decode(cls,s): + """Decode, optimized version""" + s = cls.bytesToGf(s,mustBePositive=True) + + a,d = cls.a,cls.d + yden = 1-a*s^2 + ynum = 1+a*s^2 + yden_sqr = yden^2 + xden_sqr = a*d*ynum^2 - yden_sqr + + isr = isqrt(xden_sqr * yden_sqr) + + xden_inv = isr * yden + yden_inv = xden_inv * isr * xden_sqr + + x = 2*s*xden_inv + if negative(x): x = -x + y = ynum * yden_inv + + if cls.cofactor==8 and (negative(x*y) or y==0): + raise InvalidEncodingException("x*y is invalid: %d, %d" % (x,y)) + + return cls(x,y) + + @classmethod + def fromJacobiQuartic(cls,s,t,sgn=1): + """Convert point from its Jacobi Quartic representation""" + a,d = cls.a,cls.d + assert s^4 - 2*cls.a*(1-2*d/(d-a))*s^2 + 1 == t^2 + x = 2*s*cls.magic / t + y = (1+a*s^2) / (1-a*s^2) + return cls(sgn*x,y) + + @classmethod + def elligatorSpec(cls,r0): + a,d = cls.a,cls.d + r = cls.qnr * cls.bytesToGf(r0,mustBeProper=False,maskHiBits=True)^2 + den = (d*r-a)*(a*r-d) + if den == 0: return cls() + n1 = cls.a*(r+1)*(a+d)*(d-a)/den + n2 = r*n1 + if is_square(n1): + sgn,s,t = 1, xsqrt(n1), -(r-1)*(a+d)^2 / den - 1 + else: + sgn,s,t = -1,-xsqrt(n2), r*(r-1)*(a+d)^2 / den - 1 + + return cls.fromJacobiQuartic(s,t) + + @classmethod + @optimized_version_of("elligatorSpec") + def elligator(cls,r0): + a,d = cls.a,cls.d + r0 = cls.bytesToGf(r0,mustBeProper=False,maskHiBits=True) + r = cls.qnr * r0^2 + den = (d*r-a)*(a*r-d) + num = cls.a*(r+1)*(a+d)*(d-a) + + iss,isri = isqrt_i(num*den) + if iss: sgn,twiddle = 1,1 + else: sgn,twiddle = -1,r0*cls.qnr + isri *= twiddle + s = isri*num + t = -sgn*isri*s*(r-1)*(d+a)^2 - 1 + if negative(s) == iss: s = -s + return cls.fromJacobiQuartic(s,t) + + +class Decaf_1_1_Point(QuotientEdwardsPoint): + """Like current decaf but tweaked for simplicity""" + def encodeSpec(self): + """Unoptimized specification for encoding""" + a,d = self.a,self.d + x,y = self + if x==0 or y==0: return(self.gfToBytes(0)) + + if self.cofactor==8 and negative(x*y*self.isoMagic): + x,y = self.torque() + + sr = xsqrt(1-a*x^2) + altx = x*y*self.isoMagic / sr + if negative(altx): s = (1+sr)/x + else: s = (1-sr)/x + + return self.gfToBytes(s,mustBePositive=True) + + @classmethod + def decodeSpec(cls,s): + """Unoptimized specification for decoding""" + a,d = cls.a,cls.d + s = cls.bytesToGf(s,mustBePositive=True) + + if s==0: return cls() + t = xsqrt(s^4 + 2*(a-2*d)*s^2 + 1) + altx = 2*s*cls.isoMagic/t + if negative(altx): t = -t + x = 2*s / (1+a*s^2) + y = (1-a*s^2) / t + + if cls.cofactor==8 and (negative(x*y*cls.isoMagic) or y==0): + raise InvalidEncodingException("x*y is invalid: %d, %d" % (x,y)) + + return cls(x,y) + + def toJacobiQuartic(self,toggle_rotation=False,toggle_altx=False,toggle_s=False): + "Return s,t on jacobi curve" + a,d = self.a,self.d + x,y,z,t = self.xyzt() + + if self.cofactor == 8: + # Cofactor 8 version + # Simulate IMAGINE_TWIST because that's how libdecaf does it + x = self.i*x + t = self.i*t + a = -a + d = -d + + # OK, the actual libdecaf code should be here + num = (z+y)*(z-y) + den = x*y + isr = isqrt(num*(a-d)*den^2) + + iden = isr * den * self.isoMagic # 1/sqrt((z+y)(z-y)) = 1/sqrt(1-Y^2) / z + inum = isr * num # sqrt(1-Y^2) * z / xysqrt(a-d) ~ 1/sqrt(1-ax^2)/z + + if negative(iden*inum*self.i*t^2*(d-a)) != toggle_rotation: + iden,inum = inum,iden + fac = x*sqrt(a) + toggle=(a==-1) + else: + fac = y + toggle=False + + imi = self.isoMagic * self.i + altx = inum*t*imi + neg_altx = negative(altx) != toggle_altx + if neg_altx != toggle: inum =- inum + + tmp = fac*(inum*z + 1) + s = iden*tmp*imi + + negm1 = (negative(s) != toggle_s) != neg_altx + if negm1: m1 = a*fac + z + else: m1 = a*fac - z + + swap = toggle_s + + else: + # Much simpler cofactor 4 version + num = (x+t)*(x-t) + isr = isqrt(num*(a-d)*x^2) + ratio = isr*num + altx = ratio*self.isoMagic + + neg_altx = negative(altx) != toggle_altx + if neg_altx: ratio =- ratio + + tmp = ratio*z - t + s = (a-d)*isr*x*tmp + + negx = (negative(s) != toggle_s) != neg_altx + if negx: m1 = -a*t + x + else: m1 = -a*t - x + + swap = toggle_s + + if negative(s): s = -s + + return s,m1,a*tmp,swap + + def invertElligator(self,toggle_r=False,*args,**kwargs): + "Produce preimage of self under elligator, or None" + a,d = self.a,self.d + + rets = [] + + tr = [False,True] if self.cofactor == 8 else [False] + for toggle_rotation in tr: + for toggle_altx in [False,True]: + for toggle_s in [False,True]: + for toggle_r in [False,True]: + s,m1,m12,swap = self.toJacobiQuartic(toggle_rotation,toggle_altx,toggle_s) + + #print + #print toggle_rotation,toggle_altx,toggle_s + #print m1 + #print m12 + + + if self == self.__class__(): + if self.cofactor == 4: + # Hacks for identity! + if toggle_altx: m12 = 1 + elif toggle_s: m1 = 1 + elif toggle_r: continue + ## BOTH??? + + else: + m12 = 1 + imi = self.isoMagic * self.i + if toggle_rotation: + if toggle_altx: m1 = -imi + else: m1 = +imi + else: + if toggle_altx: m1 = 0 + else: m1 = a-d + + rnum = (d*a*m12-m1) + rden = ((d*a-1)*m12+m1) + if swap: rnum,rden = rden,rnum + + ok,sr = isqrt_i(rnum*rden*self.qnr) + if not ok: continue + sr *= rnum + #print "Works! %d %x" % (swap,sr) + + if negative(sr) != toggle_r: sr = -sr + ret = self.gfToBytes(sr) + if self.elligator(ret) != self and self.elligator(ret) != -self: + print "WRONG!",[toggle_rotation,toggle_altx,toggle_s] + if self.elligator(ret) == -self and self != -self: print "Negated!",[toggle_rotation,toggle_altx,toggle_s] + rets.append(bytes(ret)) + return rets + + @optimized_version_of("encodeSpec") + def encode(self): + """Encode, optimized version""" + return self.gfToBytes(self.toJacobiQuartic()[0]) + + @classmethod + @optimized_version_of("decodeSpec") + def decode(cls,s): + """Decode, optimized version""" + a,d = cls.a,cls.d + s = cls.bytesToGf(s,mustBePositive=True) + + #if s==0: return cls() + s2 = s^2 + den = 1+a*s2 + num = den^2 - 4*d*s2 + isr = isqrt(num*den^2) + altx = 2*s*isr*den*cls.isoMagic + if negative(altx): isr = -isr + x = 2*s *isr^2*den*num + y = (1-a*s^2) * isr*den + + if cls.cofactor==8 and (negative(x*y*cls.isoMagic) or y==0): + raise InvalidEncodingException("x*y is invalid: %d, %d" % (x,y)) + + return cls(x,y) + + @classmethod + def fromJacobiQuartic(cls,s,t,sgn=1): + """Convert point from its Jacobi Quartic representation""" + a,d = cls.a,cls.d + if s==0: return cls() + x = 2*s / (1+a*s^2) + y = (1-a*s^2) / t + return cls(x,sgn*y) + + @optimized_version_of("doubleAndEncodeSpec") + def doubleAndEncode(self): + X,Y,Z,T = self.xyzt() + a,d = self.a,self.d + + if self.cofactor == 8: + # Cofactor 8 version + # Simulate IMAGINE_TWIST because that's how libdecaf does it + X = self.i*X + T = self.i*T + a = -a + d = -d + # TODO: This is only being called for a=-1, so could + # be wrong for a=1 + + e = 2*X*Y + f = Y^2+a*X^2 + g = Y^2-a*X^2 + h = Z^2-d*T^2 + + eim = e*self.isoMagic + inv = 1/(eim*g*f*h) + fh_inv = eim*g*inv*self.i + + if negative(eim*g*fh_inv): + idf = g*self.isoMagic*self.i + bar = f + foo = g + test = eim*f + else: + idf = eim + bar = h + foo = -eim + test = g*h + + if negative(test*fh_inv): bar =- bar + s = idf*(foo+bar)*inv*f*h + + else: + xy = X*Y + h = Z^2-d*T^2 + inv = 1/(xy*h) + if negative(inv*2*xy^2*self.isoMagic): tmp = Y + else: tmp = X + s = tmp^2*h*inv # = X/Y or Y/X, interestingly + + return self.gfToBytes(s,mustBePositive=True) + + @classmethod + def elligatorSpec(cls,r0,fromR=False): + a,d = cls.a,cls.d + if fromR: r = r0 + else: r = cls.qnr * cls.bytesToGf(r0,mustBeProper=False,maskHiBits=True)^2 + + den = (d*r-(d-a))*((d-a)*r-d) + if den == 0: return cls() + n1 = (r+1)*(a-2*d)/den + n2 = r*n1 + if is_square(n1): + sgn,s,t = 1, xsqrt(n1), -(r-1)*(a-2*d)^2 / den - 1 + else: + sgn,s,t = -1, -xsqrt(n2), r*(r-1)*(a-2*d)^2 / den - 1 + + return cls.fromJacobiQuartic(s,t) + + @classmethod + @optimized_version_of("elligatorSpec") + def elligator(cls,r0): + a,d = cls.a,cls.d + r0 = cls.bytesToGf(r0,mustBeProper=False,maskHiBits=True) + r = cls.qnr * r0^2 + den = (d*r-(d-a))*((d-a)*r-d) + num = (r+1)*(a-2*d) + + iss,isri = isqrt_i(num*den) + if iss: sgn,twiddle = 1,1 + else: sgn,twiddle = -1,r0*cls.qnr + isri *= twiddle + s = isri*num + t = -sgn*isri*s*(r-1)*(a-2*d)^2 - 1 + if negative(s) == iss: s = -s + return cls.fromJacobiQuartic(s,t) + + def elligatorInverseBruteForce(self): + """Invert Elligator using SAGE's polynomial solver""" + a,d = self.a,self.d + R. = self.F[] + r = self.qnr * r0^2 + den = (d*r-(d-a))*((d-a)*r-d) + n1 = (r+1)*(a-2*d)/den + n2 = r*n1 + ret = set() + for s2,t in [(n1, -(r-1)*(a-2*d)^2 / den - 1), + (n2,r*(r-1)*(a-2*d)^2 / den - 1)]: + x2 = 4*s2/(1+a*s2)^2 + y = (1-a*s2) / t + + selfT = self + for i in xrange(self.cofactor/2): + xT,yT = selfT + polyX = xT^2-x2 + polyY = yT-y + sx = set(r for r,_ in polyX.numerator().roots()) + sy = set(r for r,_ in polyY.numerator().roots()) + ret = ret.union(sx.intersection(sy)) + + selfT = selfT.torque() + + ret = [self.gfToBytes(r) for r in ret] + + for r in ret: + assert self.elligator(r) in [self,-self] + + ret = [r for r in ret if self.elligator(r) == self] + + return ret + +class Ed25519Point(RistrettoPoint): + F = GF(2^255-19) + d = F(-121665/121666) + a = F(-1) + i = sqrt(F(-1)) + mneg = F(1) + qnr = i + magic = isqrt(a*d-1) + cofactor = 8 + encLen = 32 + + @classmethod + def base(cls): + return cls( 15112221349535400772501151409588531511454012693041857206046113283949847762202, 46316835694926478169428394003475163141307993866256225615783033603165251855960 + ) + +class NegEd25519Point(RistrettoPoint): + F = GF(2^255-19) + d = F(121665/121666) + a = F(1) + i = sqrt(F(-1)) + mneg = F(-1) # TODO checkme vs 1-ad or whatever + qnr = i + magic = isqrt(a*d-1) + cofactor = 8 + encLen = 32 + + @classmethod + def base(cls): + y = cls.F(4/5) + x = sqrt((y^2-1)/(cls.d*y^2-cls.a)) + if negative(x): x = -x + return cls(x,y) + +class IsoEd448Point(RistrettoPoint): + F = GF(2^448-2^224-1) + d = F(39082/39081) + a = F(1) + mneg = F(-1) + qnr = -1 + magic = isqrt(a*d-1) + cofactor = 4 + encLen = 56 + + @classmethod + def base(cls): + return cls( # RFC has it wrong + 345397493039729516374008604150537410266655260075183290216406970281645695073672344430481787759340633221708391583424041788924124567700732, + -363419362147803445274661903944002267176820680343659030140745099590306164083365386343198191849338272965044442230921818680526749009182718 + ) + +class TwistedEd448GoldilocksPoint(Decaf_1_1_Point): + F = GF(2^448-2^224-1) + d = F(-39082) + a = F(-1) + qnr = -1 + cofactor = 4 + encLen = 56 + isoMagic = IsoEd448Point.magic + + @classmethod + def base(cls): + return cls.decodeSpec(Ed448GoldilocksPoint.base().encodeSpec()) + +class Ed448GoldilocksPoint(Decaf_1_1_Point): + F = GF(2^448-2^224-1) + d = F(-39081) + a = F(1) + qnr = -1 + cofactor = 4 + encLen = 56 + isoMagic = IsoEd448Point.magic + + @classmethod + def base(cls): + return 2*cls( + 224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710, 298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660 + ) + +class IsoEd25519Point(Decaf_1_1_Point): + # TODO: twisted iso too! + # TODO: twisted iso might have to IMAGINE_TWIST or whatever + F = GF(2^255-19) + d = F(-121665) + a = F(1) + i = sqrt(F(-1)) + qnr = i + magic = isqrt(a*d-1) + cofactor = 8 + encLen = 32 + isoMagic = Ed25519Point.magic + isoA = Ed25519Point.a + + @classmethod + def base(cls): + return cls.decodeSpec(Ed25519Point.base().encode()) + +class TestFailedException(Exception): pass + +def test(cls,n): + print "Testing curve %s" % cls.__name__ + + specials = [1] + ii = cls.F(-1) + while is_square(ii): + specials.append(ii) + ii = sqrt(ii) + specials.append(ii) + for i in specials: + if negative(cls.F(i)): i = -i + i = enc_le(i,cls.encLen) + try: + Q = cls.decode(i) + QE = Q.encode() + if QE != i: + raise TestFailedException("Round trip special %s != %s" % + (binascii.hexlify(QE),binascii.hexlify(i))) + except NotOnCurveException: pass + except InvalidEncodingException: pass + + + P = cls.base() + Q = cls() + for i in xrange(n): + #print binascii.hexlify(Q.encode()) + QE = Q.encode() + QQ = cls.decode(QE) + if QQ != Q: raise TestFailedException("Round trip %s != %s" % (str(QQ),str(Q))) + + # Testing s -> 1/s: encodes -point on cofactor + s = cls.bytesToGf(QE) + if s != 0: + ss = cls.gfToBytes(1/s,mustBePositive=True) + try: + QN = cls.decode(ss) + if cls.cofactor == 8: + raise TestFailedException("1/s shouldnt work for cofactor 8") + if QN != -Q: + raise TestFailedException("s -> 1/s should negate point for cofactor 4") + except InvalidEncodingException as e: + # Should be raised iff cofactor==8 + if cls.cofactor == 4: + raise TestFailedException("s -> 1/s should work for cofactor 4") + + QT = Q + for h in xrange(cls.cofactor): + QT = QT.torque() + if QT.encode() != QE: + raise TestFailedException("Can't torque %s,%d" % (str(Q),h+1)) + + Q0 = Q + P + if Q0 == Q: raise TestFailedException("Addition doesn't work") + if Q0-P != Q: raise TestFailedException("Subtraction doesn't work") + + r = randint(1,1000) + Q1 = Q0*r + Q2 = Q0*(r+1) + if Q1 + Q0 != Q2: raise TestFailedException("Scalarmul doesn't work") + Q = Q1 + +def testElligator(cls,n): + print "Testing elligator on %s" % cls.__name__ + for i in xrange(n): + r = randombytes(cls.encLen) + P = cls.elligator(r) + if hasattr(P,"invertElligator"): + iv = P.invertElligator() + modr = bytes(cls.gfToBytes(cls.bytesToGf(r,mustBeProper=False,maskHiBits=True))) + iv2 = P.torque().invertElligator() + if modr not in iv: print "Failed to invert Elligator!" + if len(iv) != len(set(iv)): + print "Elligator inverses not unique!", len(set(iv)), len(iv) + if iv != iv2: + print "Elligator is untorqueable!" + #print [binascii.hexlify(j) for j in iv] + #print [binascii.hexlify(j) for j in iv2] + #break + else: + pass # TODO + +def gangtest(classes,n): + print "Gang test",[cls.__name__ for cls in classes] + specials = [1] + ii = classes[0].F(-1) + while is_square(ii): + specials.append(ii) + ii = sqrt(ii) + specials.append(ii) + + for i in xrange(n): + rets = [bytes((cls.base()*i).encode()) for cls in classes] + if len(set(rets)) != 1: + print "Divergence in encode at %d" % i + for c,ret in zip(classes,rets): + print c,binascii.hexlify(ret) + print + + if i < len(specials): r0 = enc_le(specials[i],classes[0].encLen) + else: r0 = randombytes(classes[0].encLen) + + rets = [bytes((cls.elligator(r0)*i).encode()) for cls in classes] + if len(set(rets)) != 1: + print "Divergence in elligator at %d" % i + for c,ret in zip(classes,rets): + print c,binascii.hexlify(ret) + print + +def testDoubleAndEncode(cls,n): + print "Testing doubleAndEncode on %s" % cls.__name__ + for i in xrange(n): + r1 = randombytes(cls.encLen) + r2 = randombytes(cls.encLen) + u = cls.elligator(r1) + cls.elligator(r2) + u.doubleAndEncode() + +testDoubleAndEncode(Ed25519Point,100) +testDoubleAndEncode(NegEd25519Point,100) +testDoubleAndEncode(IsoEd25519Point,100) +testDoubleAndEncode(IsoEd448Point,100) +testDoubleAndEncode(TwistedEd448GoldilocksPoint,100) +#test(Ed25519Point,100) +#test(NegEd25519Point,100) +#test(IsoEd25519Point,100) +#test(IsoEd448Point,100) +#test(TwistedEd448GoldilocksPoint,100) +#test(Ed448GoldilocksPoint,100) +#testElligator(Ed25519Point,100) +#testElligator(NegEd25519Point,100) +#testElligator(IsoEd25519Point,100) +#testElligator(IsoEd448Point,100) +#testElligator(Ed448GoldilocksPoint,100) +#testElligator(TwistedEd448GoldilocksPoint,100) +#gangtest([IsoEd448Point,TwistedEd448GoldilocksPoint,Ed448GoldilocksPoint],100) +#gangtest([Ed25519Point,IsoEd25519Point],100) diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/.cargo-checksum.json b/net/gurk-rs/files/vendor/curve25519-dalek/.cargo-checksum.json new file mode 100644 index 0000000..26ddeea --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"7b436de74cc950b84ec3a82b0d77cb144c38ba701029597718d03e156934beff","CODE_OF_CONDUCT.md":"3282ab0de79898b07eff6595f46024f8ddc0e21eef8d61b4912f95998468eb53","CONTRIBUTING.md":"8ef9d405ab43c54787636b9d29b560f61c94773f726694ec37998dc66e43a788","Cargo.toml":"36b91df15a3296bf979467730894b8dac7616d35a34802fd939046a81513988f","LICENSE":"cca0bd3c4fcdba74145ef9d49c62337e2c9fbf9368288f11d0547f1b0273219f","Makefile":"3bdd6d7b89b2a1d0e69feab4b8f11514aef2b14c180726750e5de413b728d544","README.md":"10b65bbebef753a0ad01c8fbc1fc4a7ed309d5b4724cb4ddcbdb0c2f66bc150d","benches/dalek_benchmarks.rs":"f7f91d84391b4b1739e825b5398a85af89d6868c7278e277fb7356e717e0e42f","docs/assets/dalek-logo-clear.png":"6babf6c1cdb10af05142501af2c4947765ef7839f87b91bc683165a8369fc3f4","docs/assets/dalek-logo.png":"a4a0451c5a2c0417584dc7d7d1388283b3bf9aeef89ee64ee073cdcd83c1a0f1","docs/assets/dalek-logo.svg":"22534b6935cfb8ccd6512ee13006700c451b28feb13acc137668caf00901633f","docs/assets/rustdoc-include-katex-header.html":"348752aa412e1dc774427f20d8d51ca0b2923979d4829cbd493d76e499f2674e","docs/avx2-notes.md":"47e41778044529299f78906d99d6dfe9c0400acf5ad32e519fa54b6d6bea36dc","docs/ifma-notes.md":"7ca18607cafca402b832c313de42763df9cf1f8c9ca0ac58621322b5e33e8461","docs/parallel-formulas.md":"c3f63ab62c11b36a917e4d0eeb6392705502910b4ebc8b50d46a9122c6351332","src/backend/mod.rs":"d7529363ef1233548d2497c94eb25508fa776d8a4405a821a20526992a99f6c6","src/backend/serial/curve_models/mod.rs":"089669be41b1972040e16170135c8b758cd88923eccd186581e83cb19482451e","src/backend/serial/fiat_u32/field.rs":"282494af2f9d16a01521aaee1d57c396270b6dbd1b8a1be298248623e2eb2e06","src/backend/serial/fiat_u32/mod.rs":"6e36a757f0f804caaebb5a2f0c04754589740279160890d592287edc7d65efcf","src/backend/serial/fiat_u64/field.rs":"e215d97a0e90ea810fae0ec32be2e20c01f998ae0a8bb4d94dbdb1b1c88b610c","src/backend/serial/fiat_u64/mod.rs":"6e6f773aa9669a740519d2256421734ddfee60cd6ad7f45156b6b5201c10487d","src/backend/serial/mod.rs":"881bc35006031abd792de9cd6c0320e7a3b053d37598271d3be569ba7e71bb12","src/backend/serial/scalar_mul/mod.rs":"396429a4f10e8d1d7851c341781fdafc814f39afc2bef0078ef1dee9dced8a8b","src/backend/serial/scalar_mul/pippenger.rs":"bfab409306c0f88bbbe0bffedf3f66ccc011e9c1f6caa46aef1ce9727c48d3b6","src/backend/serial/scalar_mul/precomputed_straus.rs":"b735367646cd08a31d127882b623d22e77fda4197557d2e5f1bbf34e8da587db","src/backend/serial/scalar_mul/straus.rs":"93b95561304b3f464e2a0866424dfd3770515533d2687ef85ca5519503db02a6","src/backend/serial/scalar_mul/variable_base.rs":"1f04ca6d725ede8135a31ab7335c6d84c6b76ebce2b0ffa52fdf5c52c1fb2ac5","src/backend/serial/scalar_mul/vartime_double_base.rs":"d9a7033c13deb7390d8d34f694336cf648bddab3607d4b4db7e1f2d3d7a678e6","src/backend/serial/u32/constants.rs":"d539cc033568d49c654b73ec24f92a8894a1847182608f8a5ebaaee7363411b9","src/backend/serial/u32/field.rs":"cc42a8f0e573b3fdc73deaf0152361e39f14f6e143064c6c9a470c73312f0cce","src/backend/serial/u32/mod.rs":"14fabb2034c68094df508c19517db14e5e3b956b5dac93bd0dd3c125f47f396e","src/backend/serial/u32/scalar.rs":"a797284c92f36626e70c877cf32da6b79b44c0ca634a3bc8754803f0cae7f600","src/backend/serial/u64/constants.rs":"a6fd2ec0abb985aea30fa320c843e8f5c208d05073f2bde420f100c65e883d07","src/backend/serial/u64/field.rs":"666ea448453b9f72c8b3197fed8c0a0771488425673c48e012d9709a054a922d","src/backend/serial/u64/mod.rs":"b4aab9c62cf39bafc976b2e03bea503f120b125c30eb0e9e5d5f257b08a3eda4","src/backend/serial/u64/scalar.rs":"6a5a76eaf5b560e71310e9d67c8ca9ba2704b4f771760ce83270d85f0cb62a19","src/backend/vector/avx2/constants.rs":"2294ac59a6cc974fc879324cbb1edc7c90b758354669ce3c77ec38f31664b141","src/backend/vector/avx2/edwards.rs":"0f9aae021fa8ef300fa3ec8faf13b0cfc666738a5744a49a4c6f2bb4964a6861","src/backend/vector/avx2/field.rs":"abc7dd5248c8136b7edb94a901bdb24cdc84d243599734b4733ef61b8f4c9f5b","src/backend/vector/avx2/mod.rs":"0fd755b94bcec333bd4ef2bedad13a591d9d785bed47bd809930c74b4c580c06","src/backend/vector/ifma/constants.rs":"b1acd2c8674a5e710d753dfb159f0ea507585f2903f49f6f97802e53f5584bcf","src/backend/vector/ifma/edwards.rs":"c3b55fa23b117a83dee32201131f64bc4a050d3e96de29be345ef41b0291ea39","src/backend/vector/ifma/field.rs":"a291bb40ce2a91ed6e996d99a322ca7198614f81d0f47cdc2c93132139276d62","src/backend/vector/ifma/mod.rs":"385c894444884ec90052143502b8e37d7f36416e1dfd7e31ec588914d1a26527","src/backend/vector/mod.rs":"22324c0c34d9f7276d0f4e0d87e1e6aa3db0a3da1c3b92ffda13cce39ca698ce","src/backend/vector/scalar_mul/mod.rs":"3b339edd3512ea91fc8542dc2b13e72b2c146ef6d3e29a595b62a269c96037be","src/backend/vector/scalar_mul/pippenger.rs":"e87703ea516006fadc567fa5b75b6c5fee6ec5a9ad27368726fae0747e471368","src/backend/vector/scalar_mul/precomputed_straus.rs":"982acacbf478c5ee0f7e0bc5650b22960655550ac08b888e3477fc786ce0c959","src/backend/vector/scalar_mul/straus.rs":"43318d83671748335a518e7e0753457a8be2b1f988b1d7974a09212d1b10c807","src/backend/vector/scalar_mul/variable_base.rs":"c638bb2975b421d2bb6f29589c2e9b46831592b835851fed43569a8a5204c36e","src/backend/vector/scalar_mul/vartime_double_base.rs":"50200972a56ecf2ac6027d8eaa1dc07777c7a935a89756b3f1ffca020cd6313a","src/constants.rs":"e5ddee4e4c905320af32bf1f246fe4092d51f9758b11103569d7778d19d393e0","src/edwards.rs":"415bd2d04c1c2092e95204539396b6f4e7db540568dcc5059743db4a0cabe042","src/field.rs":"7baf29e0dc1a83668831c0fb266593a58e0e327e74b9f67884b396d7679ae501","src/lib.rs":"c022c9fae48b9b97176527298d277b1b14948901304bb8e529e0f63675031dc8","src/macros.rs":"893faee478e19905b54eefafc8d8db38e90084ef185bdfb96e51c10f7038ba6e","src/montgomery.rs":"b2d81976c9f89c2bc3e2b882c46b26297c3926727f841599bc6a9badb3268168","src/prelude.rs":"029695a58dec3a1c97fe0ca7611e81a81c6fb0b5b570f224bcda25f142288a0f","src/ristretto.rs":"d59e62dcef3faf78fc953ec6dd0068f64c6495c873d16d3bbc9bef6b141470e3","src/scalar.rs":"897f9ca64fae7c5739e7e612dee47d17789b2d29acb8c2416384862fe2683b4b","src/traits.rs":"973b467960df61d70a16b646a67c2e7de641ebe5c691bea5ee43e28d1ed65fe4","src/window.rs":"fd593bbee8bb598e96fa198cd7821a132d8baff9efc5e6c33e5f82c111420fe4","vendor/ristretto.sage":"a2f4309ada0afa4156f5a660be4384a0f1f332c12f836199124f48e89310344d"},"package":"639891fde0dbea823fc3d798a0fdf9d2f9440a42d64a78ab3488b0ca025117b3"} \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/CHANGELOG.md b/net/gurk-rs/files/vendor/curve25519-dalek/CHANGELOG.md new file mode 100644 index 0000000..1d42492 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/CHANGELOG.md @@ -0,0 +1,169 @@ +# Changelog + +Entries are listed in reverse chronological order per undeprecated +major series. + +## 3.x series + +### 3.1.0 + +* Add support for the Elligator2 encoding for Edwards points. +* Add two optional formally-verified field arithmetic backends which + use the Fiat Crypto project's Rust code, which is generated from + proofs of functional correctness checked by the Coq theorem proving + system. +* Add support for additional sizes of precomputed tables for basepoint + scalar multiplication. +* Fix an unused import. +* Add support for using the `zeroize` traits with all point types. + Note that points are not automatically zeroized on Drop, but that + consumers of `curve25519-dalek` should call these methods manually + when needed. + +### 3.0.2 + +* Fixes to make using alloc+no_std possible for stable Rust. + +### 3.0.1 + +* Update the optional `packed-simd` dependency to rely on a newer, + maintained version of the `packed-simd-2` crate. + +### 3.0.0 + +* Update the `digest` dependency to `0.9`. This requires a major version + because the `digest` traits are part of the public API, but there are + otherwise no changes to the API. + +## 2.x series + +### 2.1.2 + +* Fixes to make using alloc+no_std possible for stable Rust. + +### 2.1.1 + +* Update the optional `packed-simd` dependency to rely on a newer, + maintained version of the `packed-simd-2` crate. + +### 2.1.0 + +* Make `Scalar::from_bits` a `const fn`, allowing its use in `const` contexts. + +### 2.0.0 + +* Fix a data modeling error in the `serde` feature pointed out by Trevor Perrin + which caused points and scalars to be serialized with length fields rather + than as fixed-size 32-byte arrays. This is a breaking change, but it fixes + compatibility with `serde-json` and ensures that the `serde-bincode` encoding + matches the conventional encoding for X/Ed25519. +* Update `rand_core` to `0.5`, allowing use with new `rand` versions. +* Switch from `clear_on_drop` to `zeroize` (by Tony Arcieri). +* Require `subtle = ^2.2.1` and remove the note advising nightly Rust, which is + no longer required as of that version of `subtle`. See the `subtle` + changelog for more details. +* Update `README.md` for `2.x` series. +* Remove the `build.rs` hack which loaded the entire crate into its own + `build.rs` to generate constants, and keep the constants in the source code. + +The only significant change is the data model change to the `serde` feature; +besides the `rand_core` version bump, there are no other user-visible changes. + +## 1.x series + +### 1.2.6 + +* Fixes to make using alloc+no_std possible for stable Rust. + +### 1.2.5 + +* Update the optional `packed-simd` dependency to rely on a newer, + maintained version of the `packed-simd-2` crate. + +### 1.2.4 + +* Specify a semver bound for `clear_on_drop` rather than an exact version, + addressing an issue where changes to inline assembly in rustc prevented + `clear_on_drop` from working without an update. + +### 1.2.3 + +* Fix an issue identified by a Quarkslab audit (and Jack Grigg), where manually + constructing unreduced `Scalar` values, as needed for X/Ed25519, and then + performing scalar/scalar arithmetic could compute incorrect results. +* Switch to upstream Rust intrinsics for the IFMA backend now that they exist in + Rust and don't need to be defined locally. +* Ensure that the NAF computation works correctly, even for parameters never + used elsewhere in the codebase. +* Minor refactoring to EdwardsPoint decompression. +* Fix broken links in documentation. +* Fix compilation on nightly broken due to changes to the `#[doc(include)]` path + root (not quite correctly done in 1.2.2). + +### 1.2.2 + +* Fix a typo in an internal doc-comment. +* Add the "crypto" tag to crate metadata. +* Fix compilation on nightly broken due to changes to the `#[doc(include)]` path + root. + +### 1.2.1 + +* Fix a bug in bucket index calculations in the Pippenger multiscalar algorithm + for very large input sizes. +* Add a more extensive randomized multiscalar multiplication consistency check + to the test suite to prevent regressions. +* Ensure that that multiscalar and NAF computations work correctly on extremal + `Scalar` values constructed via `from_bits`. + +### 1.2.0 + +* New multiscalar multiplication algorithm with better performance for + large problem sizes. The backend algorithm is selected + transparently using the size hints of the input iterators, so no + changes are required for client crates to start using it. +* Equality of Edwards points is now checked in projective coordinates. +* Serde can now be used with `no_std`. + +### 1.1.4 + +* Fix typos in documentation comments. +* Remove unnecessary `Default` bound on `Scalar::from_hash`. + +### 1.1.3 + +* Reverts the change in 1.1.0 to allow owned and borrowed RNGs, which caused a breakage due to a subtle interaction with ownership rules. (The `RngCore` change is retained). + +### 1.1.2 + +* Disabled KaTeX on `docs.rs` pending proper [support upstream](https://github.com/rust-lang/docs.rs/issues/302). + +## 1.1.1 + +* Fixed an issue related to `#[cfg(rustdoc)]` which prevented documenting multiple backends. + +### 1.1.0 + +* Adds support for precomputation for multiscalar multiplication. +* Restructures the internal source tree into `serial` and `vector` backends (no change to external API). +* Adds a new IFMA backend which sets speed records. +* The `avx2_backend` feature is now an alias for the `simd_backend` feature, which autoselects an appropriate vector backend (currently AVX2 or IFMA). +* Replaces the `rand` dependency with `rand_core`. +* Generalizes trait bounds on `RistrettoPoint::random()` and `Scalar::random()` to allow owned and borrowed RNGs and to allow `RngCore` instead of `Rng`. + +### 1.0.3 + +* Adds `ConstantTimeEq` implementation for compressed points. + +### 1.0.2 + +* Fixes a typo in the naming of variables in Ristretto formulas (no change to functionality). + +### 1.0.1 + +* Depends on the stable `2.0` version of `subtle` instead of `2.0.0-pre.0`. + +### 1.0.0 + +Initial stable release. Yanked due to a dependency mistake (see above). + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/CODE_OF_CONDUCT.md b/net/gurk-rs/files/vendor/curve25519-dalek/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..a802fde --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/CODE_OF_CONDUCT.md @@ -0,0 +1,8 @@ +# Code of Conduct + +We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html), +with the following additional clauses: + +* We respect the rights to privacy and anonymity for contributors and people in + the community. If someone wishes to contribute under a pseudonym different to + their primary identity, that wish is to be respected by all contributors. diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/CONTRIBUTING.md b/net/gurk-rs/files/vendor/curve25519-dalek/CONTRIBUTING.md new file mode 100644 index 0000000..d4e0ff8 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/CONTRIBUTING.md @@ -0,0 +1,19 @@ +# Contributing to curve25519-dalek + +If you have questions or comments, please feel free to email the +authors. + +For feature requests, suggestions, and bug reports, please open an issue on +[our Github](https://github.com/dalek-cryptography/curve25519-dalek). (Or, send us +an email if you're opposed to using Github for whatever reason.) + +Patches are welcomed as pull requests on +[our Github](https://github.com/dalek-cryptography/curve25519-dalek), as well as by +email (preferably sent to all of the authors listed in `Cargo.toml`). + +All issues on curve25519-dalek are mentored, if you want help with a bug just +ask @isislovecruft or @hdevalence. + +Some issues are easier than others. The `easy` label can be used to find the +easy issues. If you want to work on an issue, please leave a comment so that we +can assign it to you! diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/Cargo.toml b/net/gurk-rs/files/vendor/curve25519-dalek/Cargo.toml new file mode 100644 index 0000000..cbeb3c9 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/Cargo.toml @@ -0,0 +1,97 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "curve25519-dalek" +version = "3.1.0" +authors = ["Isis Lovecruft ", "Henry de Valence "] +exclude = ["**/.gitignore", ".gitignore", ".travis.yml"] +description = "A pure-Rust implementation of group operations on ristretto255 and Curve25519" +homepage = "https://dalek.rs/curve25519-dalek" +documentation = "https://docs.rs/curve25519-dalek" +readme = "README.md" +keywords = ["cryptography", "crypto", "ristretto", "curve25519", "ristretto255"] +categories = ["cryptography", "no-std"] +license = "BSD-3-Clause" +repository = "https://github.com/dalek-cryptography/curve25519-dalek" +[package.metadata.docs.rs] +features = ["nightly", "simd_backend"] + +[[bench]] +name = "dalek_benchmarks" +harness = false +[dependencies.byteorder] +version = "^1.2.3" +features = ["i128"] +default-features = false + +[dependencies.digest] +version = "0.9" +default-features = false + +[dependencies.fiat-crypto] +version = "0.1.6" +optional = true + +[dependencies.packed_simd] +version = "0.3.4" +features = ["into_bits"] +optional = true +package = "packed_simd_2" + +[dependencies.rand_core] +version = "0.5" +default-features = false + +[dependencies.serde] +version = "1.0" +features = ["derive"] +optional = true +default-features = false + +[dependencies.subtle] +version = "^2.2.1" +default-features = false + +[dependencies.zeroize] +version = "1" +default-features = false +[dev-dependencies.bincode] +version = "1" + +[dev-dependencies.criterion] +version = "0.3.0" + +[dev-dependencies.hex] +version = "0.4.2" + +[dev-dependencies.rand] +version = "0.7" + +[dev-dependencies.sha2] +version = "0.9" +default-features = false + +[features] +alloc = ["zeroize/alloc"] +avx2_backend = ["simd_backend"] +default = ["std", "u64_backend"] +fiat_u32_backend = ["fiat-crypto"] +fiat_u64_backend = ["fiat-crypto"] +nightly = ["subtle/nightly"] +simd_backend = ["nightly", "u64_backend", "packed_simd"] +std = ["alloc", "subtle/std", "rand_core/std"] +u32_backend = [] +u64_backend = [] +[badges.travis-ci] +branch = "master" +repository = "dalek-cryptography/curve25519-dalek" diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/LICENSE b/net/gurk-rs/files/vendor/curve25519-dalek/LICENSE new file mode 100644 index 0000000..ff34757 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/LICENSE @@ -0,0 +1,65 @@ +Copyright (c) 2016-2021 isis agora lovecruft. All rights reserved. +Copyright (c) 2016-2021 Henry de Valence. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +======================================================================== + +Portions of curve25519-dalek were originally derived from Adam Langley's +Go ed25519 implementation, found at , +under the following licence: + +======================================================================== + +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/Makefile b/net/gurk-rs/files/vendor/curve25519-dalek/Makefile new file mode 100644 index 0000000..e447175 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/Makefile @@ -0,0 +1,8 @@ +FEATURES := nightly yolocrypto avx2_backend + +doc: + cargo rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html + +doc-internal: + cargo rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html --document-private-items + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/README.md b/net/gurk-rs/files/vendor/curve25519-dalek/README.md new file mode 100644 index 0000000..19679f9 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/README.md @@ -0,0 +1,220 @@ + +# curve25519-dalek [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) [![](https://img.shields.io/badge/dynamic/json.svg?label=docs&uri=https%3A%2F%2Fcrates.io%2Fapi%2Fv1%2Fcrates%2Fcurve25519-dalek%2Fversions&query=%24.versions%5B0%5D.num&colorB=4F74A6)](https://doc.dalek.rs) [![](https://travis-ci.org/dalek-cryptography/curve25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/curve25519-dalek) + + + +**A pure-Rust implementation of group operations on Ristretto and Curve25519.** + +`curve25519-dalek` is a library providing group operations on the Edwards and +Montgomery forms of Curve25519, and on the prime-order Ristretto group. + +`curve25519-dalek` is not intended to provide implementations of any particular +crypto protocol. Rather, implementations of those protocols (such as +[`x25519-dalek`][x25519-dalek] and [`ed25519-dalek`][ed25519-dalek]) should use +`curve25519-dalek` as a library. + +`curve25519-dalek` is intended to provide a clean and safe _mid-level_ API for use +implementing a wide range of ECC-based crypto protocols, such as key agreement, +signatures, anonymous credentials, rangeproofs, and zero-knowledge proof +systems. + +In particular, `curve25519-dalek` implements Ristretto, which constructs a +prime-order group from a non-prime-order Edwards curve. This provides the +speed and safety benefits of Edwards curve arithmetic, without the pitfalls of +cofactor-related abstraction mismatches. + +# Documentation + +The semver-stable, public-facing `curve25519-dalek` API is documented +[here][docs-external]. In addition, the unstable internal implementation +details are documented [here][docs-internal]. + +The `curve25519-dalek` documentation requires a custom HTML header to include +KaTeX for math support. Unfortunately `cargo doc` does not currently support +this, but docs can be built using +```sh +make doc +make doc-internal +``` + +# Use + +To import `curve25519-dalek`, add the following to the dependencies section of +your project's `Cargo.toml`: +```toml +curve25519-dalek = "3" +``` + +The sole breaking change in the `3.x` series was an update to the `digest` +version, and in terms of non-breaking changes it includes: + +* support for using `alloc` instead of `std` on stable Rust, +* the Elligator2 encoding for Edwards points, +* a fix to use `packed_simd2`, +* various documentation fixes and improvements, +* support for configurably-sized, precomputed lookup tables for basepoint scalar + multiplication, +* two new formally-verified field arithmetic backends which use the Fiat Crypto + Rust code, which is generated from proofs of functional correctness checked by + the Coq theorem proving system, and +* support for explicitly calling the `zeroize` traits for all point types. + +The `2.x` series has API almost entirely unchanged from the `1.x` series, +except that: + +* an error in the data modeling for the (optional) `serde` feature was + corrected, so that when the `2.x`-series `serde` implementation is used + with `serde-bincode`, the derived serialization matches the usual X/Ed25519 + formats; +* the `rand` version was updated. + +See `CHANGELOG.md` for more details. + +# Backends and Features + +The `nightly` feature enables features available only when using a Rust nightly +compiler. In particular, it is required for rendering documentation and for +the SIMD backends. + +Curve arithmetic is implemented using one of the following backends: + +* a `u32` backend using serial formulas and `u64` products; +* a `u64` backend using serial formulas and `u128` products; +* an `avx2` backend using [parallel formulas][parallel_doc] and `avx2` instructions (sets speed records); +* an `ifma` backend using [parallel formulas][parallel_doc] and `ifma` instructions (sets speed records); + +By default the `u64` backend is selected. To select a specific backend, use: +```sh +cargo build --no-default-features --features "std u32_backend" +cargo build --no-default-features --features "std u64_backend" +# Requires nightly, RUSTFLAGS="-C target_feature=+avx2" to use avx2 +cargo build --no-default-features --features "std simd_backend" +# Requires nightly, RUSTFLAGS="-C target_feature=+avx512ifma" to use ifma +cargo build --no-default-features --features "std simd_backend" +``` +Crates using `curve25519-dalek` can either select a backend on behalf of their +users, or expose feature flags that control the `curve25519-dalek` backend. + +The `std` feature is enabled by default, but it can be disabled for no-`std` +builds using `--no-default-features`. Note that this requires explicitly +selecting an arithmetic backend using one of the `_backend` features. +If no backend is selected, compilation will fail. + +# Safety + +The `curve25519-dalek` types are designed to make illegal states +unrepresentable. For example, any instance of an `EdwardsPoint` is +guaranteed to hold a point on the Edwards curve, and any instance of a +`RistrettoPoint` is guaranteed to hold a valid point in the Ristretto +group. + +All operations are implemented using constant-time logic (no +secret-dependent branches, no secret-dependent memory accesses), +unless specifically marked as being variable-time code. +We believe that our constant-time logic is lowered to constant-time +assembly, at least on `x86_64` targets. + +As an additional guard against possible future compiler optimizations, +the `subtle` crate places an optimization barrier before every +conditional move or assignment. More details can be found in [the +documentation for the `subtle` crate][subtle_doc]. + +Some functionality (e.g., multiscalar multiplication or batch +inversion) requires heap allocation for temporary buffers. All +heap-allocated buffers of potentially secret data are explicitly +zeroed before release. + +However, we do not attempt to zero stack data, for two reasons. +First, it's not possible to do so correctly: we don't have control +over stack allocations, so there's no way to know how much data to +wipe. Second, because `curve25519-dalek` provides a mid-level API, +the correct place to start zeroing stack data is likely not at the +entrypoints of `curve25519-dalek` functions, but at the entrypoints of +functions in other crates. + +The implementation is memory-safe, and contains no significant +`unsafe` code. The SIMD backend uses `unsafe` internally to call SIMD +intrinsics. These are marked `unsafe` only because invoking them on an +inappropriate CPU would cause `SIGILL`, but the entire backend is only +compiled with appropriate `target_feature`s, so this cannot occur. + +# Performance + +Benchmarks are run using [`criterion.rs`][criterion]: + +```sh +cargo bench --no-default-features --features "std u32_backend" +cargo bench --no-default-features --features "std u64_backend" +# Uses avx2 or ifma only if compiled for an appropriate target. +export RUSTFLAGS="-C target_cpu=native" +cargo bench --no-default-features --features "std simd_backend" +``` + +Performance is a secondary goal behind correctness, safety, and +clarity, but we aim to be competitive with other implementations. + +# FFI + +Unfortunately, we have no plans to add FFI to `curve25519-dalek` directly. The +reason is that we use Rust features to provide an API that maintains safety +invariants, which are not possible to maintain across an FFI boundary. For +instance, as described in the _Safety_ section above, invalid points are +impossible to construct, and this would not be the case if we exposed point +operations over FFI. + +However, `curve25519-dalek` is designed as a *mid-level* API, aimed at +implementing other, higher-level primitives. Instead of providing FFI at the +mid-level, our suggestion is to implement the higher-level primitive (a +signature, PAKE, ZKP, etc) in Rust, using `curve25519-dalek` as a dependency, +and have that crate provide a minimal, byte-buffer-oriented FFI specific to +that primitive. + +# Contributing + +Please see [CONTRIBUTING.md][contributing]. + +Patches and pull requests should be make against the `develop` +branch, **not** `master`. + +# About + +**SPOILER ALERT:** *The Twelfth Doctor's first encounter with the Daleks is in +his second full episode, "Into the Dalek". A beleaguered ship of the "Combined +Galactic Resistance" has discovered a broken Dalek that has turned "good", +desiring to kill all other Daleks. The Doctor, Clara and a team of soldiers +are miniaturized and enter the Dalek, which the Doctor names Rusty. They +repair the damage, but accidentally restore it to its original nature, causing +it to go on the rampage and alert the Dalek fleet to the whereabouts of the +rebel ship. However, the Doctor manages to return Rusty to its previous state +by linking his mind with the Dalek's: Rusty shares the Doctor's view of the +universe's beauty, but also his deep hatred of the Daleks. Rusty destroys the +other Daleks and departs the ship, determined to track down and bring an end +to the Dalek race.* + +`curve25519-dalek` is authored by Isis Agora Lovecruft and Henry de Valence. + +Portions of this library were originally a port of [Adam Langley's +Golang ed25519 library](https://github.com/agl/ed25519), which was in +turn a port of the reference `ref10` implementation. Most of this code, +including the 32-bit field arithmetic, has since been rewritten. + +The fast `u32` and `u64` scalar arithmetic was implemented by Andrew Moon, and +the addition chain for scalar inversion was provided by Brian Smith. The +optimised batch inversion was contributed by Sean Bowe and Daira Hopwood. + +The `no_std` and `zeroize` support was contributed by Tony Arcieri. + +Thanks also to Ashley Hauck, Lucas Salibian, and Manish Goregaokar for their +contributions. + +[ed25519-dalek]: https://github.com/dalek-cryptography/ed25519-dalek +[x25519-dalek]: https://github.com/dalek-cryptography/x25519-dalek +[contributing]: https://github.com/dalek-cryptography/curve25519-dalek/blob/master/CONTRIBUTING.md +[docs-external]: https://doc.dalek.rs/curve25519_dalek/ +[docs-internal]: https://doc-internal.dalek.rs/curve25519_dalek/ +[criterion]: https://github.com/japaric/criterion.rs +[parallel_doc]: https://doc-internal.dalek.rs/curve25519_dalek/backend/vector/avx2/index.html +[subtle_doc]: https://doc.dalek.rs/subtle/ diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/benches/dalek_benchmarks.rs b/net/gurk-rs/files/vendor/curve25519-dalek/benches/dalek_benchmarks.rs new file mode 100644 index 0000000..136d0e7 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/benches/dalek_benchmarks.rs @@ -0,0 +1,363 @@ +#![allow(non_snake_case)] + +extern crate rand; +use rand::rngs::OsRng; +use rand::thread_rng; + +#[macro_use] +extern crate criterion; + +use criterion::measurement::Measurement; +use criterion::BatchSize; +use criterion::Criterion; +use criterion::{BenchmarkGroup, BenchmarkId}; + +extern crate curve25519_dalek; + +use curve25519_dalek::constants; +use curve25519_dalek::scalar::Scalar; + +static BATCH_SIZES: [usize; 5] = [1, 2, 4, 8, 16]; +static MULTISCALAR_SIZES: [usize; 13] = [1, 2, 4, 8, 16, 32, 64, 128, 256, 384, 512, 768, 1024]; + +mod edwards_benches { + use super::*; + + use curve25519_dalek::edwards::EdwardsPoint; + + fn compress(c: &mut Criterion) { + let B = &constants::ED25519_BASEPOINT_POINT; + c.bench_function("EdwardsPoint compression", move |b| b.iter(|| B.compress())); + } + + fn decompress(c: &mut Criterion) { + let B_comp = &constants::ED25519_BASEPOINT_COMPRESSED; + c.bench_function("EdwardsPoint decompression", move |b| { + b.iter(|| B_comp.decompress().unwrap()) + }); + } + + fn consttime_fixed_base_scalar_mul(c: &mut Criterion) { + let B = &constants::ED25519_BASEPOINT_TABLE; + let s = Scalar::from(897987897u64).invert(); + c.bench_function("Constant-time fixed-base scalar mul", move |b| { + b.iter(|| B * &s) + }); + } + + fn consttime_variable_base_scalar_mul(c: &mut Criterion) { + let B = &constants::ED25519_BASEPOINT_POINT; + let s = Scalar::from(897987897u64).invert(); + c.bench_function("Constant-time variable-base scalar mul", move |b| { + b.iter(|| B * s) + }); + } + + fn vartime_double_base_scalar_mul(c: &mut Criterion) { + c.bench_function("Variable-time aA+bB, A variable, B fixed", |bench| { + let mut rng = thread_rng(); + let A = &Scalar::random(&mut rng) * &constants::ED25519_BASEPOINT_TABLE; + bench.iter_batched( + || (Scalar::random(&mut rng), Scalar::random(&mut rng)), + |(a, b)| EdwardsPoint::vartime_double_scalar_mul_basepoint(&a, &A, &b), + BatchSize::SmallInput, + ); + }); + } + + criterion_group! { + name = edwards_benches; + config = Criterion::default(); + targets = + compress, + decompress, + consttime_fixed_base_scalar_mul, + consttime_variable_base_scalar_mul, + vartime_double_base_scalar_mul, + } +} + +mod multiscalar_benches { + use super::*; + + use curve25519_dalek::edwards::EdwardsPoint; + use curve25519_dalek::edwards::VartimeEdwardsPrecomputation; + use curve25519_dalek::traits::MultiscalarMul; + use curve25519_dalek::traits::VartimeMultiscalarMul; + use curve25519_dalek::traits::VartimePrecomputedMultiscalarMul; + + fn construct_scalars(n: usize) -> Vec { + let mut rng = thread_rng(); + (0..n).map(|_| Scalar::random(&mut rng)).collect() + } + + fn construct_points(n: usize) -> Vec { + let mut rng = thread_rng(); + (0..n) + .map(|_| &Scalar::random(&mut rng) * &constants::ED25519_BASEPOINT_TABLE) + .collect() + } + + fn construct(n: usize) -> (Vec, Vec) { + (construct_scalars(n), construct_points(n)) + } + + fn consttime_multiscalar_mul(c: &mut BenchmarkGroup) { + for multiscalar_size in &MULTISCALAR_SIZES { + c.bench_with_input( + BenchmarkId::new( + "Constant-time variable-base multiscalar multiplication", + *multiscalar_size, + ), + &multiscalar_size, + |b, &&size| { + let points = construct_points(size); + // This is supposed to be constant-time, but we might as well + // rerandomize the scalars for every call just in case. + b.iter_batched( + || construct_scalars(size), + |scalars| EdwardsPoint::multiscalar_mul(&scalars, &points), + BatchSize::SmallInput, + ); + }, + ); + } + } + + fn vartime_multiscalar_mul(c: &mut BenchmarkGroup) { + for multiscalar_size in &MULTISCALAR_SIZES { + c.bench_with_input( + BenchmarkId::new( + "Variable-time variable-base multiscalar multiplication", + *multiscalar_size, + ), + &multiscalar_size, + |b, &&size| { + let points = construct_points(size); + // Rerandomize the scalars for every call to prevent + // false timings from better caching (e.g., the CPU + // cache lifts exactly the right table entries for the + // benchmark into the highest cache levels). + b.iter_batched( + || construct_scalars(size), + |scalars| EdwardsPoint::vartime_multiscalar_mul(&scalars, &points), + BatchSize::SmallInput, + ); + }, + ); + } + } + + fn vartime_precomputed_pure_static(c: &mut BenchmarkGroup) { + for multiscalar_size in &MULTISCALAR_SIZES { + c.bench_with_input( + BenchmarkId::new( + "Variable-time fixed-base multiscalar multiplication", + &multiscalar_size, + ), + &multiscalar_size, + move |b, &&total_size| { + let static_size = total_size; + + let static_points = construct_points(static_size); + let precomp = VartimeEdwardsPrecomputation::new(&static_points); + // Rerandomize the scalars for every call to prevent + // false timings from better caching (e.g., the CPU + // cache lifts exactly the right table entries for the + // benchmark into the highest cache levels). + b.iter_batched( + || construct_scalars(static_size), + |scalars| precomp.vartime_multiscalar_mul(&scalars), + BatchSize::SmallInput, + ); + }, + ); + } + } + + fn vartime_precomputed_helper( + c: &mut BenchmarkGroup, + dynamic_fraction: f64, + ) { + for multiscalar_size in &MULTISCALAR_SIZES { + c.bench_with_input( + BenchmarkId::new( + "Variable-time mixed-base multiscalar multiplication ({:.0}pct dyn)", + format!("({:.0}pct dyn)", 100.0 * dynamic_fraction), + ), + &multiscalar_size, + move |b, &&total_size| { + let dynamic_size = ((total_size as f64) * dynamic_fraction) as usize; + let static_size = total_size - dynamic_size; + + let static_points = construct_points(static_size); + let dynamic_points = construct_points(dynamic_size); + let precomp = VartimeEdwardsPrecomputation::new(&static_points); + // Rerandomize the scalars for every call to prevent + // false timings from better caching (e.g., the CPU + // cache lifts exactly the right table entries for the + // benchmark into the highest cache levels). Timings + // should be independent of points so we don't + // randomize them. + b.iter_batched( + || { + ( + construct_scalars(static_size), + construct_scalars(dynamic_size), + ) + }, + |(static_scalars, dynamic_scalars)| { + precomp.vartime_mixed_multiscalar_mul( + &static_scalars, + &dynamic_scalars, + &dynamic_points, + ) + }, + BatchSize::SmallInput, + ); + }, + ); + } + } + + fn multiscalar_multiplications(c: &mut Criterion) { + let mut group: BenchmarkGroup<_> = c.benchmark_group("Multiscalar muls"); + + consttime_multiscalar_mul(&mut group); + vartime_multiscalar_mul(&mut group); + vartime_precomputed_pure_static(&mut group); + + let dynamic_fracs = [0.0, 0.2, 0.5]; + for frac in dynamic_fracs.iter() { + vartime_precomputed_helper(&mut group, *frac); + } + group.finish(); + } + + criterion_group! { + name = multiscalar_benches; + // Lower the sample size to run the benchmarks faster + config = Criterion::default().sample_size(15); + targets = + multiscalar_multiplications, + } +} + +mod ristretto_benches { + use super::*; + use curve25519_dalek::ristretto::RistrettoPoint; + + fn compress(c: &mut Criterion) { + c.bench_function("RistrettoPoint compression", |b| { + let B = &constants::RISTRETTO_BASEPOINT_POINT; + b.iter(|| B.compress()) + }); + } + + fn decompress(c: &mut Criterion) { + c.bench_function("RistrettoPoint decompression", |b| { + let B_comp = &constants::RISTRETTO_BASEPOINT_COMPRESSED; + b.iter(|| B_comp.decompress().unwrap()) + }); + } + + fn double_and_compress_batch(c: &mut BenchmarkGroup) { + for batch_size in &BATCH_SIZES { + c.bench_with_input( + BenchmarkId::new("Batch Ristretto double-and-encode", *batch_size), + &batch_size, + |b, &&size| { + let mut rng = OsRng; + let points: Vec = (0..size) + .map(|_| RistrettoPoint::random(&mut rng)) + .collect(); + b.iter(|| RistrettoPoint::double_and_compress_batch(&points)); + }, + ); + } + } + + fn double_and_compress_group(c: &mut Criterion) { + let mut group: BenchmarkGroup<_> = c.benchmark_group("double & compress batched"); + double_and_compress_batch(&mut group); + group.finish(); + } + + criterion_group! { + name = ristretto_benches; + config = Criterion::default(); + targets = + compress, + decompress, + double_and_compress_group, + } +} + +mod montgomery_benches { + use super::*; + + fn montgomery_ladder(c: &mut Criterion) { + c.bench_function("Montgomery pseudomultiplication", |b| { + let B = constants::X25519_BASEPOINT; + let s = Scalar::from(897987897u64).invert(); + b.iter(|| B * s); + }); + } + + criterion_group! { + name = montgomery_benches; + config = Criterion::default(); + targets = montgomery_ladder, + } +} + +mod scalar_benches { + use super::*; + + fn scalar_inversion(c: &mut Criterion) { + c.bench_function("Scalar inversion", |b| { + let s = Scalar::from(897987897u64).invert(); + b.iter(|| s.invert()); + }); + } + + fn batch_scalar_inversion(c: &mut BenchmarkGroup) { + for batch_size in &BATCH_SIZES { + c.bench_with_input( + BenchmarkId::new("Batch scalar inversion", *batch_size), + &batch_size, + |b, &&size| { + let mut rng = OsRng; + let scalars: Vec = + (0..size).map(|_| Scalar::random(&mut rng)).collect(); + b.iter(|| { + let mut s = scalars.clone(); + Scalar::batch_invert(&mut s); + }); + }, + ); + } + } + + fn batch_scalar_inversion_group(c: &mut Criterion) { + let mut group: BenchmarkGroup<_> = c.benchmark_group("batch scalar inversion"); + batch_scalar_inversion(&mut group); + group.finish(); + } + + criterion_group! { + name = scalar_benches; + config = Criterion::default(); + targets = + scalar_inversion, + batch_scalar_inversion_group, + } +} + +criterion_main!( + scalar_benches::scalar_benches, + montgomery_benches::montgomery_benches, + ristretto_benches::ristretto_benches, + edwards_benches::edwards_benches, + multiscalar_benches::multiscalar_benches, +); diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/dalek-logo-clear.png b/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/dalek-logo-clear.png new file mode 100644 index 0000000..d3170d8 Binary files /dev/null and b/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/dalek-logo-clear.png differ diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/dalek-logo.png b/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/dalek-logo.png new file mode 100644 index 0000000..83d6a0c Binary files /dev/null and b/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/dalek-logo.png differ diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/dalek-logo.svg b/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/dalek-logo.svg new file mode 100644 index 0000000..3e87a44 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/dalek-logo.svg @@ -0,0 +1 @@ +dalek \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/rustdoc-include-katex-header.html b/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/rustdoc-include-katex-header.html new file mode 100644 index 0000000..bc4e3d8 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/docs/assets/rustdoc-include-katex-header.html @@ -0,0 +1,10 @@ + + + + + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/docs/avx2-notes.md b/net/gurk-rs/files/vendor/curve25519-dalek/docs/avx2-notes.md new file mode 100644 index 0000000..ccb5022 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/docs/avx2-notes.md @@ -0,0 +1,140 @@ +An AVX2 implementation of the vectorized point operation strategy. + +# Field element representation + +Our strategy is to implement 4-wide multiplication and squaring by +wordslicing, using one 64-bit AVX2 lane for each field element. Field +elements are represented in the usual way as 10 `u32` limbs in radix +\\(25.5\\) (i.e., alternating between \\(2\^{26}\\) for even limbs and +\\(2\^{25}\\) for odd limbs). This has the effect that passing between +the parallel 32-bit AVX2 representation and the serial 64-bit +representation (which uses radix \\(2^{51}\\)) amounts to regrouping +digits. + +The field element representation is oriented around the AVX2 +`vpmuludq` instruction, which multiplies the low 32 bits of each +64-bit lane of each operand to produce a 64-bit result. + +```text,no_run +(a1 ?? b1 ?? c1 ?? d1 ??) +(a2 ?? b2 ?? c2 ?? d2 ??) + +(a1*a2 b1*b2 c1*c2 d1*d2) +``` + +To unpack 32-bit values into 64-bit lanes for use in multiplication +it would be convenient to use the `vpunpck[lh]dq` instructions, +which unpack and interleave the low and high 32-bit lanes of two +source vectors. +However, the AVX2 versions of these instructions are designed to +operate only within 128-bit lanes of the 256-bit vectors, so that +interleaving the low lanes of `(a0 b0 c0 d0 a1 b1 c1 d1)` with zero +gives `(a0 00 b0 00 a1 00 b1 00)`. Instead, we pre-shuffle the data +layout as `(a0 b0 a1 b1 c0 d0 c1 d1)` so that we can unpack the +"low" and "high" parts as + +```text,no_run +(a0 00 b0 00 c0 00 d0 00) +(a1 00 b1 00 c1 00 d1 00) +``` + +The data layout for a vector of four field elements \\( (a,b,c,d) +\\) with limbs \\( a_0, a_1, \ldots, a_9 \\) is as `[u32x8; 5]` in +the form + +```text,no_run +(a0 b0 a1 b1 c0 d0 c1 d1) +(a2 b2 a3 b3 c2 d2 c3 d3) +(a4 b4 a5 b5 c4 d4 c5 d5) +(a6 b6 a7 b7 c6 d6 c7 d7) +(a8 b8 a9 b9 c8 d8 c9 d9) +``` + +Since this breaks cleanly into two 128-bit lanes, it may be possible +to adapt it to 128-bit vector instructions such as NEON without too +much difficulty. + +# Avoiding Overflow in Doubling + +To analyze the size of the field element coefficients during the +computations, we can parameterize the bounds on the limbs of each +field element by \\( b \in \mathbb R \\) representing the excess bits +above that limb's radix, so that each limb is bounded by either +\\(2\^{25+b} \\) or \\( 2\^{26+b} \\), as appropriate. + +The multiplication routine requires that its inputs are bounded with +\\( b < 1.75 \\), in order to fit a multiplication by \\( 19 \\) +into 32 bits. Since \\( \lg 19 < 4.25 \\), \\( 19x < 2\^{32} \\) +when \\( x < 2\^{27.75} = 2\^{26 + 1.75} \\). However, this is only +required for one of the inputs; the other can grow up to \\( b < 2.5 +\\). + +In addition, the multiplication and squaring routines do not +canonically reduce their outputs, but can leave some small uncarried +excesses, so that their reduced outputs are bounded with +\\( b < 0.007 \\). + +The non-parallel portion of the doubling formulas is +$$ +\begin{aligned} +(S\_5 &&,&& S\_6 &&,&& S\_8 &&,&& S\_9 ) +&\gets +(S\_1 + S\_2 &&,&& S\_1 - S\_2 &&,&& S\_1 + 2S\_3 - S\_2 &&,&& S\_1 + S\_2 - S\_4) +\end{aligned} +$$ + +Computing \\( (S\_5, S\_6, S\_8, S\_9 ) \\) as +$$ +\begin{matrix} + & S\_1 & S\_1 & S\_1 & S\_1 \\\\ ++& S\_2 & & & S\_2 \\\\ ++& & & S\_3 & \\\\ ++& & & S\_3 & \\\\ ++& & 2p & 2p & 2p \\\\ +-& & S\_2 & S\_2 & \\\\ +-& & & & S\_4 \\\\ +=& S\_5 & S\_6 & S\_8 & S\_9 +\end{matrix} +$$ +results in bit-excesses \\( < (1.01, 1.60, 2.33, 2.01)\\) for +\\( (S\_5, S\_6, S\_8, S\_9 ) \\). The products we want to compute +are then +$$ +\begin{aligned} +X\_3 &\gets S\_8 S\_9 \leftrightarrow (2.33, 2.01) \\\\ +Y\_3 &\gets S\_5 S\_6 \leftrightarrow (1.01, 1.60) \\\\ +Z\_3 &\gets S\_8 S\_6 \leftrightarrow (2.33, 1.60) \\\\ +T\_3 &\gets S\_5 S\_9 \leftrightarrow (1.01, 2.01) +\end{aligned} +$$ +which are too large: it's not possible to arrange the multiplicands so +that one vector has \\(b < 2.5\\) and the other has \\( b < 1.75 \\). +However, if we flip the sign of \\( S\_4 = S\_0\^2 \\) during +squaring, so that we output \\(S\_4' = -S\_4 \pmod p\\), then we can +compute +$$ +\begin{matrix} + & S\_1 & S\_1 & S\_1 & S\_1 \\\\ ++& S\_2 & & & S\_2 \\\\ ++& & & S\_3 & \\\\ ++& & & S\_3 & \\\\ ++& & & & S\_4' \\\\ ++& & 2p & 2p & \\\\ +-& & S\_2 & S\_2 & \\\\ +=& S\_5 & S\_6 & S\_8 & S\_9 +\end{matrix} +$$ +resulting in bit-excesses \\( < (1.01, 1.60, 2.33, 1.60)\\) for +\\( (S\_5, S\_6, S\_8, S\_9 ) \\). The products we want to compute +are then +$$ +\begin{aligned} +X\_3 &\gets S\_8 S\_9 \leftrightarrow (2.33, 1.60) \\\\ +Y\_3 &\gets S\_5 S\_6 \leftrightarrow (1.01, 1.60) \\\\ +Z\_3 &\gets S\_8 S\_6 \leftrightarrow (2.33, 1.60) \\\\ +T\_3 &\gets S\_5 S\_9 \leftrightarrow (1.01, 1.60) +\end{aligned} +$$ +whose right-hand sides are all bounded with \\( b < 1.75 \\) and +whose left-hand sides are all bounded with \\( b < 2.5 \\), +so that we can avoid any intermediate reductions. diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/docs/ifma-notes.md b/net/gurk-rs/files/vendor/curve25519-dalek/docs/ifma-notes.md new file mode 100644 index 0000000..c6fd3b3 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/docs/ifma-notes.md @@ -0,0 +1,580 @@ +An AVX512-IFMA implementation of the vectorized point operation +strategy. + +# IFMA instructions + +AVX512-IFMA is an extension to AVX-512 consisting of two instructions: + +* `vpmadd52luq`: packed multiply of unsigned 52-bit integers and add + the low 52 product bits to 64-bit accumulators; +* `vpmadd52huq`: packed multiply of unsigned 52-bit integers and add + the high 52 product bits to 64-bit accumulators; + +These operate on 64-bit lanes of their source vectors, taking the low +52 bits of each lane of each source vector, computing the 104-bit +products of each pair, and then adding either the high or low 52 bits +of the 104-bit products to the 64-bit lanes of the destination vector. +The multiplication is performed internally by reusing circuitry for +floating-point arithmetic. Although these instructions are part of +AVX512, the AVX512VL (vector length) extension (present whenever IFMA +is) allows using them with 512, 256, or 128-bit operands. + +This provides a major advantage to vectorized integer operations: +previously, vector operations could only use a \\(32 \times 32 +\rightarrow 64\\)-bit multiplier, while serial code could use a +\\(64\times 64 \rightarrow 128\\)-bit multiplier. + +## IFMA for big-integer multiplications + +A detailed example of the intended use of the IFMA instructions can be +found in a 2016 paper by Gueron and Krasnov, [_Accelerating Big +Integer Arithmetic Using Intel IFMA Extensions_][2016_gueron_krasnov]. +The basic idea is that multiplication of large integers (such as 1024, +2048, or more bits) can be performed as follows. + +First, convert a “packed” 64-bit representation +\\[ +\begin{aligned} +x &= x'_0 + x'_1 2^{64} + x'_2 2^{128} + \cdots \\\\ +y &= y'_0 + y'_1 2^{64} + y'_2 2^{128} + \cdots +\end{aligned} +\\] +into a “redundant” 52-bit representation +\\[ +\begin{aligned} +x &= x_0 + x_1 2^{52} + x_2 2^{104} + \cdots \\\\ +y &= y_0 + y_1 2^{52} + y_2 2^{104} + \cdots +\end{aligned} +\\] +with each \\(x_i, y_j\\) in a 64-bit lane. + +Writing the product as \\(z = z_0 + z_1 2^{52} + z_2 2^{104} + \cdots\\), +the “schoolbook” multiplication strategy gives +\\[ +\begin{aligned} +&z_0 &&=& x_0 & y_0 & & & & & & & & \\\\ +&z_1 &&=& x_1 & y_0 &+ x_0 & y_1 & & & & & & \\\\ +&z_2 &&=& x_2 & y_0 &+ x_1 & y_1 &+ x_0 & y_2 & & & & \\\\ +&z_3 &&=& x_3 & y_0 &+ x_2 & y_1 &+ x_1 & y_2 &+ x_0 & y_3 & & \\\\ +&z_4 &&=& \vdots\\;&\\;\vdots &+ x_3 & y_1 &+ x_2 & y_2 &+ x_1 & y_3 &+ \cdots& \\\\ +&z_5 &&=& & & \vdots\\;&\\;\vdots &+ x_3 & y_2 &+ x_2 & y_3 &+ \cdots& \\\\ +&z_6 &&=& & & & & \vdots\\;&\\;\vdots &+ x_3 & y_3 &+ \cdots& \\\\ +&z_7 &&=& & & & & & & \vdots\\;&\\;\vdots &+ \cdots& \\\\ +&\vdots&&=& & & & & & & & & \ddots& \\\\ +\end{aligned} +\\] +Notice that the product coefficient \\(z_k\\), representing the value +\\(z_k 2^{52k}\\), is the sum of all product terms +\\( +(x_i 2^{52 i}) (y_j 2^{52 j}) +\\) +with \\(k = i + j\\). +Write the IFMA operators \\(\mathrm{lo}(a,b)\\), denoting the low +\\(52\\) bits of \\(ab\\), and +\\(\mathrm{hi}(a,b)\\), denoting the high \\(52\\) bits of +\\(ab\\). +Now we can rewrite the product terms as +\\[ +\begin{aligned} +(x_i 2^{52 i}) (y_j 2^{52 j}) +&= +2^{52 (i+j)}( +\mathrm{lo}(x_i, y_j) + +\mathrm{hi}(x_i, y_j) 2^{52} +) +\\\\ +&= +\mathrm{lo}(x_i, y_j) 2^{52 (i+j)} + +\mathrm{hi}(x_i, y_j) 2^{52 (i+j+1)}. +\end{aligned} +\\] +This means that the low half of \\(x_i y_j\\) can be accumulated onto +the product limb \\(z_{i+j}\\) and the high half can be directly +accumulated onto the next-higher product limb \\(z_{i+j+1}\\) with no +additional operations. This allows rewriting the schoolbook +multiplication into the form +\\[ +\begin{aligned} +&z_0 &&=& \mathrm{lo}(x_0,&y_0) & & & & & & & & & & \\\\ +&z_1 &&=& \mathrm{lo}(x_1,&y_0) &+\mathrm{hi}(x_0,&y_0) &+\mathrm{lo}(x_0,&y_1) & & & & & & \\\\ +&z_2 &&=& \mathrm{lo}(x_2,&y_0) &+\mathrm{hi}(x_1,&y_0) &+\mathrm{lo}(x_1,&y_1) &+\mathrm{hi}(x_0,&y_1) &+\mathrm{lo}(x_0,&y_2) & & \\\\ +&z_3 &&=& \mathrm{lo}(x_3,&y_0) &+\mathrm{hi}(x_2,&y_0) &+\mathrm{lo}(x_2,&y_1) &+\mathrm{hi}(x_1,&y_1) &+\mathrm{lo}(x_1,&y_2) &+ \cdots& \\\\ +&z_4 &&=& \vdots\\;&\\;\vdots &+\mathrm{hi}(x_3,&y_0) &+\mathrm{lo}(x_3,&y_1) &+\mathrm{hi}(x_2,&y_1) &+\mathrm{lo}(x_2,&y_2) &+ \cdots& \\\\ +&z_5 &&=& & & \vdots\\;&\\;\vdots & \vdots\\;&\\;\vdots &+\mathrm{hi}(x_3,&y_1) &+\mathrm{lo}(x_3,&y_2) &+ \cdots& \\\\ +&z_6 &&=& & & & & & & \vdots\\;&\\;\vdots & \vdots\\;&\\;\vdots &+ \cdots& \\\\ +&\vdots&&=& & & & & & & & & & & \ddots& \\\\ +\end{aligned} +\\] +Gueron and Krasnov implement multiplication by constructing vectors +out of the columns of this diagram, so that the source operands for +the IFMA instructions are of the form \\((x_0, x_1, x_2, \ldots)\\) +and \\((y_i, y_i, y_i, \ldots)\\). +After performing the multiplication, +the product terms \\(z_i\\) are then repacked into a 64-bit representation. + +## An alternative strategy + +The strategy described above is aimed at big-integer multiplications, +such as 1024, 2048, or 4096 bits, which would be used for applications +like RSA. However, elliptic curve cryptography uses much smaller field +sizes, such as 256 or 384 bits, so a different strategy is needed. + +The parallel Edwards formulas provide parallelism at the level of the +formulas for curve operations. This means that instead of scanning +through the terms of the source operands and parallelizing *within* a +field element (as described above), we can arrange the computation in +product-scanning form and parallelize *across* field elements (as +described below). + +The parallel Edwards +formulas provide 4-way parallelism, so they can be implemented using +256-bit vectors using a single 64-bit lane for each element, or using +512-bit vectors using two 64-bit lanes. +The only available CPU supporting IFMA (the +i3-8121U) executes 512-bit IFMA instructions at half rate compared to +256-bit instructions, so for now there's no throughput advantage to +using 512-bit IFMA instructions, and this implementation uses 256-bit +vectors. + +To extend this to 512-bit vectors, it's only only necessary to achieve +2-way parallelism, and it's possible (with a small amount of overhead) +to create a hybrid strategy that operates entirely within 128-bit +lanes. This means that cross-lane operations can use the faster +`vpshufd` (1c latency) instead of a general shuffle instruction (3c +latency). + +# Choice of radix + +The inputs to IFMA instructions are 52 bits wide, so the radix \\(r\\) +used to represent a multiprecision integer must be \\( r \leq 52 \\). +The obvious choice is the "native" radix \\(r = 52\\). + +As described above, this choice +has the advantage that for \\(x_i, y_j \in [0,2^{52})\\), the product term +\\[ +\begin{aligned} +(x_i 2^{52 i}) (y_j 2^{52 j}) +&= +2^{52 (i+j)}( +\mathrm{lo}(x_i, y_j) + +\mathrm{hi}(x_i, y_j) 2^{52} +) +\\\\ +&= +\mathrm{lo}(x_i, y_j) 2^{52 (i+j)} + +\mathrm{hi}(x_i, y_j) 2^{52 (i+j+1)}, +\end{aligned} +\\] +so that the low and high halves of the product can be directly accumulated +onto the product limbs. +In contrast, when using a smaller radix \\(r = 52 - k\\), +the product term has the form +\\[ +\begin{aligned} +(x_i 2^{r i}) (y_j 2^{r j}) +&= +2^{r (i+j)}( +\mathrm{lo}(x_i, y_j) + +\mathrm{hi}(x_i, y_j) 2^{52} +) +\\\\ +&= +\mathrm{lo}(x_i, y_j) 2^{r (i+j)} + +( +\mathrm{hi}(x_i, y_j) 2^k +) +2^{r (i+j+1)}. +\end{aligned} +\\] +What's happening is that the product \\(x_i y_j\\) of size \\(2r\\) +bits is split not at \\(r\\) but at \\(52\\), so \\(k\\) product bits +are placed into the low half instead of the high half. This means +that the high half of the product cannot be directly accumulated onto +\\(z_{i+j+1}\\), but must first be multiplied by \\(2^k\\) (i.e., left +shifted by \\(k\\)). In addition, the low half of the product is +\\(52\\) bits large instead of \\(r\\) bits. + +## Handling offset product terms + +[Drucker and Gueron][2018_drucker_gueron] analyze the choice of radix +in the context of big-integer squaring, outlining three ways to handle +the offset product terms, before concluding that all of them are +suboptimal: + +1. Shift the results after accumulation; +2. Shift the input operands before multiplication; +3. Split the MAC operation, accumulating into a zeroed register, + shifting the result, and then adding. + +The first option is rejected because it could double-shift some +previously accumulated terms, the second doesn't work because the +inputs could become larger than \\(52\\) bits, and the third requires +additional instructions to handle the shifting and adding. + +Based on an analysis of total number of instructions, they suggest an +addition to the instruction set, which they call `FMSA` (fused +multiply-shift-add). This would shift the result according to an 8-bit +immediate value before accumulating it into the destination register. + +However, this change to the instruction set doesn't seem to be +necessary. Instead, the product terms can be grouped according to +their coefficients, accumulated together, then shifted once before +adding them to the final sum. This uses an extra register, shift, and +add, but only once per product term (accumulation target), not once +per source term (as in the Drucker-Gueron paper). + +Moreover, because IFMA instructions execute only on two ports +(presumably 0 and 1), while adds and shifts can execute on three ports +(0, 1, and 5), the adds and shifts can execute independently of the +IFMA operations, as long as there is not too much pressure on port 5. +This means that, although the total number of instructions increases, +the shifts and adds do not necessarily increase the execution time, as +long as throughput is limited by IFMA operations. + +Finally, because IFMA instructions have 4 cycle latency and 0.5/1 +cycle throughput (for 256/512 bit vectors), maximizing IFMA throughput +requires either 8 (for 256) or 4 (for 512) independent operations. So +accumulating groups of terms independently before adding them at the +end may be necessary anyways, in order to prevent long chains of +dependent instructions. + +## Advantages of a smaller radix + +Using a smaller radix has other advantages. Although radix \\(52\\) +is an unsaturated representation from the point of view of the +\\(64\\)-bit accumulators (because up to 4096 product terms can be +accumulated without carries), it's a saturated representation from the +point of view of the multiplier (since \\(52\\)-bit values are the +maximum input size). + +Because the inputs to a multiplication must have all of their limbs +bounded by \\(2^{52}\\), limbs in excess of \\(2^{52}\\) must be +reduced before they can be used as an input. The +[Gueron-Krasnov][2016_gueron_krasnov] paper suggests normalizing +values using a standard, sequential carry chain: for each limb, add +the carryin from reducing the previous limb, compute the carryout and +reduce the current limb, then move to the next limb. + +However, when using a smaller radix, such as \\(51\\), each limb can +store a carry bit and still be used as the input to a multiplication. +This means that the inputs do not need to be normalized, and instead +of using a sequential carry chain, we can compute all carryouts in +parallel, reduce all limbs in parallel, and then add the carryins in +parallel (possibly growing the limb values by one bit). + +Because the output of this partial reduction is an acceptable +multiplication input, we can "close the loop" using partial reductions +and never have to normalize to a canonical representation through the +entire computation, in contrast to the Gueron-Krasnov approach, which +converts back to a packed representation after every operation. (This +idea seems to trace back to at least as early as [this 1999 +paper][1999_walter]). + +Using \\(r = 51\\) is enough to keep a carry bit in each limb and +avoid normalizations. What about an even smaller radix? One reason +to choose a smaller radix would be to align the limb boundaries with +an inline reduction (for instance, choosing \\(r = 43\\) for the +Mersenne field \\(p = 2^{127} - 1\\)), but for \\(p = 2^{255 - 19}\\), +\\(r = 51 = 255/5\\) is the natural choice. + +# Multiplication + +The inputs to a multiplication are two field elements +\\[ +\begin{aligned} +x &= x_0 + x_1 2^{51} + x_2 2^{102} + x_3 2^{153} + x_4 2^{204} \\\\ +y &= y_0 + y_1 2^{51} + y_2 2^{102} + y_3 2^{153} + y_4 2^{204}, +\end{aligned} +\\] +with limbs in range \\([0,2^{52})\\). + +Writing the product terms as +\\[ +\begin{aligned} +z &= z_0 + z_1 2^{51} + z_2 2^{102} + z_3 2^{153} + z_4 2^{204} \\\\ + &+ z_5 2^{255} + z_6 2^{306} + z_7 2^{357} + z_8 2^{408} + z_9 2^{459}, +\end{aligned} +\\] +a schoolbook multiplication in product scanning form takes the form +\\[ +\begin{aligned} +z_0 &= x_0 y_0 \\\\ +z_1 &= x_1 y_0 + x_0 y_1 \\\\ +z_2 &= x_2 y_0 + x_1 y_1 + x_0 y_2 \\\\ +z_3 &= x_3 y_0 + x_2 y_1 + x_1 y_2 + x_0 y_3 \\\\ +z_4 &= x_4 y_0 + x_3 y_1 + x_2 y_2 + x_1 y_3 + x_0 y_4 \\\\ +z_5 &= x_4 y_1 + x_3 y_2 + x_2 y_3 + x_1 y_4 \\\\ +z_6 &= x_4 y_2 + x_3 y_3 + x_2 y_4 \\\\ +z_7 &= x_4 y_3 + x_3 y_4 \\\\ +z_8 &= x_4 y_4 \\\\ +z_9 &= 0 \\\\ +\end{aligned} +\\] +Each term \\(x_i y_j\\) can be written in terms of IFMA operations as +\\[ +x_i y_j = \mathrm{lo}(x_i,y_j) + 2\mathrm{hi}(x_i,y_j)2^{51}. +\\] +Substituting this equation into the schoolbook multiplication, then +moving terms to eliminate the \\(2^{51}\\) factors gives +\\[ +\begin{aligned} +z_0 &= \mathrm{lo}(x_0, y_0) \\\\ + &+ \qquad 0 \\\\ +z_1 &= \mathrm{lo}(x_1, y_0) + \mathrm{lo}(x_0, y_1) \\\\ + &+ \qquad 2( \mathrm{hi}(x_0, y_0) )\\\\ +z_2 &= \mathrm{lo}(x_2, y_0) + \mathrm{lo}(x_1, y_1) + \mathrm{lo}(x_0, y_2) \\\\ + &+ \qquad 2( \mathrm{hi}(x_1, y_0) + \mathrm{hi}(x_0, y_1) )\\\\ +z_3 &= \mathrm{lo}(x_3, y_0) + \mathrm{lo}(x_2, y_1) + \mathrm{lo}(x_1, y_2) + \mathrm{lo}(x_0, y_3) \\\\ + &+ \qquad 2( \mathrm{hi}(x_2, y_0) + \mathrm{hi}(x_1, y_1) + \mathrm{hi}(x_0, y_2) )\\\\ +z_4 &= \mathrm{lo}(x_4, y_0) + \mathrm{lo}(x_3, y_1) + \mathrm{lo}(x_2, y_2) + \mathrm{lo}(x_1, y_3) + \mathrm{lo}(x_0, y_4) \\\\ + &+ \qquad 2( \mathrm{hi}(x_3, y_0) + \mathrm{hi}(x_2, y_1) + \mathrm{hi}(x_1, y_2) + \mathrm{hi}(x_0, y_3) )\\\\ +z_5 &= \mathrm{lo}(x_4, y_1) + \mathrm{lo}(x_3, y_2) + \mathrm{lo}(x_2, y_3) + \mathrm{lo}(x_1, y_4) \\\\ + &+ \qquad 2( \mathrm{hi}(x_4, y_0) + \mathrm{hi}(x_3, y_1) + \mathrm{hi}(x_2, y_2) + \mathrm{hi}(x_1, y_3) + \mathrm{hi}(x_0, y_4) )\\\\ +z_6 &= \mathrm{lo}(x_4, y_2) + \mathrm{lo}(x_3, y_3) + \mathrm{lo}(x_2, y_4) \\\\ + &+ \qquad 2( \mathrm{hi}(x_4, y_1) + \mathrm{hi}(x_3, y_2) + \mathrm{hi}(x_2, y_3) + \mathrm{hi}(x_1, y_4) )\\\\ +z_7 &= \mathrm{lo}(x_4, y_3) + \mathrm{lo}(x_3, y_4) \\\\ + &+ \qquad 2( \mathrm{hi}(x_4, y_2) + \mathrm{hi}(x_3, y_3) + \mathrm{hi}(x_2, y_4) )\\\\ +z_8 &= \mathrm{lo}(x_4, y_4) \\\\ + &+ \qquad 2( \mathrm{hi}(x_4, y_3) + \mathrm{hi}(x_3, y_4) )\\\\ +z_9 &= 0 \\\\ + &+ \qquad 2( \mathrm{hi}(x_4, y_4) )\\\\ +\end{aligned} +\\] +As noted above, our strategy will be to multiply and accumulate the +terms with coefficient \\(2\\) separately from those with coefficient +\\(1\\), before combining them at the end. This can alternately be +thought of as accumulating product terms into a *doubly-redundant* +representation, with two limbs for each digit, before collapsing +the doubly-redundant representation by shifts and adds. + +This computation requires 25 `vpmadd52luq` and 25 `vpmadd52huq` +operations. For 256-bit vectors, IFMA operations execute on an +i3-8121U with latency 4 cycles, throughput 0.5 cycles, so executing 50 +instructions requires 25 cycles' worth of throughput. Accumulating +terms with coefficient \\(1\\) and \\(2\\) seperately means that the +longest dependency chain has length 5, so the critical path has length +20 cycles and the bottleneck is throughput. + +# Reduction modulo \\(p\\) + +The next question is how to handle the reduction modulo \\(p\\). +Because \\(p = 2^{255} - 19\\), \\(2^{255} = 19 \pmod p\\), so we can +alternately write +\\[ +\begin{aligned} +z &= z_0 + z_1 2^{51} + z_2 2^{102} + z_3 2^{153} + z_4 2^{204} \\\\ + &+ z_5 2^{255} + z_6 2^{306} + z_7 2^{357} + z_8 2^{408} + z_9 2^{459} +\end{aligned} +\\] +as +\\[ +\begin{aligned} +z &= (z_0 + 19z_5) + (z_1 + 19z_6) 2^{51} + (z_2 + 19z_7) 2^{102} + (z_3 + 19z_8) 2^{153} + (z_4 + 19z_9) 2^{204}. +\end{aligned} +\\] +When using a \\(64 \times 64 \rightarrow 128\\)-bit multiplier, this +can be handled (as in [Ed25519][ed25519_paper]) by premultiplying +source terms by \\(19\\). Since \\(\lg(19) < 4.25\\), this increases +their size by less than \\(4.25\\) bits, and the rest of the +multiplication can be shown to work out. + +Here, we have at most \\(1\\) bit of headroom. In order to allow +premultiplication, we would need to use radix \\(2^{47}\\), which +would require six limbs instead of five. Instead, we compute the high +terms \\(z_5, \ldots, z_9\\), each using two chains of IFMA +operations, then multiply by \\(19\\) and combine with the lower terms +\\(z_0, \ldots, z_4\\). There are two ways to perform the +multiplication by \\(19\\): using more IFMA operations, or using the +`vpmullq` instruction, which computes the low \\(64\\) bits of a \\(64 +\times 64\\)-bit product. However, `vpmullq` has 15c/1.5c +latency/throughput, in contrast to the 4c/0.5c latency/throughput of +IFMA operations, so it seems like a worse choice. + +The high terms \\(z_5, \ldots, z_9\\) are sums of \\(52\\)-bit terms, +so they are larger than \\(52\\) bits. Write these terms in radix \\(52\\) as +\\[ +z_{5+i} = z_{5+i}' + z_{5+i}'' 2^{52}, \qquad z_{5+i}' < 2^{52}. +\\] +Then the contribution of \\(z_{5+i}\\), taken modulo \\(p\\), is +\\[ +\begin{aligned} +z_{5+i} 2^{255} 2^{51 i} +&= +19 (z_{5+i}' + z_{5+i}'' 2^{52}) 2^{51 i} +\\\\ +&= +19 z_{5+i}' 2^{51 i} + 2 \cdot 19 z_{5+i}'' 2^{51 (i+1)} +\\\\ +\end{aligned} +\\] +The products \\(19 z_{5+i}', 19 z_{5+i}''\\) can be written in terms of IFMA operations as +\\[ +\begin{aligned} +19 z_{5+i}' &= \mathrm{lo}(19, z_{5+i}') + 2 \mathrm{hi}(19, z_{5+i}') 2^{51}, \\\\ +19 z_{5+i}'' &= \mathrm{lo}(19, z_{5+i}'') + 2 \mathrm{hi}(19, z_{5+i}'') 2^{51}. \\\\ +\end{aligned} +\\] +Because \\(z_{5+i} < 2^{64}\\), \\(z_{5+i}'' < 2^{12} \\), so \\(19 +z_{5+i}'' < 2^{17} < 2^{52} \\) and \\(\mathrm{hi}(19, z_{5+i}'') = 0\\). +Because IFMA operations ignore the high bits of their source +operands, we do not need to compute \\(z\_{5+i}'\\) explicitly: +the high bits will be ignored. +Combining these observations, we can write +\\[ +\begin{aligned} +z_{5+i} 2^{255} 2^{51 i} +&= +19 z_{5+i}' 2^{51 i} + 2 \cdot 19 z_{5+i}'' 2^{51 (i+1)} +\\\\ +&= +\mathrm{lo}(19, z_{5+i}) 2^{51 i} +\+ 2 \mathrm{hi}(19, z_{5+i}) 2^{51 (i+1)} +\+ 2 \mathrm{lo}(19, z_{5+i}/2^{52}) 2^{51 (i+1)}. +\end{aligned} +\\] + +For \\(i = 0,1,2,3\\), this allows reducing \\(z_{5+i}\\) onto +\\(z_{i}, z_{i+1}\\), and if the low terms are computed using a +doubly-redundant representation, no additional shifts are needed to +handle the \\(2\\) coefficients. For \\(i = 4\\), there's a +complication: the contribution becomes +\\[ +\begin{aligned} +z_{9} 2^{255} 2^{204} +&= +\mathrm{lo}(19, z_{9}) 2^{204} +\+ 2 \mathrm{hi}(19, z_{9}) 2^{255} +\+ 2 \mathrm{lo}(19, z_{9}/2^{52}) 2^{255} +\\\\ +&= +\mathrm{lo}(19, z_{9}) 2^{204} +\+ 2 \mathrm{hi}(19, z_{9}) 19 +\+ 2 \mathrm{lo}(19, z_{9}/2^{52}) 19 +\\\\ +&= +\mathrm{lo}(19, z_{9}) 2^{204} +\+ 2 +\mathrm{lo}(19, \mathrm{hi}(19, z_{9}) + \mathrm{lo}(19, z_{9}/2^{52})). +\\\\ +\end{aligned} +\\] + +It would be possible to cut the number of multiplications from 3 to 2 +by carrying the high part of each \\(z_i\\) onto \\(z_{i+1}\\). This +would eliminate 5 multiplications, clearing 2.5 cycles of port +pressure, at the cost of 5 additions, adding 1.66 cycles of port +pressure. But doing this would create a dependency between terms +(e.g., \\(z_{5}\\) must be computed before the reduction of +\\(z_{6}\\) can begin), whereas with the approach above, all +contributions to all terms are computed independently, to maximize ILP +and flexibility for the processor to schedule instructions. + +This strategy performs 16 IFMA operations, adding two IFMA operations +to each of the \\(2\\)-coefficient terms and one to each of the +\\(1\\)-coefficient terms. Considering the multiplication and +reduction together, we use 66 IFMA operations, requiring 33 cycles' +throughput, while the longest chain of IFMA operations is in the +reduction of \\(z_5\\) onto \\(z_1\\), of length 7 (so 28 cycles, plus +2 cycles to combine the two parts of \\(z_5\\), and the bottleneck is +again throughput. + +Once this is done, we have computed the product terms +\\[ +z = z_0 + z_1 2^{51} + z_2 2^{102} + z_3 2^{153} + z_4 2^{204}, +\\] +without reducing the \\(z_i\\) to fit in \\(52\\) bits. Because the +overall flow of operations alternates multiplications and additions or +subtractions, we would have to perform a reduction after an addition +but before the next multiplication anyways, so there's no benefit to +fully reducing the limbs at the end of a multiplication. Instead, we +leave them unreduced, and track the reduction state using the type +system to ensure that unreduced limbs are not accidentally used as an +input to a multiplication. + +# Squaring + +Squaring operates similarly to multiplication, but with the +possibility to combine identical terms. +As before, we write the input as +\\[ +\begin{aligned} +x &= x_0 + x_1 2^{51} + x_2 2^{102} + x_3 2^{153} + x_4 2^{204} +\end{aligned} +\\] +with limbs in range \\([0,2^{52})\\). +Writing the product terms as +\\[ +\begin{aligned} +z &= z_0 + z_1 2^{51} + z_2 2^{102} + z_3 2^{153} + z_4 2^{204} \\\\ + &+ z_5 2^{255} + z_6 2^{306} + z_7 2^{357} + z_8 2^{408} + z_9 2^{459}, +\end{aligned} +\\] +a schoolbook squaring in product scanning form takes the form +\\[ +\begin{aligned} +z_0 &= x_0 x_0 \\\\ +z_1 &= 2 x_1 x_0 \\\\ +z_2 &= 2 x_2 x_0 + x_1 x_1 \\\\ +z_3 &= 2 x_3 x_0 + 2 x_2 x_1 \\\\ +z_4 &= 2 x_4 x_0 + 2 x_3 x_1 + x_2 x_2 \\\\ +z_5 &= 2 x_4 x_1 + 2 x_3 x_2 \\\\ +z_6 &= 2 x_4 x_2 + x_3 x_3 \\\\ +z_7 &= 2 x_4 x_3 \\\\ +z_8 &= x_4 x_4 \\\\ +z_9 &= 0 \\\\ +\end{aligned} +\\] +As before, we write \\(x_i x_j\\) as +\\[ +x_i x_j = \mathrm{lo}(x_i,x_j) + 2\mathrm{hi}(x_i,x_j)2^{51}, +\\] +and substitute to obtain +\\[ +\begin{aligned} +z_0 &= \mathrm{lo}(x_0, x_0) + 0 \\\\ +z_1 &= 2 \mathrm{lo}(x_1, x_0) + 2 \mathrm{hi}(x_0, x_0) \\\\ +z_2 &= 2 \mathrm{lo}(x_2, x_0) + \mathrm{lo}(x_1, x_1) + 4 \mathrm{hi}(x_1, x_0) \\\\ +z_3 &= 2 \mathrm{lo}(x_3, x_0) + 2 \mathrm{lo}(x_2, x_1) + 4 \mathrm{hi}(x_2, x_0) + 2 \mathrm{hi}(x_1, x_1) \\\\ +z_4 &= 2 \mathrm{lo}(x_4, x_0) + 2 \mathrm{lo}(x_3, x_1) + \mathrm{lo}(x_2, x_2) + 4 \mathrm{hi}(x_3, x_0) + 4 \mathrm{hi}(x_2, x_1) \\\\ +z_5 &= 2 \mathrm{lo}(x_4, x_1) + 2 \mathrm{lo}(x_3, x_2) + 4 \mathrm{hi}(x_4, x_0) + 4 \mathrm{hi}(x_3, x_1) + 2 \mathrm{hi}(x_2, x_2) \\\\ +z_6 &= 2 \mathrm{lo}(x_4, x_2) + \mathrm{lo}(x_3, x_3) + 4 \mathrm{hi}(x_4, x_1) + 4 \mathrm{hi}(x_3, x_2) \\\\ +z_7 &= 2 \mathrm{lo}(x_4, x_3) + 4 \mathrm{hi}(x_4, x_2) + 2 \mathrm{hi}(x_3, x_3) \\\\ +z_8 &= \mathrm{lo}(x_4, x_4) + 4 \mathrm{hi}(x_4, x_3) \\\\ +z_9 &= 0 + 2 \mathrm{hi}(x_4, x_4) \\\\ +\end{aligned} +\\] +To implement these, we group terms by their coefficient, computing +those with coefficient \\(2\\) on set of IFMA chains, and on another +set of chains, we begin with coefficient-\\(4\\) terms, then shift +left before continuing with the coefficient-\\(1\\) terms. +The reduction strategy is the same as for multiplication. + +# Future improvements + +LLVM won't use blend operations on [256-bit vectors yet][llvm_blend], +so there's a bunch of blend instructions that could be omitted. + +Although the multiplications and squarings are much faster, there's no +speedup to the additions and subtractions, so there are diminishing +returns. In fact, the complications in the doubling formulas mean +that doubling is actually slower than readdition. This also suggests +that moving to 512-bit vectors won't be much help for a strategy aimed +at parallelism within a group operation, so to extract performance +gains from 512-bit vectors it will probably be necessary to create a +parallel-friendly multiscalar multiplication algorithm. This could +also help with reducing shuffle pressure. + +The squaring implementation could probably be optimized, but without +`perf` support on Cannonlake it's difficult to make actual +measurements. + +Another improvement would be to implement vectorized square root +computations, which would allow creating an iterator adaptor for point +decompression that bunched decompression operations and executed them +in parallel. This would accelerate batch verification. + +[2016_gueron_krasnov]: https://ieeexplore.ieee.org/document/7563269 +[2018_drucker_gueron]: https://eprint.iacr.org/2018/335 +[1999_walter]: https://pdfs.semanticscholar.org/0e6a/3e8f30b63b556679f5dff2cbfdfe9523f4fa.pdf +[ed25519_paper]: https://ed25519.cr.yp.to/ed25519-20110926.pdf +[llvm_blend]: https://bugs.llvm.org/show_bug.cgi?id=38343 diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/docs/parallel-formulas.md b/net/gurk-rs/files/vendor/curve25519-dalek/docs/parallel-formulas.md new file mode 100644 index 0000000..f84d1cc --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/docs/parallel-formulas.md @@ -0,0 +1,333 @@ +Vectorized implementations of field and point operations, using a +modification of the 4-way parallel formulas of Hisil, Wong, Carter, +and Dawson. + +These notes explain the parallel formulas and our strategy for using +them with SIMD operations. There are two backend implementations: one +using AVX2, and the other using AVX512-IFMA. + +# Overview + +The 2008 paper [_Twisted Edwards Curves Revisited_][hwcd08] by Hisil, +Wong, Carter, and Dawson (HWCD) introduced the “extended coordinates” +and mixed-model representations which are used by most Edwards curve +implementations. + +However, they also describe 4-way parallel formulas for point addition +and doubling: a unified addition algorithm taking an effective +\\(2\mathbf M + 1\mathbf D\\), a doubling algorithm taking an +effective \\(1\mathbf M + 1\mathbf S\\), and a dedicated (i.e., for +distinct points) addition algorithm taking an effective \\(2 \mathbf M +\\). They compare these formulas with a 2-way parallel variant of the +Montgomery ladder. + +Unlike their serial formulas, which are used widely, their parallel +formulas do not seem to have been implemented in software before. The +2-way parallel Montgomery ladder was used in 2015 by Tung Chou's +`sandy2x` implementation. Curiously, however, although the [`sandy2x` +paper][sandy2x] also implements Edwards arithmetic, and cites HWCD08, +it doesn't mention their parallel Edwards formulas. +A 2015 paper by Hernández and López describes an AVX2 implementation +of X25519. Neither the paper nor the code are publicly available, but +it apparently gives only a [slight speedup][avx2trac], suggesting that +it uses a 4-way parallel Montgomery ladder rather than parallel +Edwards formulas. + +The reason may be that HWCD08 describe their formulas as operating on +four independent processors, which would make a software +implementation impractical: all of the operations are too low-latency +to effectively synchronize. But a closer inspection reveals that the +(more expensive) multiplication and squaring steps are uniform, while +the instruction divergence occurs in the (much cheaper) addition and +subtraction steps. This means that a SIMD implementation can perform +the expensive steps uniformly, and handle divergence in the +inexpensive steps using masking. + +These notes describe modifications to the original parallel formulas +to allow a SIMD implementation, and this module contains +implementations of the modified formulas targeting either AVX2 or +AVX512-IFMA. + +# Parallel formulas in HWCD'08 + +The doubling formula is presented in the HWCD paper as follows: + +| Cost | Processor 1 | Processor 2 | Processor 3 | Processor 4 | +|------------------|--------------------------------|--------------------------------|--------------------------------|--------------------------------| +| | idle | idle | idle | \\( R\_1 \gets X\_1 + Y\_1 \\) | +| \\(1\mathbf S\\) | \\( R\_2 \gets X\_1\^2 \\) | \\( R\_3 \gets Y\_1\^2 \\) | \\( R\_4 \gets Z\_1\^2 \\) | \\( R\_5 \gets R\_1\^2 \\) | +| | \\( R\_6 \gets R\_2 + R\_3 \\) | \\( R\_7 \gets R\_2 - R\_3 \\) | \\( R\_4 \gets 2 R\_4 \\) | idle | +| | idle | \\( R\_1 \gets R\_4 + R\_7 \\) | idle | \\( R\_2 \gets R\_6 - R\_5 \\) | +| \\(1\mathbf M\\) | \\( X\_3 \gets R\_1 R\_2 \\) | \\( Y\_3 \gets R\_6 R\_7 \\) | \\( T\_3 \gets R\_2 R\_6 \\) | \\( Z\_3 \gets R\_1 R\_7 \\) | + +and the unified addition algorithm is presented as follows: + +| Cost | Processor 1 | Processor 2 | Processor 3 | Processor 4 | +|------------------|--------------------------------|--------------------------------|--------------------------------|--------------------------------| +| | \\( R\_1 \gets Y\_1 - X\_1 \\) | \\( R\_2 \gets Y\_2 - X\_2 \\) | \\( R\_3 \gets Y\_1 + X\_1 \\) | \\( R\_4 \gets Y\_2 + X\_2 \\) | +| \\(1\mathbf M\\) | \\( R\_5 \gets R\_1 R\_2 \\) | \\( R\_6 \gets R\_3 R\_4 \\) | \\( R\_7 \gets T\_1 T\_2 \\) | \\( R\_8 \gets Z\_1 Z\_2 \\) | +| \\(1\mathbf D\\) | idle | idle | \\( R\_7 \gets k R\_7 \\) | \\( R\_8 \gets 2 R\_8 \\) | +| | \\( R\_1 \gets R\_6 - R\_5 \\) | \\( R\_2 \gets R\_8 - R\_7 \\) | \\( R\_3 \gets R\_8 + R\_7 \\) | \\( R\_4 \gets R\_6 + R\_5 \\) | +| \\(1\mathbf M\\) | \\( X\_3 \gets R\_1 R\_2 \\) | \\( Y\_3 \gets R\_3 R\_4 \\) | \\( T\_3 \gets R\_1 R\_4 \\) | \\( Z\_3 \gets R\_2 R\_3 \\) | + +Here \\(\mathbf M\\) and \\(\mathbf S\\) represent the cost of +multiplication and squaring of generic field elements, \\(\mathbf D\\) +represents the cost of multiplication by a curve constant (in this +case \\( k = 2d \\)). + +Notice that the \\(1\mathbf M\\) and \\(1\mathbf S\\) steps are +uniform. The non-uniform steps are all inexpensive additions or +subtractions, with the exception of the multiplication by the curve +constant \\(k = 2d\\): +$$ +R\_7 \gets 2 d R\_7. +$$ + +HWCD suggest parallelising this step by breaking \\(k = 2d\\) into four +parts as \\(k = k_0 + 2\^n k_1 + 2\^{2n} k_2 + 2\^{3n} k_3 \\) and +computing \\(k_i R_7 \\) in parallel. This is quite awkward, but if +the curve constant is a ratio \\( d = d\_1/d\_2 \\), then projective +coordinates allow us to instead compute +$$ +(R\_5, R\_6, R\_7, R\_8) \gets (d\_2 R\_5, d\_2 R\_6, 2d\_1 R\_7, d\_2 R\_8). +$$ +This can be performed as a uniform multiplication by a vector of +constants, and if \\(d\_1, d\_2\\) are small, it is relatively +inexpensive. (This trick was suggested by Mike Hamburg). +In the Curve25519 case, we have +$$ +d = \frac{d\_1}{d\_2} = \frac{-121665}{121666}; +$$ +Since \\(2 \cdot 121666 < 2\^{18}\\), all the constants above fit (up +to sign) in 32 bits, so this can be done in parallel as four +multiplications by small constants \\( (121666, 121666, 2\cdot 121665, +2\cdot 121666) \\), followed by a negation to compute \\( - 2\cdot 121665\\). + +# Modified parallel formulas + +Using the modifications sketched above, we can write SIMD-friendly +versions of the parallel formulas as follows. To avoid confusion with +the original formulas, temporary variables are named \\(S\\) instead +of \\(R\\) and are in static single-assignment form. + +## Addition + +To add points +\\(P_1 = (X_1 : Y_1 : Z_1 : T_1) \\) +and +\\(P_2 = (X_2 : Y_2 : Z_2 : T_2 ) \\), +we compute +$$ +\begin{aligned} +(S\_0 &&,&& S\_1 &&,&& S\_2 &&,&& S\_3 ) +&\gets +(Y\_1 - X\_1&&,&& Y\_1 + X\_1&&,&& Y\_2 - X\_2&&,&& Y\_2 + X\_2) +\\\\ +(S\_4 &&,&& S\_5 &&,&& S\_6 &&,&& S\_7 ) +&\gets +(S\_0 \cdot S\_2&&,&& S\_1 \cdot S\_3&&,&& Z\_1 \cdot Z\_2&&,&& T\_1 \cdot T\_2) +\\\\ +(S\_8 &&,&& S\_9 &&,&& S\_{10} &&,&& S\_{11} ) +&\gets +(d\_2 \cdot S\_4 &&,&& d\_2 \cdot S\_5 &&,&& 2 d\_2 \cdot S\_6 &&,&& 2 d\_1 \cdot S\_7 ) +\\\\ +(S\_{12} &&,&& S\_{13} &&,&& S\_{14} &&,&& S\_{15}) +&\gets +(S\_9 - S\_8&&,&& S\_9 + S\_8&&,&& S\_{10} - S\_{11}&&,&& S\_{10} + S\_{11}) +\\\\ +(X\_3&&,&& Y\_3&&,&& Z\_3&&,&& T\_3) +&\gets +(S\_{12} \cdot S\_{14}&&,&& S\_{15} \cdot S\_{13}&&,&& S\_{15} \cdot S\_{14}&&,&& S\_{12} \cdot S\_{13}) +\end{aligned} +$$ +to obtain \\( P\_3 = (X\_3 : Y\_3 : Z\_3 : T\_3) = P\_1 + P\_2 \\). +This costs \\( 2\mathbf M + 1 \mathbf D\\). + +## Readdition + +If the point \\( P_2 = (X\_2 : Y\_2 : Z\_2 : T\_2) \\) is fixed, we +can cache the multiplication of the curve constants by computing +$$ +\begin{aligned} +(S\_2' &&,&& S\_3' &&,&& Z\_2' &&,&& T\_2' ) +&\gets +(d\_2 \cdot (Y\_2 - X\_2)&&,&& d\_2 \cdot (Y\_1 + X\_1)&&,&& 2d\_2 \cdot Z\_2 &&,&& 2d\_1 \cdot T\_2). +\end{aligned} +$$ +This costs \\( 1\mathbf D\\); with \\( (S\_2', S\_3', Z\_2', T\_2')\\) +in hand, the addition formulas above become +$$ +\begin{aligned} +(S\_0 &&,&& S\_1 &&,&& Z\_1 &&,&& T\_1 ) +&\gets +(Y\_1 - X\_1&&,&& Y\_1 + X\_1&&,&& Z\_1 &&,&& T\_1) +\\\\ +(S\_8 &&,&& S\_9 &&,&& S\_{10} &&,&& S\_{11} ) +&\gets +(S\_0 \cdot S\_2' &&,&& S\_1 \cdot S\_3'&&,&& Z\_1 \cdot Z\_2' &&,&& T\_1 \cdot T\_2') +\\\\ +(S\_{12} &&,&& S\_{13} &&,&& S\_{14} &&,&& S\_{15}) +&\gets +(S\_9 - S\_8&&,&& S\_9 + S\_8&&,&& S\_{10} - S\_{11}&&,&& S\_{10} + S\_{11}) +\\\\ +(X\_3&&,&& Y\_3&&,&& Z\_3&&,&& T\_3) +&\gets +(S\_{12} \cdot S\_{14}&&,&& S\_{15} \cdot S\_{13}&&,&& S\_{15} \cdot S\_{14}&&,&& S\_{12} \cdot S\_{13}) +\end{aligned} +$$ +which costs only \\( 2\mathbf M \\). This precomputation is +essentially similar to the precomputation that HWCD suggest for their +serial formulas. Because the cost of precomputation and then +readdition is the same as addition, it's sufficient to only +implement caching and readdition. + +## Doubling + +The non-uniform portions of the (re)addition formulas have a fairly +regular structure. Unfortunately, this is not the case for the +doubling formulas, which are much less nice. + +To double a point \\( P = (X\_1 : Y\_1 : Z\_1 : T\_1) \\), we compute +$$ +\begin{aligned} +(X\_1 &&,&& Y\_1 &&,&& Z\_1 &&,&& S\_0) +&\gets +(X\_1 &&,&& Y\_1 &&,&& Z\_1 &&,&& X\_1 + Y\_1) +\\\\ +(S\_1 &&,&& S\_2 &&,&& S\_3 &&,&& S\_4 ) +&\gets +(X\_1\^2 &&,&& Y\_1\^2&&,&& Z\_1\^2 &&,&& S\_0\^2) +\\\\ +(S\_5 &&,&& S\_6 &&,&& S\_8 &&,&& S\_9 ) +&\gets +(S\_1 + S\_2 &&,&& S\_1 - S\_2 &&,&& S\_1 + 2S\_3 - S\_2 &&,&& S\_1 + S\_2 - S\_4) +\\\\ +(X\_3 &&,&& Y\_3 &&,&& Z\_3 &&,&& T\_3 ) +&\gets +(S\_8 \cdot S\_9 &&,&& S\_5 \cdot S\_6 &&,&& S\_8 \cdot S\_6 &&,&& S\_5 \cdot S\_9) +\end{aligned} +$$ +to obtain \\( P\_3 = (X\_3 : Y\_3 : Z\_3 : T\_3) = [2]P\_1 \\). + +The intermediate step between the squaring and multiplication requires +a long chain of additions. For the IFMA-based implementation, this is not a problem; for the AVX2-based implementation, it is, but with some care and finesse, it's possible to arrange the computation without requiring an intermediate reduction. + +# Implementation + +These formulas aren't specific to a particular representation of field +element vectors, whose optimum choice is determined by the details of +the instruction set. However, it's not possible to perfectly separate +the implementation of the field element vectors from the +implementation of the point operations. Instead, the [`avx2`] and +[`ifma`] backends provide `ExtendedPoint` and `CachedPoint` types, and +the [`scalar_mul`] code uses one of the backend types by a type alias. + +# Comparison to non-vectorized formulas + +In theory, the parallel Edwards formulas seem to allow a \\(4\\)-way +speedup from parallelism. However, an actual vectorized +implementation has several slowdowns that cut into this speedup. + +First, the parallel formulas can only use the available vector +multiplier. For AVX2, this is a \\( 32 \times 32 \rightarrow 64 +\\)-bit integer multiplier, so the speedup from vectorization must +overcome the disadvantage of losing the \\( 64 \times 64 \rightarrow +128\\)-bit (serial) integer multiplier. The effect of this slowdown +is microarchitecture-dependent, since it requires accounting for the +total number of multiplications and additions and their relative +costs. IFMA allows using a \\( 52 \times 52 \rightarrow 104 \\)-bit +multiplier, but the high and low halves need to be computed +separately, and the reduction requires extra work because it's not +possible to pre-multiply by \\(19\\). + +Second, the parallel doubling formulas incur both a theoretical and +practical slowdown. The parallel formulas described above work on the +\\( \mathbb P\^3 \\) “extended” coordinates. The \\( \mathbb P\^2 \\) +model introduced earlier by [Bernstein, Birkner, Joye, Lange, and +Peters][bbjlp08] allows slightly faster doublings, so HWCD suggest +mixing coordinate systems while performing scalar multiplication +(attributing the idea to [a 1998 paper][cmo98] by Cohen, Miyagi, and +Ono). The \\( T \\) coordinate is not required for doublings, so when +doublings are followed by doublings, its computation can be skipped. +More details on this approach and the different coordinate systems can +be found in the [`curve_models` module documentation][curve_models]. + +Unfortunately, this optimization is not compatible with the parallel +formulas, which cannot save time by skipping a single variable, so the +parallel doubling formulas do slightly more work when counting the +total number of field multiplications and squarings. + +In addition, the parallel doubling formulas have a less regular +pattern of additions and subtractions than the parallel addition +formulas, so the vectorization overhead is proportionately greater. +Both the parallel addition and parallel doubling formulas also require +some shuffling to rearrange data within the vectors, which places more +pressure on the shuffle unit than is desirable. + +This means that the speedup from using a vectorized implementation of +parallel Edwards formulas is likely to be greatest in applications +that do fewer doublings and more additions (like a large multiscalar +multiplication) rather than applications that do fewer additions and +more doublings (like a double-base scalar multiplication). + +Third, Amdahl's law says that the speedup is limited to the portion +which can be parallelized. Normally, the field multiplications +dominate the cost of point operations, but with the IFMA backend, the +multiplications are so fast that the non-parallel additions end up as +a significant portion of the total time. + +Fourth, current Intel CPUs perform thermal throttling when using wide +vector instructions. A detailed description can be found in §15.26 of +[the Intel Optimization Manual][intel], but using wide vector +instructions prevents the core from operating at higher frequencies. +The core can return to the higher-frequency state after 2 +milliseconds, but this timer is reset every time high-power +instructions are used. + +Any speedup from vectorization therefore has to be weighed against a +slowdown for the next few million instructions. For a mixed workload, +where point operations are interspersed with other tasks, this can +reduce overall performance. This implementation is therefore probably +not suitable for basic applications, like signatures, but is +worthwhile for complex applications, like zero-knowledge proofs, which +do sustained work. + +# Future work + +There are several directions for future improvement: + +* Using the vectorized field arithmetic code to parallelize across + point operations rather than within a single point operation. This + is less flexible, but would give a speedup both from allowing use of + the faster mixed-model arithmetic and from reducing shuffle + pressure. One approach in this direction would be to implement + batched scalar-point operations using vectors of points (AoSoA + layout). This less generally useful but would give a speedup for + Bulletproofs. + +* Extending the IFMA implementation to use the full width of AVX512, + either handling the extra parallelism internally to a single point + operation (by using a 2-way parallel implementation of field + arithmetic instead of a wordsliced one), or externally, + parallelizing across point operations. Internal parallelism would + be preferable but might require too much shuffle pressure. For now, + the only available CPU which runs IFMA operations executes them at + 256-bits wide anyways, so this isn't yet important. + +* Generalizing the implementation to NEON instructions. The current + point arithmetic code is written in terms of field element vectors, + which are in turn implemented using platform SIMD vectors. It + should be possible to write an alternate implementation of the + `FieldElement2625x4` using NEON without changing the point + arithmetic. NEON has 128-bit vectors rather than 256-bit vectors, + but this may still be worthwhile compared to a serial + implementation. + + +[sandy2x]: https://eprint.iacr.org/2015/943.pdf +[avx2trac]: https://trac.torproject.org/projects/tor/ticket/8897#comment:28 +[hwcd08]: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf +[curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/backend/serial/curve_models/index.html +[bbjlp08]: https://eprint.iacr.org/2008/013 +[cmo98]: https://link.springer.com/content/pdf/10.1007%2F3-540-49649-1_6.pdf +[intel]: https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/mod.rs new file mode 100644 index 0000000..18f8af7 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/mod.rs @@ -0,0 +1,65 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Pluggable implementations for different architectures. +//! +//! The backend code is split into two parts: a serial backend, +//! and a vector backend. +//! +//! The [`serial`] backend contains 32- and 64-bit implementations of +//! field arithmetic and scalar arithmetic, as well as implementations +//! of point operations using the mixed-model strategy (passing +//! between different curve models depending on the operation). +//! +//! The [`vector`] backend contains implementations of vectorized +//! field arithmetic, used to implement point operations using a novel +//! implementation strategy derived from parallel formulas of Hisil, +//! Wong, Carter, and Dawson. +//! +//! Because the two strategies give rise to different curve models, +//! it's not possible to reuse exactly the same scalar multiplication +//! code (or to write it generically), so both serial and vector +//! backends contain matching implementations of scalar multiplication +//! algorithms. These are intended to be selected by a `#[cfg]`-based +//! type alias. +//! +//! The [`vector`] backend is selected by the `simd_backend` cargo +//! feature; it uses the [`serial`] backend for non-vectorized operations. + +#[cfg(not(any( + feature = "u32_backend", + feature = "u64_backend", + feature = "fiat_u32_backend", + feature = "fiat_u64_backend", + feature = "simd_backend", +)))] +compile_error!( + "no curve25519-dalek backend cargo feature enabled! \ + please enable one of: u32_backend, u64_backend, fiat_u32_backend, fiat_u64_backend, simd_backend" +); + +pub mod serial; + +#[cfg(any( + all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") + ), + all(feature = "nightly", rustdoc) +))] +#[cfg_attr( + feature = "nightly", + doc(cfg(any(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") + )))) +)] +pub mod vector; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/curve_models/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/curve_models/mod.rs new file mode 100644 index 0000000..9d10d92 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/curve_models/mod.rs @@ -0,0 +1,551 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Internal curve representations which are not part of the public API. +//! +//! # Curve representations +//! +//! Internally, we use several different models for the curve. Here +//! is a sketch of the relationship between the models, following [a +//! post][smith-moderncrypto] +//! by Ben Smith on the `moderncrypto` mailing list. This is also briefly +//! discussed in section 2.5 of [_Montgomery curves and their +//! arithmetic_][costello-smith-2017] by Costello and Smith. +//! +//! Begin with the affine equation for the curve, +//! $$ +//! -x\^2 + y\^2 = 1 + dx\^2y\^2. +//! $$ +//! Next, pass to the projective closure \\(\mathbb P\^1 \times \mathbb +//! P\^1 \\) by setting \\(x=X/Z\\), \\(y=Y/T.\\) Clearing denominators +//! gives the model +//! $$ +//! -X\^2T\^2 + Y\^2Z\^2 = Z\^2T\^2 + dX\^2Y\^2. +//! $$ +//! In `curve25519-dalek`, this is represented as the `CompletedPoint` +//! struct. +//! To map from \\(\mathbb P\^1 \times \mathbb P\^1 \\), a product of +//! two lines, to \\(\mathbb P\^3\\), we use the [Segre +//! embedding](https://en.wikipedia.org/wiki/Segre_embedding) +//! $$ +//! \sigma : ((X:Z),(Y:T)) \mapsto (XY:XT:ZY:ZT). +//! $$ +//! Using coordinates \\( (W_0:W_1:W_2:W_3) \\) for \\(\mathbb P\^3\\), +//! the image \\(\sigma (\mathbb P\^1 \times \mathbb P\^1) \\) is the +//! surface defined by \\( W_0 W_3 = W_1 W_2 \\), and under \\( +//! \sigma\\), the equation above becomes +//! $$ +//! -W\_1\^2 + W\_2\^2 = W\_3\^2 + dW\_0\^2, +//! $$ +//! so that the curve is given by the pair of equations +//! $$ +//! \begin{aligned} +//! -W\_1\^2 + W\_2\^2 &= W\_3\^2 + dW\_0\^2, \\\\ W_0 W_3 &= W_1 W_2. +//! \end{aligned} +//! $$ +//! Up to variable naming, this is exactly the "extended" curve model +//! introduced in [_Twisted Edwards Curves +//! Revisited_][hisil-wong-carter-dawson-2008] by Hisil, Wong, Carter, +//! and Dawson. In `curve25519-dalek`, it is represented as the +//! `EdwardsPoint` struct. We can map from \\(\mathbb P\^3 \\) to +//! \\(\mathbb P\^2 \\) by sending \\( (W\_0:W\_1:W\_2:W\_3) \\) to \\( +//! (W\_1:W\_2:W\_3) \\). Notice that +//! $$ +//! \frac {W\_1} {W\_3} = \frac {XT} {ZT} = \frac X Z = x, +//! $$ +//! and +//! $$ +//! \frac {W\_2} {W\_3} = \frac {YZ} {ZT} = \frac Y T = y, +//! $$ +//! so this is the same as if we had started with the affine model +//! and passed to \\( \mathbb P\^2 \\) by setting \\( x = W\_1 / W\_3 +//! \\), \\(y = W\_2 / W\_3 \\). +//! Up to variable naming, this is the projective representation +//! introduced in in [_Twisted Edwards +//! Curves_][bernstein-birkner-joye-lange-peters-2008] by Bernstein, +//! Birkner, Joye, Lange, and Peters. In `curve25519-dalek`, it is +//! represented by the `ProjectivePoint` struct. +//! +//! # Passing between curve models +//! +//! Although the \\( \mathbb P\^3 \\) model provides faster addition +//! formulas, the \\( \mathbb P\^2 \\) model provides faster doubling +//! formulas. Hisil, Wong, Carter, and Dawson therefore suggest mixing +//! coordinate systems for scalar multiplication, attributing the idea +//! to [a 1998 paper][cohen-miyaji-ono-1998] of Cohen, Miyagi, and Ono. +//! +//! Their suggestion is to vary the formulas used by context, using a +//! \\( \mathbb P\^2 \rightarrow \mathbb P\^2 \\) doubling formula when +//! a doubling is followed +//! by another doubling, a \\( \mathbb P\^2 \rightarrow \mathbb P\^3 \\) +//! doubling formula when a doubling is followed by an addition, and +//! computing point additions using a \\( \mathbb P\^3 \times \mathbb P\^3 +//! \rightarrow \mathbb P\^2 \\) formula. +//! +//! The `ref10` reference implementation of [Ed25519][ed25519], by +//! Bernstein, Duif, Lange, Schwabe, and Yang, tweaks +//! this strategy, factoring the addition formulas through the +//! completion \\( \mathbb P\^1 \times \mathbb P\^1 \\), so that the +//! output of an addition or doubling always lies in \\( \mathbb P\^1 \times +//! \mathbb P\^1\\), and the choice of which formula to use is replaced +//! by a choice of whether to convert the result to \\( \mathbb P\^2 \\) +//! or \\(\mathbb P\^3 \\). However, this tweak is not described in +//! their paper, only in their software. +//! +//! Our naming for the `CompletedPoint` (\\(\mathbb P\^1 \times \mathbb +//! P\^1 \\)), `ProjectivePoint` (\\(\mathbb P\^2 \\)), and +//! `EdwardsPoint` (\\(\mathbb P\^3 \\)) structs follows the naming in +//! Adam Langley's [Golang ed25519][agl-ed25519] implementation, which +//! `curve25519-dalek` was originally derived from. +//! +//! Finally, to accelerate readditions, we use two cached point formats +//! in "Niels coordinates", named for Niels Duif, +//! one for the affine model and one for the \\( \mathbb P\^3 \\) model: +//! +//! * `AffineNielsPoint`: \\( (y+x, y-x, 2dxy) \\) +//! * `ProjectiveNielsPoint`: \\( (Y+X, Y-X, Z, 2dXY) \\) +//! +//! [smith-moderncrypto]: https://moderncrypto.org/mail-archive/curves/2016/000807.html +//! [costello-smith-2017]: https://eprint.iacr.org/2017/212 +//! [hisil-wong-carter-dawson-2008]: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf +//! [bernstein-birkner-joye-lange-peters-2008]: https://eprint.iacr.org/2008/013 +//! [cohen-miyaji-ono-1998]: https://link.springer.com/content/pdf/10.1007%2F3-540-49649-1_6.pdf +//! [ed25519]: https://eprint.iacr.org/2011/368 +//! [agl-ed25519]: https://github.com/agl/ed25519 + +#![allow(non_snake_case)] + +use core::fmt::Debug; +use core::ops::{Add, Neg, Sub}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use zeroize::Zeroize; + +use constants; + +use edwards::EdwardsPoint; +use field::FieldElement; +use traits::ValidityCheck; + +// ------------------------------------------------------------------------ +// Internal point representations +// ------------------------------------------------------------------------ + +/// A `ProjectivePoint` is a point \\((X:Y:Z)\\) on the \\(\mathbb +/// P\^2\\) model of the curve. +/// A point \\((x,y)\\) in the affine model corresponds to +/// \\((x:y:1)\\). +/// +/// More details on the relationships between the different curve models +/// can be found in the module-level documentation. +#[derive(Copy, Clone)] +pub struct ProjectivePoint { + pub X: FieldElement, + pub Y: FieldElement, + pub Z: FieldElement, +} + +/// A `CompletedPoint` is a point \\(((X:Z), (Y:T))\\) on the \\(\mathbb +/// P\^1 \times \mathbb P\^1 \\) model of the curve. +/// A point (x,y) in the affine model corresponds to \\( ((x:1),(y:1)) +/// \\). +/// +/// More details on the relationships between the different curve models +/// can be found in the module-level documentation. +#[derive(Copy, Clone)] +#[allow(missing_docs)] +pub struct CompletedPoint { + pub X: FieldElement, + pub Y: FieldElement, + pub Z: FieldElement, + pub T: FieldElement, +} + +/// A pre-computed point in the affine model for the curve, represented as +/// \\((y+x, y-x, 2dxy)\\) in "Niels coordinates". +/// +/// More details on the relationships between the different curve models +/// can be found in the module-level documentation. +// Safe to derive Eq because affine coordinates. +#[derive(Copy, Clone, Eq, PartialEq)] +#[allow(missing_docs)] +pub struct AffineNielsPoint { + pub y_plus_x: FieldElement, + pub y_minus_x: FieldElement, + pub xy2d: FieldElement, +} + +impl Zeroize for AffineNielsPoint { + fn zeroize(&mut self) { + self.y_plus_x.zeroize(); + self.y_minus_x.zeroize(); + self.xy2d.zeroize(); + } +} + +/// A pre-computed point on the \\( \mathbb P\^3 \\) model for the +/// curve, represented as \\((Y+X, Y-X, Z, 2dXY)\\) in "Niels coordinates". +/// +/// More details on the relationships between the different curve models +/// can be found in the module-level documentation. +#[derive(Copy, Clone)] +pub struct ProjectiveNielsPoint { + pub Y_plus_X: FieldElement, + pub Y_minus_X: FieldElement, + pub Z: FieldElement, + pub T2d: FieldElement, +} + +impl Zeroize for ProjectiveNielsPoint { + fn zeroize(&mut self) { + self.Y_plus_X.zeroize(); + self.Y_minus_X.zeroize(); + self.Z.zeroize(); + self.T2d.zeroize(); + } +} + +// ------------------------------------------------------------------------ +// Constructors +// ------------------------------------------------------------------------ + +use traits::Identity; + +impl Identity for ProjectivePoint { + fn identity() -> ProjectivePoint { + ProjectivePoint { + X: FieldElement::zero(), + Y: FieldElement::one(), + Z: FieldElement::one(), + } + } +} + +impl Identity for ProjectiveNielsPoint { + fn identity() -> ProjectiveNielsPoint { + ProjectiveNielsPoint{ + Y_plus_X: FieldElement::one(), + Y_minus_X: FieldElement::one(), + Z: FieldElement::one(), + T2d: FieldElement::zero(), + } + } +} + +impl Default for ProjectiveNielsPoint { + fn default() -> ProjectiveNielsPoint { + ProjectiveNielsPoint::identity() + } +} + +impl Identity for AffineNielsPoint { + fn identity() -> AffineNielsPoint { + AffineNielsPoint{ + y_plus_x: FieldElement::one(), + y_minus_x: FieldElement::one(), + xy2d: FieldElement::zero(), + } + } +} + +impl Default for AffineNielsPoint { + fn default() -> AffineNielsPoint { + AffineNielsPoint::identity() + } +} + +// ------------------------------------------------------------------------ +// Validity checks (for debugging, not CT) +// ------------------------------------------------------------------------ + +impl ValidityCheck for ProjectivePoint { + fn is_valid(&self) -> bool { + // Curve equation is -x^2 + y^2 = 1 + d*x^2*y^2, + // homogenized as (-X^2 + Y^2)*Z^2 = Z^4 + d*X^2*Y^2 + let XX = self.X.square(); + let YY = self.Y.square(); + let ZZ = self.Z.square(); + let ZZZZ = ZZ.square(); + let lhs = &(&YY - &XX) * &ZZ; + let rhs = &ZZZZ + &(&constants::EDWARDS_D * &(&XX * &YY)); + + lhs == rhs + } +} + +// ------------------------------------------------------------------------ +// Constant-time assignment +// ------------------------------------------------------------------------ + +impl ConditionallySelectable for ProjectiveNielsPoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + ProjectiveNielsPoint { + Y_plus_X: FieldElement::conditional_select(&a.Y_plus_X, &b.Y_plus_X, choice), + Y_minus_X: FieldElement::conditional_select(&a.Y_minus_X, &b.Y_minus_X, choice), + Z: FieldElement::conditional_select(&a.Z, &b.Z, choice), + T2d: FieldElement::conditional_select(&a.T2d, &b.T2d, choice), + } + } + + fn conditional_assign(&mut self, other: &Self, choice: Choice) { + self.Y_plus_X.conditional_assign(&other.Y_plus_X, choice); + self.Y_minus_X.conditional_assign(&other.Y_minus_X, choice); + self.Z.conditional_assign(&other.Z, choice); + self.T2d.conditional_assign(&other.T2d, choice); + } +} + +impl ConditionallySelectable for AffineNielsPoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + AffineNielsPoint { + y_plus_x: FieldElement::conditional_select(&a.y_plus_x, &b.y_plus_x, choice), + y_minus_x: FieldElement::conditional_select(&a.y_minus_x, &b.y_minus_x, choice), + xy2d: FieldElement::conditional_select(&a.xy2d, &b.xy2d, choice), + } + } + + fn conditional_assign(&mut self, other: &Self, choice: Choice) { + self.y_plus_x.conditional_assign(&other.y_plus_x, choice); + self.y_minus_x.conditional_assign(&other.y_minus_x, choice); + self.xy2d.conditional_assign(&other.xy2d, choice); + } +} + +// ------------------------------------------------------------------------ +// Point conversions +// ------------------------------------------------------------------------ + +impl ProjectivePoint { + /// Convert this point from the \\( \mathbb P\^2 \\) model to the + /// \\( \mathbb P\^3 \\) model. + /// + /// This costs \\(3 \mathrm M + 1 \mathrm S\\). + pub fn to_extended(&self) -> EdwardsPoint { + EdwardsPoint { + X: &self.X * &self.Z, + Y: &self.Y * &self.Z, + Z: self.Z.square(), + T: &self.X * &self.Y, + } + } +} + +impl CompletedPoint { + /// Convert this point from the \\( \mathbb P\^1 \times \mathbb P\^1 + /// \\) model to the \\( \mathbb P\^2 \\) model. + /// + /// This costs \\(3 \mathrm M \\). + pub fn to_projective(&self) -> ProjectivePoint { + ProjectivePoint { + X: &self.X * &self.T, + Y: &self.Y * &self.Z, + Z: &self.Z * &self.T, + } + } + + /// Convert this point from the \\( \mathbb P\^1 \times \mathbb P\^1 + /// \\) model to the \\( \mathbb P\^3 \\) model. + /// + /// This costs \\(4 \mathrm M \\). + pub fn to_extended(&self) -> EdwardsPoint { + EdwardsPoint { + X: &self.X * &self.T, + Y: &self.Y * &self.Z, + Z: &self.Z * &self.T, + T: &self.X * &self.Y, + } + } +} + +// ------------------------------------------------------------------------ +// Doubling +// ------------------------------------------------------------------------ + +impl ProjectivePoint { + /// Double this point: return self + self + pub fn double(&self) -> CompletedPoint { // Double() + let XX = self.X.square(); + let YY = self.Y.square(); + let ZZ2 = self.Z.square2(); + let X_plus_Y = &self.X + &self.Y; + let X_plus_Y_sq = X_plus_Y.square(); + let YY_plus_XX = &YY + &XX; + let YY_minus_XX = &YY - &XX; + + CompletedPoint{ + X: &X_plus_Y_sq - &YY_plus_XX, + Y: YY_plus_XX, + Z: YY_minus_XX, + T: &ZZ2 - &YY_minus_XX + } + } +} + +// ------------------------------------------------------------------------ +// Addition and Subtraction +// ------------------------------------------------------------------------ + +// XXX(hdevalence) These were doc(hidden) so they don't appear in the +// public API docs. +// However, that prevents them being used with --document-private-items, +// so comment out the doc(hidden) for now until this is resolved +// +// upstream rust issue: https://github.com/rust-lang/rust/issues/46380 +//#[doc(hidden)] +impl<'a, 'b> Add<&'b ProjectiveNielsPoint> for &'a EdwardsPoint { + type Output = CompletedPoint; + + fn add(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint { + let Y_plus_X = &self.Y + &self.X; + let Y_minus_X = &self.Y - &self.X; + let PP = &Y_plus_X * &other.Y_plus_X; + let MM = &Y_minus_X * &other.Y_minus_X; + let TT2d = &self.T * &other.T2d; + let ZZ = &self.Z * &other.Z; + let ZZ2 = &ZZ + &ZZ; + + CompletedPoint{ + X: &PP - &MM, + Y: &PP + &MM, + Z: &ZZ2 + &TT2d, + T: &ZZ2 - &TT2d + } + } +} + +//#[doc(hidden)] +impl<'a, 'b> Sub<&'b ProjectiveNielsPoint> for &'a EdwardsPoint { + type Output = CompletedPoint; + + fn sub(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint { + let Y_plus_X = &self.Y + &self.X; + let Y_minus_X = &self.Y - &self.X; + let PM = &Y_plus_X * &other.Y_minus_X; + let MP = &Y_minus_X * &other.Y_plus_X; + let TT2d = &self.T * &other.T2d; + let ZZ = &self.Z * &other.Z; + let ZZ2 = &ZZ + &ZZ; + + CompletedPoint{ + X: &PM - &MP, + Y: &PM + &MP, + Z: &ZZ2 - &TT2d, + T: &ZZ2 + &TT2d + } + } +} + +//#[doc(hidden)] +impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a EdwardsPoint { + type Output = CompletedPoint; + + fn add(self, other: &'b AffineNielsPoint) -> CompletedPoint { + let Y_plus_X = &self.Y + &self.X; + let Y_minus_X = &self.Y - &self.X; + let PP = &Y_plus_X * &other.y_plus_x; + let MM = &Y_minus_X * &other.y_minus_x; + let Txy2d = &self.T * &other.xy2d; + let Z2 = &self.Z + &self.Z; + + CompletedPoint{ + X: &PP - &MM, + Y: &PP + &MM, + Z: &Z2 + &Txy2d, + T: &Z2 - &Txy2d + } + } +} + +//#[doc(hidden)] +impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a EdwardsPoint { + type Output = CompletedPoint; + + fn sub(self, other: &'b AffineNielsPoint) -> CompletedPoint { + let Y_plus_X = &self.Y + &self.X; + let Y_minus_X = &self.Y - &self.X; + let PM = &Y_plus_X * &other.y_minus_x; + let MP = &Y_minus_X * &other.y_plus_x; + let Txy2d = &self.T * &other.xy2d; + let Z2 = &self.Z + &self.Z; + + CompletedPoint{ + X: &PM - &MP, + Y: &PM + &MP, + Z: &Z2 - &Txy2d, + T: &Z2 + &Txy2d + } + } +} + +// ------------------------------------------------------------------------ +// Negation +// ------------------------------------------------------------------------ + +impl<'a> Neg for &'a ProjectiveNielsPoint { + type Output = ProjectiveNielsPoint; + + fn neg(self) -> ProjectiveNielsPoint { + ProjectiveNielsPoint{ + Y_plus_X: self.Y_minus_X, + Y_minus_X: self.Y_plus_X, + Z: self.Z, + T2d: -(&self.T2d), + } + } +} + +impl<'a> Neg for &'a AffineNielsPoint { + type Output = AffineNielsPoint; + + fn neg(self) -> AffineNielsPoint { + AffineNielsPoint{ + y_plus_x: self.y_minus_x, + y_minus_x: self.y_plus_x, + xy2d: -(&self.xy2d) + } + } +} + +// ------------------------------------------------------------------------ +// Debug traits +// ------------------------------------------------------------------------ + +impl Debug for ProjectivePoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "ProjectivePoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?}\n}}", + &self.X, &self.Y, &self.Z) + } +} + +impl Debug for CompletedPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "CompletedPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", + &self.X, &self.Y, &self.Z, &self.T) + } +} + +impl Debug for AffineNielsPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "AffineNielsPoint{{\n\ty_plus_x: {:?},\n\ty_minus_x: {:?},\n\txy2d: {:?}\n}}", + &self.y_plus_x, &self.y_minus_x, &self.xy2d) + } +} + +impl Debug for ProjectiveNielsPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "ProjectiveNielsPoint{{\n\tY_plus_X: {:?},\n\tY_minus_X: {:?},\n\tZ: {:?},\n\tT2d: {:?}\n}}", + &self.Y_plus_X, &self.Y_minus_X, &self.Z, &self.T2d) + } +} + + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u32/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u32/field.rs new file mode 100644 index 0000000..2864c95 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u32/field.rs @@ -0,0 +1,260 @@ +// -*- mode: rust; coding: utf-8; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(32\\)-bit +//! limbs with \\(64\\)-bit products. +//! +//! This code was originally derived from Adam Langley's Golang ed25519 +//! implementation, and was then rewritten to use unsigned limbs instead +//! of signed limbs. +//! +//! This uses the formally-verified field arithmetic generated by the +//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto) + +use core::fmt::Debug; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Sub, SubAssign}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use zeroize::Zeroize; + +use fiat_crypto::curve25519_32::*; + +/// A `FieldElement2625` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// In the 32-bit implementation, a `FieldElement` is represented in +/// radix \\(2\^{25.5}\\) as ten `u32`s. This means that a field +/// element \\(x\\) is represented as +/// $$ +/// x = \sum\_{i=0}\^9 x\_i 2\^{\lceil i \frac {51} 2 \rceil} +/// = x\_0 + x\_1 2\^{26} + x\_2 2\^{51} + x\_3 2\^{77} + \cdots + x\_9 2\^{230}; +/// $$ +/// the coefficients are alternately bounded by \\(2\^{25}\\) and +/// \\(2\^{26}\\). The limbs are allowed to grow between reductions up +/// to \\(2\^{25+b}\\) or \\(2\^{26+b}\\), where \\(b = 1.75\\). +/// +/// # Note +/// +/// The `curve25519_dalek::field` module provides a type alias +/// `curve25519_dalek::field::FieldElement` to either `FieldElement51` +/// or `FieldElement2625`. +/// +/// The backend-specific type `FieldElement2625` should not be used +/// outside of the `curve25519_dalek::field` module. +#[derive(Copy, Clone)] +pub struct FieldElement2625(pub(crate) [u32; 10]); + +impl Debug for FieldElement2625 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "FieldElement2625({:?})", &self.0[..]) + } +} + +impl Zeroize for FieldElement2625 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl<'b> AddAssign<&'b FieldElement2625> for FieldElement2625 { + fn add_assign(&mut self, _rhs: &'b FieldElement2625) { + let input = self.0; + fiat_25519_add(&mut self.0, &input, &_rhs.0); + let input = self.0; + fiat_25519_carry(&mut self.0, &input); + } +} + +impl<'a, 'b> Add<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn add(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut output = *self; + fiat_25519_add(&mut output.0, &self.0, &_rhs.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl<'b> SubAssign<&'b FieldElement2625> for FieldElement2625 { + fn sub_assign(&mut self, _rhs: &'b FieldElement2625) { + let input = self.0; + fiat_25519_sub(&mut self.0, &input, &_rhs.0); + let input = self.0; + fiat_25519_carry(&mut self.0, &input); + } +} + +impl<'a, 'b> Sub<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn sub(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut output = *self; + fiat_25519_sub(&mut output.0, &self.0, &_rhs.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl<'b> MulAssign<&'b FieldElement2625> for FieldElement2625 { + fn mul_assign(&mut self, _rhs: &'b FieldElement2625) { + let input = self.0; + fiat_25519_carry_mul(&mut self.0, &input, &_rhs.0); + } +} + +impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn mul(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut output = *self; + fiat_25519_carry_mul(&mut output.0, &self.0, &_rhs.0); + output + } +} + +impl<'a> Neg for &'a FieldElement2625 { + type Output = FieldElement2625; + fn neg(self) -> FieldElement2625 { + let mut output = *self; + fiat_25519_opp(&mut output.0, &self.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl ConditionallySelectable for FieldElement2625 { + fn conditional_select( + a: &FieldElement2625, + b: &FieldElement2625, + choice: Choice, + ) -> FieldElement2625 { + let mut output = [0u32; 10]; + fiat_25519_selectznz(&mut output, choice.unwrap_u8() as fiat_25519_u1, &a.0, &b.0); + FieldElement2625(output) + } + + fn conditional_assign(&mut self, other: &FieldElement2625, choice: Choice) { + let mut output = [0u32; 10]; + let choicebit = choice.unwrap_u8() as fiat_25519_u1; + fiat_25519_cmovznz_u32(&mut output[0], choicebit, self.0[0], other.0[0]); + fiat_25519_cmovznz_u32(&mut output[1], choicebit, self.0[1], other.0[1]); + fiat_25519_cmovznz_u32(&mut output[2], choicebit, self.0[2], other.0[2]); + fiat_25519_cmovznz_u32(&mut output[3], choicebit, self.0[3], other.0[3]); + fiat_25519_cmovznz_u32(&mut output[4], choicebit, self.0[4], other.0[4]); + fiat_25519_cmovznz_u32(&mut output[5], choicebit, self.0[5], other.0[5]); + fiat_25519_cmovznz_u32(&mut output[6], choicebit, self.0[6], other.0[6]); + fiat_25519_cmovznz_u32(&mut output[7], choicebit, self.0[7], other.0[7]); + fiat_25519_cmovznz_u32(&mut output[8], choicebit, self.0[8], other.0[8]); + fiat_25519_cmovznz_u32(&mut output[9], choicebit, self.0[9], other.0[9]); + *self = FieldElement2625(output); + } + + fn conditional_swap(a: &mut FieldElement2625, b: &mut FieldElement2625, choice: Choice) { + u32::conditional_swap(&mut a.0[0], &mut b.0[0], choice); + u32::conditional_swap(&mut a.0[1], &mut b.0[1], choice); + u32::conditional_swap(&mut a.0[2], &mut b.0[2], choice); + u32::conditional_swap(&mut a.0[3], &mut b.0[3], choice); + u32::conditional_swap(&mut a.0[4], &mut b.0[4], choice); + u32::conditional_swap(&mut a.0[5], &mut b.0[5], choice); + u32::conditional_swap(&mut a.0[6], &mut b.0[6], choice); + u32::conditional_swap(&mut a.0[7], &mut b.0[7], choice); + u32::conditional_swap(&mut a.0[8], &mut b.0[8], choice); + u32::conditional_swap(&mut a.0[9], &mut b.0[9], choice); + } +} + +impl FieldElement2625 { + /// Invert the sign of this field element + pub fn negate(&mut self) { + let neg = self.neg(); + self.0 = neg.0; + } + + /// Construct zero. + pub fn zero() -> FieldElement2625 { + FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + } + + /// Construct one. + pub fn one() -> FieldElement2625 { + FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + } + + /// Construct -1. + pub fn minus_one() -> FieldElement2625 { + FieldElement2625([ + 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, + 0x3ffffff, 0x1ffffff, + ]) + } + + /// Given `k > 0`, return `self^(2^k)`. + pub fn pow2k(&self, k: u32) -> FieldElement2625 { + debug_assert!(k > 0); + let mut z = self.square(); + for _ in 1..k { + z = z.square(); + } + z + } + + /// Load a `FieldElement2625` from the low 255 bits of a 256-bit + /// input. + /// + /// # Warning + /// + /// This function does not check that the input used the canonical + /// representative. It masks the high bit, but it will happily + /// decode 2^255 - 18 to 1. Applications that require a canonical + /// encoding of every field element should decode, re-encode to + /// the canonical encoding, and check that the input was + /// canonical. + pub fn from_bytes(data: &[u8; 32]) -> FieldElement2625 { + let mut temp = [0u8; 32]; + temp.copy_from_slice(data); + temp[31] &= 127u8; + let mut output = [0u32; 10]; + fiat_25519_from_bytes(&mut output, &temp); + FieldElement2625(output) + } + + /// Serialize this `FieldElement51` to a 32-byte array. The + /// encoding is canonical. + pub fn to_bytes(&self) -> [u8; 32] { + let mut bytes = [0u8; 32]; + fiat_25519_to_bytes(&mut bytes, &self.0); + return bytes; + } + + /// Compute `self^2`. + pub fn square(&self) -> FieldElement2625 { + let mut output = *self; + fiat_25519_carry_square(&mut output.0, &self.0); + output + } + + /// Compute `2*self^2`. + pub fn square2(&self) -> FieldElement2625 { + let mut output = *self; + let mut temp = *self; + // Void vs return type, measure cost of copying self + fiat_25519_carry_square(&mut temp.0, &self.0); + fiat_25519_add(&mut output.0, &temp.0, &temp.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u32/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u32/mod.rs new file mode 100644 index 0000000..974316e --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u32/mod.rs @@ -0,0 +1,26 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier. +//! +//! This code is intended to be portable, but it requires that +//! multiplication of two \\(32\\)-bit values to a \\(64\\)-bit result +//! is constant-time on the target platform. +//! +//! This uses the formally-verified field arithmetic generated by the +//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto) + +#[path = "../u32/scalar.rs"] +pub mod scalar; + +pub mod field; + +#[path = "../u32/constants.rs"] +pub mod constants; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u64/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u64/field.rs new file mode 100644 index 0000000..7e381b6 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u64/field.rs @@ -0,0 +1,249 @@ +// -*- mode: rust; coding: utf-8; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit +//! limbs with \\(128\\)-bit products. +//! +//! This uses the formally-verified field arithmetic generated by the +//! [fiat-crypto project](https://github.com/mit-plv/fiat-crypto) + +use core::fmt::Debug; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Sub, SubAssign}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use zeroize::Zeroize; + +use fiat_crypto::curve25519_64::*; + +/// A `FieldElement51` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// In the 64-bit implementation, a `FieldElement` is represented in +/// radix \\(2\^{51}\\) as five `u64`s; the coefficients are allowed to +/// grow up to \\(2\^{54}\\) between reductions modulo \\(p\\). +/// +/// # Note +/// +/// The `curve25519_dalek::field` module provides a type alias +/// `curve25519_dalek::field::FieldElement` to either `FieldElement51` +/// or `FieldElement2625`. +/// +/// The backend-specific type `FieldElement51` should not be used +/// outside of the `curve25519_dalek::field` module. +#[derive(Copy, Clone)] +pub struct FieldElement51(pub(crate) [u64; 5]); + +impl Debug for FieldElement51 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "FieldElement51({:?})", &self.0[..]) + } +} + +impl Zeroize for FieldElement51 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl<'b> AddAssign<&'b FieldElement51> for FieldElement51 { + fn add_assign(&mut self, _rhs: &'b FieldElement51) { + let input = self.0; + fiat_25519_add(&mut self.0, &input, &_rhs.0); + let input = self.0; + fiat_25519_carry(&mut self.0, &input); + } +} + +impl<'a, 'b> Add<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn add(self, _rhs: &'b FieldElement51) -> FieldElement51 { + let mut output = *self; + fiat_25519_add(&mut output.0, &self.0, &_rhs.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl<'b> SubAssign<&'b FieldElement51> for FieldElement51 { + fn sub_assign(&mut self, _rhs: &'b FieldElement51) { + let input = self.0; + fiat_25519_sub(&mut self.0, &input, &_rhs.0); + let input = self.0; + fiat_25519_carry(&mut self.0, &input); + } +} + +impl<'a, 'b> Sub<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn sub(self, _rhs: &'b FieldElement51) -> FieldElement51 { + let mut output = *self; + fiat_25519_sub(&mut output.0, &self.0, &_rhs.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl<'b> MulAssign<&'b FieldElement51> for FieldElement51 { + fn mul_assign(&mut self, _rhs: &'b FieldElement51) { + let input = self.0; + fiat_25519_carry_mul(&mut self.0, &input, &_rhs.0); + } +} + +impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn mul(self, _rhs: &'b FieldElement51) -> FieldElement51 { + let mut output = *self; + fiat_25519_carry_mul(&mut output.0, &self.0, &_rhs.0); + output + } +} + +impl<'a> Neg for &'a FieldElement51 { + type Output = FieldElement51; + fn neg(self) -> FieldElement51 { + let mut output = *self; + fiat_25519_opp(&mut output.0, &self.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} + +impl ConditionallySelectable for FieldElement51 { + fn conditional_select( + a: &FieldElement51, + b: &FieldElement51, + choice: Choice, + ) -> FieldElement51 { + let mut output = [0u64; 5]; + fiat_25519_selectznz(&mut output, choice.unwrap_u8() as fiat_25519_u1, &a.0, &b.0); + FieldElement51(output) + } + + fn conditional_swap(a: &mut FieldElement51, b: &mut FieldElement51, choice: Choice) { + u64::conditional_swap(&mut a.0[0], &mut b.0[0], choice); + u64::conditional_swap(&mut a.0[1], &mut b.0[1], choice); + u64::conditional_swap(&mut a.0[2], &mut b.0[2], choice); + u64::conditional_swap(&mut a.0[3], &mut b.0[3], choice); + u64::conditional_swap(&mut a.0[4], &mut b.0[4], choice); + } + + fn conditional_assign(&mut self, _rhs: &FieldElement51, choice: Choice) { + let mut output = [0u64; 5]; + let choicebit = choice.unwrap_u8() as fiat_25519_u1; + fiat_25519_cmovznz_u64(&mut output[0], choicebit, self.0[0], _rhs.0[0]); + fiat_25519_cmovznz_u64(&mut output[1], choicebit, self.0[1], _rhs.0[1]); + fiat_25519_cmovznz_u64(&mut output[2], choicebit, self.0[2], _rhs.0[2]); + fiat_25519_cmovznz_u64(&mut output[3], choicebit, self.0[3], _rhs.0[3]); + fiat_25519_cmovznz_u64(&mut output[4], choicebit, self.0[4], _rhs.0[4]); + *self = FieldElement51(output); + } +} + +impl FieldElement51 { + /// Construct zero. + pub fn zero() -> FieldElement51 { + FieldElement51([0, 0, 0, 0, 0]) + } + + /// Construct one. + pub fn one() -> FieldElement51 { + FieldElement51([1, 0, 0, 0, 0]) + } + + /// Construct -1. + pub fn minus_one() -> FieldElement51 { + FieldElement51([ + 2251799813685228, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, + ]) + } + + /// Given 64-bit input limbs, reduce to enforce the bound 2^(51 + epsilon). + #[inline(always)] + #[allow(dead_code)] // Need this to not complain about reduce not being used + fn reduce(mut limbs: [u64; 5]) -> FieldElement51 { + let input = limbs; + fiat_25519_carry(&mut limbs, &input); + FieldElement51(limbs) + } + + /// Load a `FieldElement51` from the low 255 bits of a 256-bit + /// input. + /// + /// # Warning + /// + /// This function does not check that the input used the canonical + /// representative. It masks the high bit, but it will happily + /// decode 2^255 - 18 to 1. Applications that require a canonical + /// encoding of every field element should decode, re-encode to + /// the canonical encoding, and check that the input was + /// canonical. + /// + pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement51 { + let mut temp = [0u8; 32]; + temp.copy_from_slice(bytes); + temp[31] &= 127u8; + let mut output = [0u64; 5]; + fiat_25519_from_bytes(&mut output, &temp); + FieldElement51(output) + } + + /// Serialize this `FieldElement51` to a 32-byte array. The + /// encoding is canonical. + pub fn to_bytes(&self) -> [u8; 32] { + let mut bytes = [0u8; 32]; + fiat_25519_to_bytes(&mut bytes, &self.0); + return bytes; + } + + /// Given `k > 0`, return `self^(2^k)`. + pub fn pow2k(&self, mut k: u32) -> FieldElement51 { + let mut output = *self; + loop { + let input = output.0; + fiat_25519_carry_square(&mut output.0, &input); + k -= 1; + if k == 0 { + return output; + } + } + } + + /// Returns the square of this field element. + pub fn square(&self) -> FieldElement51 { + let mut output = *self; + fiat_25519_carry_square(&mut output.0, &self.0); + output + } + + /// Returns 2 times the square of this field element. + pub fn square2(&self) -> FieldElement51 { + let mut output = *self; + let mut temp = *self; + // Void vs return type, measure cost of copying self + fiat_25519_carry_square(&mut temp.0, &self.0); + fiat_25519_add(&mut output.0, &temp.0, &temp.0); + let input = output.0; + fiat_25519_carry(&mut output.0, &input); + output + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u64/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u64/mod.rs new file mode 100644 index 0000000..8c83062 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/fiat_u64/mod.rs @@ -0,0 +1,28 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! The `u64` backend uses `u64`s and a `(u64, u64) -> u128` multiplier. +//! +//! On x86_64, the idiom `(x as u128) * (y as u128)` lowers to `MUL` +//! instructions taking 64-bit inputs and producing 128-bit outputs. On +//! other platforms, this implementation is not recommended. +//! +//! On Haswell and newer, the BMI2 extension provides `MULX`, and on +//! Broadwell and newer, the ADX extension provides `ADCX` and `ADOX` +//! (allowing the CPU to compute two carry chains in parallel). These +//! will be used if available. + +#[path = "../u64/scalar.rs"] +pub mod scalar; + +pub mod field; + +#[path = "../u64/constants.rs"] +pub mod constants; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/mod.rs new file mode 100644 index 0000000..971afe9 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/mod.rs @@ -0,0 +1,55 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Serial implementations of field, scalar, point arithmetic. +//! +//! When the vector backend is disabled, the crate uses the +//! mixed-model strategy for implementing point operations and scalar +//! multiplication; see the [`curve_models`](self::curve_models) and +//! [`scalar_mul`](self::scalar_mul) documentation for more +//! information. +//! +//! When the vector backend is enabled, the field and scalar +//! implementations are still used for non-vectorized operations. +//! +//! Note: at this time the `u32` and `u64` backends cannot be built +//! together. + +#[cfg(not(any( + feature = "u32_backend", + feature = "u64_backend", + feature = "fiat_u32_backend", + feature = "fiat_u64_backend" +)))] +compile_error!( + "no curve25519-dalek backend cargo feature enabled! \ + please enable one of: u32_backend, u64_backend, fiat_u32_backend, fiat_u64_backend" +); + +#[cfg(feature = "u32_backend")] +pub mod u32; + +#[cfg(feature = "u64_backend")] +pub mod u64; + +#[cfg(feature = "fiat_u32_backend")] +pub mod fiat_u32; + +#[cfg(feature = "fiat_u64_backend")] +pub mod fiat_u64; + +pub mod curve_models; + +#[cfg(not(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +)))] +pub mod scalar_mul; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/mod.rs new file mode 100644 index 0000000..8bdad1f --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/mod.rs @@ -0,0 +1,31 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Implementations of various scalar multiplication algorithms. +//! +//! Note that all of these implementations use serial code for field +//! arithmetic with the multi-model strategy described in the +//! `curve_models` module. The vectorized AVX2 backend has its own +//! scalar multiplication implementations, since it only uses one +//! curve model. + +pub mod variable_base; + +pub mod vartime_double_base; + +#[cfg(feature = "alloc")] +pub mod straus; + +#[cfg(feature = "alloc")] +pub mod precomputed_straus; + +#[cfg(feature = "alloc")] +pub mod pippenger; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs new file mode 100644 index 0000000..bffe140 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs @@ -0,0 +1,202 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Oleg Andreev +// See LICENSE for licensing information. +// +// Authors: +// - Oleg Andreev + +//! Implementation of a variant of Pippenger's algorithm. + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::VartimeMultiscalarMul; + +#[allow(unused_imports)] +use prelude::*; + +/// Implements a version of Pippenger's algorithm. +/// +/// The algorithm works as follows: +/// +/// Let `n` be a number of point-scalar pairs. +/// Let `w` be a window of bits (6..8, chosen based on `n`, see cost factor). +/// +/// 1. Prepare `2^(w-1) - 1` buckets with indices `[1..2^(w-1))` initialized with identity points. +/// Bucket 0 is not needed as it would contain points multiplied by 0. +/// 2. Convert scalars to a radix-`2^w` representation with signed digits in `[-2^w/2, 2^w/2]`. +/// Note: only the last digit may equal `2^w/2`. +/// 3. Starting with the last window, for each point `i=[0..n)` add it to a a bucket indexed by +/// the point's scalar's value in the window. +/// 4. Once all points in a window are sorted into buckets, add buckets by multiplying each +/// by their index. Efficient way of doing it is to start with the last bucket and compute two sums: +/// intermediate sum from the last to the first, and the full sum made of all intermediate sums. +/// 5. Shift the resulting sum of buckets by `w` bits by using `w` doublings. +/// 6. Add to the return value. +/// 7. Repeat the loop. +/// +/// Approximate cost w/o wNAF optimizations (A = addition, D = doubling): +/// +/// ```ascii +/// cost = (n*A + 2*(2^w/2)*A + w*D + A)*256/w +/// | | | | | +/// | | | | looping over 256/w windows +/// | | | adding to the result +/// sorting points | shifting the sum by w bits (to the next window, starting from last window) +/// one by one | +/// into buckets adding/subtracting all buckets +/// multiplied by their indexes +/// using a sum of intermediate sums +/// ``` +/// +/// For large `n`, dominant factor is (n*256/w) additions. +/// However, if `w` is too big and `n` is not too big, then `(2^w/2)*A` could dominate. +/// Therefore, the optimal choice of `w` grows slowly as `n` grows. +/// +/// This algorithm is adapted from section 4 of https://eprint.iacr.org/2012/549.pdf. +pub struct Pippenger; + +#[cfg(any(feature = "alloc", feature = "std"))] +impl VartimeMultiscalarMul for Pippenger { + type Point = EdwardsPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + use traits::Identity; + + let mut scalars = scalars.into_iter(); + let size = scalars.by_ref().size_hint().0; + + // Digit width in bits. As digit width grows, + // number of point additions goes down, but amount of + // buckets and bucket additions grows exponentially. + let w = if size < 500 { + 6 + } else if size < 800 { + 7 + } else { + 8 + }; + + let max_digit: usize = 1 << w; + let digits_count: usize = Scalar::to_radix_2w_size_hint(w); + let buckets_count: usize = max_digit / 2; // digits are signed+centered hence 2^w/2, excluding 0-th bucket + + // Collect optimized scalars and points in buffers for repeated access + // (scanning the whole set per digit position). + let scalars = scalars + .map(|s| s.borrow().to_radix_2w(w)); + + let points = points + .into_iter() + .map(|p| p.map(|P| P.to_projective_niels())); + + let scalars_points = scalars + .zip(points) + .map(|(s, maybe_p)| maybe_p.map(|p| (s, p))) + .collect::>>()?; + + // Prepare 2^w/2 buckets. + // buckets[i] corresponds to a multiplication factor (i+1). + let mut buckets: Vec<_> = (0..buckets_count) + .map(|_| EdwardsPoint::identity()) + .collect(); + + let mut columns = (0..digits_count).rev().map(|digit_index| { + // Clear the buckets when processing another digit. + for i in 0..buckets_count { + buckets[i] = EdwardsPoint::identity(); + } + + // Iterate over pairs of (point, scalar) + // and add/sub the point to the corresponding bucket. + // Note: if we add support for precomputed lookup tables, + // we'll be adding/subtracting point premultiplied by `digits[i]` to buckets[0]. + for (digits, pt) in scalars_points.iter() { + // Widen digit so that we don't run into edge cases when w=8. + let digit = digits[digit_index] as i16; + if digit > 0 { + let b = (digit - 1) as usize; + buckets[b] = (&buckets[b] + pt).to_extended(); + } else if digit < 0 { + let b = (-digit - 1) as usize; + buckets[b] = (&buckets[b] - pt).to_extended(); + } + } + + // Add the buckets applying the multiplication factor to each bucket. + // The most efficient way to do that is to have a single sum with two running sums: + // an intermediate sum from last bucket to the first, and a sum of intermediate sums. + // + // For example, to add buckets 1*A, 2*B, 3*C we need to add these points: + // C + // C B + // C B A Sum = C + (C+B) + (C+B+A) + let mut buckets_intermediate_sum = buckets[buckets_count - 1]; + let mut buckets_sum = buckets[buckets_count - 1]; + for i in (0..(buckets_count - 1)).rev() { + buckets_intermediate_sum += buckets[i]; + buckets_sum += buckets_intermediate_sum; + } + + buckets_sum + }); + + // Take the high column as an initial value to avoid wasting time doubling the identity element in `fold()`. + // `unwrap()` always succeeds because we know we have more than zero digits. + let hi_column = columns.next().unwrap(); + + Some( + columns + .fold(hi_column, |total, p| total.mul_by_pow_2(w as u32) + p), + ) + } +} + +#[cfg(test)] +mod test { + use super::*; + use constants; + use scalar::Scalar; + + #[test] + fn test_vartime_pippenger() { + // Reuse points across different tests + let mut n = 512; + let x = Scalar::from(2128506u64).invert(); + let y = Scalar::from(4443282u64).invert(); + let points: Vec<_> = (0..n) + .map(|i| constants::ED25519_BASEPOINT_POINT * Scalar::from(1 + i as u64)) + .collect(); + let scalars: Vec<_> = (0..n) + .map(|i| x + (Scalar::from(i as u64) * y)) // fast way to make ~random but deterministic scalars + .collect(); + + let premultiplied: Vec = scalars + .iter() + .zip(points.iter()) + .map(|(sc, pt)| sc * pt) + .collect(); + + while n > 0 { + let scalars = &scalars[0..n].to_vec(); + let points = &points[0..n].to_vec(); + let control: EdwardsPoint = premultiplied[0..n].iter().sum(); + + let subject = Pippenger::vartime_multiscalar_mul(scalars.clone(), points.clone()); + + assert_eq!(subject.compress(), control.compress()); + + n = n / 2; + } + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs new file mode 100644 index 0000000..97f5e86 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs @@ -0,0 +1,110 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Henry de Valence. +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +//! Precomputation for Straus's method. + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use backend::serial::curve_models::{ + AffineNielsPoint, CompletedPoint, ProjectiveNielsPoint, ProjectivePoint, +}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::Identity; +use traits::VartimePrecomputedMultiscalarMul; +use window::{NafLookupTable5, NafLookupTable8}; + +#[allow(unused_imports)] +use prelude::*; + +pub struct VartimePrecomputedStraus { + static_lookup_tables: Vec>, +} + +impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { + type Point = EdwardsPoint; + + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + Self { + static_lookup_tables: static_points + .into_iter() + .map(|P| NafLookupTable8::::from(P.borrow())) + .collect(), + } + } + + fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator>, + { + let static_nafs = static_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + let dynamic_nafs: Vec<_> = dynamic_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + + let dynamic_lookup_tables = dynamic_points + .into_iter() + .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) + .collect::>>()?; + + let sp = self.static_lookup_tables.len(); + let dp = dynamic_lookup_tables.len(); + assert_eq!(sp, static_nafs.len()); + assert_eq!(dp, dynamic_nafs.len()); + + // We could save some doublings by looking for the highest + // nonzero NAF coefficient, but since we might have a lot of + // them to search, it's not clear it's worthwhile to check. + let mut S = ProjectivePoint::identity(); + for j in (0..256).rev() { + let mut R: CompletedPoint = S.double(); + + for i in 0..dp { + let t_ij = dynamic_nafs[i][j]; + if t_ij > 0 { + R = &R.to_extended() + &dynamic_lookup_tables[i].select(t_ij as usize); + } else if t_ij < 0 { + R = &R.to_extended() - &dynamic_lookup_tables[i].select(-t_ij as usize); + } + } + + for i in 0..sp { + let t_ij = static_nafs[i][j]; + if t_ij > 0 { + R = &R.to_extended() + &self.static_lookup_tables[i].select(t_ij as usize); + } else if t_ij < 0 { + R = &R.to_extended() - &self.static_lookup_tables[i].select(-t_ij as usize); + } + } + + S = R.to_projective(); + } + + Some(S.to_extended()) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/straus.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/straus.rs new file mode 100644 index 0000000..a361df5 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/straus.rs @@ -0,0 +1,196 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Implementation of the interleaved window method, also known as Straus' method. + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::MultiscalarMul; +use traits::VartimeMultiscalarMul; + +#[allow(unused_imports)] +use prelude::*; + +/// Perform multiscalar multiplication by the interleaved window +/// method, also known as Straus' method (since it was apparently +/// [first published][solution] by Straus in 1964, as a solution to [a +/// problem][problem] posted in the American Mathematical Monthly in +/// 1963). +/// +/// It is easy enough to reinvent, and has been repeatedly. The basic +/// idea is that when computing +/// \\[ +/// Q = s_1 P_1 + \cdots + s_n P_n +/// \\] +/// by means of additions and doublings, the doublings can be shared +/// across the \\( P_i \\\). +/// +/// We implement two versions, a constant-time algorithm using fixed +/// windows and a variable-time algorithm using sliding windows. They +/// are slight variations on the same idea, and are described in more +/// detail in the respective implementations. +/// +/// [solution]: https://www.jstor.org/stable/2310929 +/// [problem]: https://www.jstor.org/stable/2312273 +pub struct Straus {} + +impl MultiscalarMul for Straus { + type Point = EdwardsPoint; + + /// Constant-time Straus using a fixed window of size \\(4\\). + /// + /// Our goal is to compute + /// \\[ + /// Q = s_1 P_1 + \cdots + s_n P_n. + /// \\] + /// + /// For each point \\( P_i \\), precompute a lookup table of + /// \\[ + /// P_i, 2P_i, 3P_i, 4P_i, 5P_i, 6P_i, 7P_i, 8P_i. + /// \\] + /// + /// For each scalar \\( s_i \\), compute its radix-\\(2^4\\) + /// signed digits \\( s_{i,j} \\), i.e., + /// \\[ + /// s_i = s_{i,0} + s_{i,1} 16^1 + ... + s_{i,63} 16^{63}, + /// \\] + /// with \\( -8 \leq s_{i,j} < 8 \\). Since \\( 0 \leq |s_{i,j}| + /// \leq 8 \\), we can retrieve \\( s_{i,j} P_i \\) from the + /// lookup table with a conditional negation: using signed + /// digits halves the required table size. + /// + /// Then as in the single-base fixed window case, we have + /// \\[ + /// \begin{aligned} + /// s_i P_i &= P_i (s_{i,0} + s_{i,1} 16^1 + \cdots + s_{i,63} 16^{63}) \\\\ + /// s_i P_i &= P_i s_{i,0} + P_i s_{i,1} 16^1 + \cdots + P_i s_{i,63} 16^{63} \\\\ + /// s_i P_i &= P_i s_{i,0} + 16(P_i s_{i,1} + 16( \cdots +16P_i s_{i,63})\cdots ) + /// \end{aligned} + /// \\] + /// so each \\( s_i P_i \\) can be computed by alternately adding + /// a precomputed multiple \\( P_i s_{i,j} \\) of \\( P_i \\) and + /// repeatedly doubling. + /// + /// Now consider the two-dimensional sum + /// \\[ + /// \begin{aligned} + /// s\_1 P\_1 &=& P\_1 s\_{1,0} &+& 16 (P\_1 s\_{1,1} &+& 16 ( \cdots &+& 16 P\_1 s\_{1,63}&) \cdots ) \\\\ + /// + & & + & & + & & & & + & \\\\ + /// s\_2 P\_2 &=& P\_2 s\_{2,0} &+& 16 (P\_2 s\_{2,1} &+& 16 ( \cdots &+& 16 P\_2 s\_{2,63}&) \cdots ) \\\\ + /// + & & + & & + & & & & + & \\\\ + /// \vdots & & \vdots & & \vdots & & & & \vdots & \\\\ + /// + & & + & & + & & & & + & \\\\ + /// s\_n P\_n &=& P\_n s\_{n,0} &+& 16 (P\_n s\_{n,1} &+& 16 ( \cdots &+& 16 P\_n s\_{n,63}&) \cdots ) + /// \end{aligned} + /// \\] + /// The sum of the left-hand column is the result \\( Q \\); by + /// computing the two-dimensional sum on the right column-wise, + /// top-to-bottom, then right-to-left, we need to multiply by \\( + /// 16\\) only once per column, sharing the doublings across all + /// of the input points. + fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + { + use zeroize::Zeroizing; + + use backend::serial::curve_models::ProjectiveNielsPoint; + use window::LookupTable; + use traits::Identity; + + let lookup_tables: Vec<_> = points + .into_iter() + .map(|point| LookupTable::::from(point.borrow())) + .collect(); + + // This puts the scalar digits into a heap-allocated Vec. + // To ensure that these are erased, pass ownership of the Vec into a + // Zeroizing wrapper. + let scalar_digits_vec: Vec<_> = scalars + .into_iter() + .map(|s| s.borrow().to_radix_16()) + .collect(); + let scalar_digits = Zeroizing::new(scalar_digits_vec); + + let mut Q = EdwardsPoint::identity(); + for j in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + let it = scalar_digits.iter().zip(lookup_tables.iter()); + for (s_i, lookup_table_i) in it { + // R_i = s_{i,j} * P_i + let R_i = lookup_table_i.select(s_i[j]); + // Q = Q + R_i + Q = (&Q + &R_i).to_extended(); + } + } + + Q + } +} + +impl VartimeMultiscalarMul for Straus { + type Point = EdwardsPoint; + + /// Variable-time Straus using a non-adjacent form of width \\(5\\). + /// + /// This is completely similar to the constant-time code, but we + /// use a non-adjacent form for the scalar, and do not do table + /// lookups in constant time. + /// + /// The non-adjacent form has signed, odd digits. Using only odd + /// digits halves the table size (since we only need odd + /// multiples), or gives fewer additions for the same table size. + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + use backend::serial::curve_models::{CompletedPoint, ProjectiveNielsPoint, ProjectivePoint}; + use window::NafLookupTable5; + use traits::Identity; + + let nafs: Vec<_> = scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect(); + + let lookup_tables = points + .into_iter() + .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) + .collect::>>()?; + + let mut r = ProjectivePoint::identity(); + + for i in (0..256).rev() { + let mut t: CompletedPoint = r.double(); + + for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) { + if naf[i] > 0 { + t = &t.to_extended() + &lookup_table.select(naf[i] as usize); + } else if naf[i] < 0 { + t = &t.to_extended() - &lookup_table.select(-naf[i] as usize); + } + } + + r = t.to_projective(); + } + + Some(r.to_extended()) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/variable_base.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/variable_base.rs new file mode 100644 index 0000000..a4ff2ed --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/variable_base.rs @@ -0,0 +1,46 @@ +#![allow(non_snake_case)] + +use traits::Identity; +use scalar::Scalar; +use edwards::EdwardsPoint; +use backend::serial::curve_models::ProjectiveNielsPoint; +use window::LookupTable; + +/// Perform constant-time, variable-base scalar multiplication. +pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + let lookup_table = LookupTable::::from(point); + // Setting s = scalar, compute + // + // s = s_0 + s_1*16^1 + ... + s_63*16^63, + // + // with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`. + let scalar_digits = scalar.to_radix_16(); + // Compute s*P as + // + // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) + // s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63 + // s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...)) + // + // We sum right-to-left. + + // Unwrap first loop iteration to save computing 16*identity + let mut tmp2; + let mut tmp3 = EdwardsPoint::identity(); + let mut tmp1 = &tmp3 + &lookup_table.select(scalar_digits[63]); + // Now tmp1 = s_63*P in P1xP1 coords + for i in (0..63).rev() { + tmp2 = tmp1.to_projective(); // tmp2 = (prev) in P2 coords + tmp1 = tmp2.double(); // tmp1 = 2*(prev) in P1xP1 coords + tmp2 = tmp1.to_projective(); // tmp2 = 2*(prev) in P2 coords + tmp1 = tmp2.double(); // tmp1 = 4*(prev) in P1xP1 coords + tmp2 = tmp1.to_projective(); // tmp2 = 4*(prev) in P2 coords + tmp1 = tmp2.double(); // tmp1 = 8*(prev) in P1xP1 coords + tmp2 = tmp1.to_projective(); // tmp2 = 8*(prev) in P2 coords + tmp1 = tmp2.double(); // tmp1 = 16*(prev) in P1xP1 coords + tmp3 = tmp1.to_extended(); // tmp3 = 16*(prev) in P3 coords + tmp1 = &tmp3 + &lookup_table.select(scalar_digits[i]); + // Now tmp1 = s_i*P + 16*(prev) in P1xP1 coords + } + tmp1.to_extended() +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/vartime_double_base.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/vartime_double_base.rs new file mode 100644 index 0000000..03517f9 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/scalar_mul/vartime_double_base.rs @@ -0,0 +1,62 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence +#![allow(non_snake_case)] + +use constants; +use traits::Identity; +use scalar::Scalar; +use edwards::EdwardsPoint; +use backend::serial::curve_models::{ProjectiveNielsPoint, ProjectivePoint}; +use window::NafLookupTable5; + +/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. +pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { + let a_naf = a.non_adjacent_form(5); + let b_naf = b.non_adjacent_form(8); + + // Find starting index + let mut i: usize = 255; + for j in (0..256).rev() { + i = j; + if a_naf[i] != 0 || b_naf[i] != 0 { + break; + } + } + + let table_A = NafLookupTable5::::from(A); + let table_B = &constants::AFFINE_ODD_MULTIPLES_OF_BASEPOINT; + + let mut r = ProjectivePoint::identity(); + loop { + let mut t = r.double(); + + if a_naf[i] > 0 { + t = &t.to_extended() + &table_A.select(a_naf[i] as usize); + } else if a_naf[i] < 0 { + t = &t.to_extended() - &table_A.select(-a_naf[i] as usize); + } + + if b_naf[i] > 0 { + t = &t.to_extended() + &table_B.select(b_naf[i] as usize); + } else if b_naf[i] < 0 { + t = &t.to_extended() - &table_B.select(-b_naf[i] as usize); + } + + r = t.to_projective(); + + if i == 0 { + break; + } + i -= 1; + } + + r.to_extended() +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/constants.rs new file mode 100644 index 0000000..af509cf --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/constants.rs @@ -0,0 +1,4789 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! This module contains various constants (such as curve parameters +//! and useful field elements like `sqrt(-1)`), as well as +//! lookup tables of pre-computed points. + +use backend::serial::curve_models::AffineNielsPoint; +use super::field::FieldElement2625; +use super::scalar::Scalar29; +use edwards::{EdwardsBasepointTable, EdwardsPoint}; +use window::{LookupTable, NafLookupTable8}; + +/// The value of minus one, equal to `-&FieldElement::one()` +pub(crate) const MINUS_ONE: FieldElement2625 = FieldElement2625([ + 67108844, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431 +]); + +/// Edwards `d` value, equal to `-121665/121666 mod p`. +pub(crate) const EDWARDS_D: FieldElement2625 = FieldElement2625([ + 56195235, 13857412, 51736253, 6949390, 114729, 24766616, 60832955, 30306712, 48412415, 21499315, +]); + +/// Edwards `2*d` value, equal to `2*(-121665/121666) mod p`. +pub(crate) const EDWARDS_D2: FieldElement2625 = FieldElement2625([ + 45281625, 27714825, 36363642, 13898781, 229458, 15978800, 54557047, 27058993, 29715967, 9444199, +]); + +/// One minus edwards `d` value squared, equal to `(1 - (-121665/121666) mod p) pow 2` +pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement2625 = FieldElement2625([ + 6275446, 16937061, 44170319, 29780721, 11667076, 7397348, 39186143, 1766194, 42675006, 672202 +]); + +/// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2` +pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement2625 = FieldElement2625([ + 15551776, 22456977, 53683765, 23429360, 55212328, 10178283, 40474537, 4729243, 61826754, 23438029 +]); + +/// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const SQRT_AD_MINUS_ONE: FieldElement2625 = FieldElement2625([ + 24849947, 33400850, 43495378, 6347714, 46036536, 32887293, 41837720, 18186727, 66238516, + 14525638, +]); + +/// `= 1/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const INVSQRT_A_MINUS_D: FieldElement2625 = FieldElement2625([ + 6111466, 4156064, 39310137, 12243467, 41204824, 120896, 20826367, 26493656, 6093567, 31568420, +]); + +/// Precomputed value of one of the square roots of -1 (mod p) +pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625([ + 34513072, 25610706, 9377949, 3500415, 12389472, 33281959, 41962654, 31548777, 326685, 11406482, +]); + +/// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) +pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 = + FieldElement2625([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + +/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation +/// for Curve25519 in its Montgomery form. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A: FieldElement2625 = + FieldElement2625([486662, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + +/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A_NEG: FieldElement2625 = FieldElement2625([ + 66622183, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, +]); + +/// `L` is the order of base point, i.e. 2^252 + +/// 27742317777372353535851937790883648493 +pub(crate) const L: Scalar29 = Scalar29([ + 0x1cf5d3ed, 0x009318d2, 0x1de73596, 0x1df3bd45, 0x0000014d, 0x00000000, 0x00000000, 0x00000000, + 0x00100000, +]); + +/// `L` * `LFACTOR` = -1 (mod 2^29) +pub(crate) const LFACTOR: u32 = 0x12547e1b; + +/// `R` = R % L where R = 2^261 +pub(crate) const R: Scalar29 = Scalar29([ + 0x114df9ed, 0x1a617303, 0x0f7c098c, 0x16793167, 0x1ffd656e, 0x1fffffff, 0x1fffffff, 0x1fffffff, + 0x000fffff, +]); + +/// `RR` = (R^2) % L where R = 2^261 +pub(crate) const RR: Scalar29 = Scalar29([ + 0x0b5f9d12, 0x1e141b17, 0x158d7f3d, 0x143f3757, 0x1972d781, 0x042feb7c, 0x1ceec73d, 0x1e184d1e, + 0x0005046d, +]); + +/// The Ed25519 basepoint, as an `EdwardsPoint`. +/// +/// This is called `_POINT` to distinguish it from +/// `ED25519_BASEPOINT_TABLE`, which should be used for scalar +/// multiplication (it's much faster). +pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { + X: FieldElement2625([ + 52811034, 25909283, 16144682, 17082669, 27570973, 30858332, 40966398, 8378388, 20764389, + 8758491, + ]), + Y: FieldElement2625([ + 40265304, 26843545, 13421772, 20132659, 26843545, 6710886, 53687091, 13421772, 40265318, + 26843545, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([ + 28827043, 27438313, 39759291, 244362, 8635006, 11264893, 19351346, 13413597, 16611511, + 27139452, + ]), +}; + +/// The 8-torsion subgroup \\(\mathcal E [8]\\). +/// +/// In the case of Curve25519, it is cyclic; the \\(i\\)-th element of +/// the array is \\([i]P\\), where \\(P\\) is a point of order \\(8\\) +/// generating \\(\mathcal E[8]\\). +/// +/// Thus \\(\mathcal E[4]\\) is the points indexed by `0,2,4,6`, and +/// \\(\mathcal E[2]\\) is the points indexed by `0,4`. +/// The Ed25519 basepoint has y = 4/5. This is called `_POINT` to +/// distinguish it from `_TABLE`, which should be used for scalar +/// multiplication (it's much faster). +pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN; + +/// Inner item used to hide limb constants from cargo doc output. +#[doc(hidden)] +pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ + EdwardsPoint { + X: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Y: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625([ + 21352778, 5345713, 4660180, 25206575, 24143089, 14568123, 30185756, 21306662, 33579924, + 8345318, + ]), + Y: FieldElement2625([ + 6952903, 1265500, 60246523, 7057497, 4037696, 5447722, 35427965, 15325401, 19365852, + 31985330, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([ + 41846657, 21581751, 11716001, 27684820, 48915701, 16297738, 20670665, 24995334, + 3541542, 28543251, + ]), + }, + EdwardsPoint { + X: FieldElement2625([ + 32595773, 7943725, 57730914, 30054016, 54719391, 272472, 25146209, 2005654, 66782178, + 22147949, + ]), + Y: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625([ + 21352778, 5345713, 4660180, 25206575, 24143089, 14568123, 30185756, 21306662, 33579924, + 8345318, + ]), + Y: FieldElement2625([ + 60155942, 32288931, 6862340, 26496934, 63071167, 28106709, 31680898, 18229030, + 47743011, 1569101, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([ + 25262188, 11972680, 55392862, 5869611, 18193162, 17256693, 46438198, 8559097, 63567321, + 5011180, + ]), + }, + EdwardsPoint { + X: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Y: FieldElement2625([ + 67108844, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, + 67108863, 33554431, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625([ + 45756067, 28208718, 62448683, 8347856, 42965774, 18986308, 36923107, 12247769, + 33528939, 25209113, + ]), + Y: FieldElement2625([ + 60155942, 32288931, 6862340, 26496934, 63071167, 28106709, 31680898, 18229030, + 47743011, 1569101, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([ + 41846657, 21581751, 11716001, 27684820, 48915701, 16297738, 20670665, 24995334, + 3541542, 28543251, + ]), + }, + EdwardsPoint { + X: FieldElement2625([ + 34513072, 25610706, 9377949, 3500415, 12389472, 33281959, 41962654, 31548777, 326685, + 11406482, + ]), + Y: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625([ + 45756067, 28208718, 62448683, 8347856, 42965774, 18986308, 36923107, 12247769, + 33528939, 25209113, + ]), + Y: FieldElement2625([ + 6952903, 1265500, 60246523, 7057497, 4037696, 5447722, 35427965, 15325401, 19365852, + 31985330, + ]), + Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625([ + 25262188, 11972680, 55392862, 5869611, 18193162, 17256693, 46438198, 8559097, 63567321, + 5011180, + ]), + }, +]; + +/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). +pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; + +/// Inner constant, used to avoid filling the docs with precomputed points. +#[doc(hidden)] +pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = + EdwardsBasepointTable([ + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 93076338, 52752828, 29566454, 37215328, 54414518, 37569218, 94653489, 21800160, + 61029707, 35602036, + ]), + y_minus_x: FieldElement2625([ + 54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692, 5043384, + 19500929, 18085054, + ]), + xy2d: FieldElement2625([ + 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918, 11864899, + 42594502, 29115885, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54292951, 54132516, 45527619, 11784319, 41753206, 30803714, 55390960, 29739860, + 66750418, 23343128, + ]), + y_minus_x: FieldElement2625([ + 45405608, 6903824, 27185491, 6451973, 37531140, 24000426, 51492312, 11189267, + 40279186, 28235350, + ]), + xy2d: FieldElement2625([ + 26966623, 11152617, 32442495, 15396054, 14353839, 20802097, 63980037, 24013313, + 51636816, 29387734, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82745136, 23865874, 24204772, 25642034, 67725840, 16869169, 94896463, 52336674, + 28944398, 32004408, + ]), + y_minus_x: FieldElement2625([ + 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576, 21778470, + 7689661, 11199574, + ]), + xy2d: FieldElement2625([ + 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774, 10017326, + 49359771, 23634074, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50071967, 13921891, 78054670, 27521000, 27105051, 17470053, 105291517, + 15006021, 70393432, 27277891, + ]), + y_minus_x: FieldElement2625([ + 23599295, 25248385, 55915199, 25867015, 13236773, 10506355, 7464579, 9656445, + 13059162, 10374397, + ]), + xy2d: FieldElement2625([ + 7798537, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, 29715387, + 66467155, 33453106, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77970208, 11473153, 27284546, 35535607, 37044514, 46132292, 99976748, 48069538, + 118779423, 44373810, + ]), + y_minus_x: FieldElement2625([ + 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196, 12483687, + 54440373, 5581305, + ]), + xy2d: FieldElement2625([ + 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349, 13850243, + 43430843, 17738489, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 51736881, 20691677, 32573249, 4720197, 107781206, 39429941, 115029100, + 18329611, 124398787, 21468653, + ]), + y_minus_x: FieldElement2625([ + 58559652, 109982, 15149363, 2178705, 22900618, 4543417, 3044240, 17864545, + 1762327, 14866737, + ]), + xy2d: FieldElement2625([ + 48909169, 17603008, 56635573, 1707277, 49922944, 3916100, 38872452, 3959420, + 27914454, 4383652, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 72262591, 43463716, 68832610, 30776557, 97632468, 39071304, 86589715, 38784565, + 43156424, 18378665, + ]), + y_minus_x: FieldElement2625([ + 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025, 16520125, + 30598449, 7715701, + ]), + xy2d: FieldElement2625([ + 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204, 1370707, + 29794553, 32145132, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 14499452, 64379265, 33917749, 62854211, 95603724, 14271266, 97399599, 10876453, + 33954766, 35936157, + ]), + y_minus_x: FieldElement2625([ + 59913433, 30899068, 52378708, 462250, 39384538, 3941371, 60872247, 3696004, + 34808032, 15351954, + ]), + xy2d: FieldElement2625([ + 27431194, 8222322, 16448760, 29646437, 48401861, 11938354, 34147463, 30583916, + 29551812, 10109425, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 53451805, 20399000, 102933977, 45331528, 88556249, 40073815, 64730579, + 31926875, 77201646, 28790260, + ]), + y_minus_x: FieldElement2625([ + 27939166, 14210322, 4677035, 16277044, 44144402, 21156292, 34600109, 12005537, + 49298737, 12803509, + ]), + xy2d: FieldElement2625([ + 17228999, 17892808, 65875336, 300139, 65883994, 21839654, 30364212, 24516238, + 18016356, 4397660, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 56150002, 25864224, 4776340, 18600194, 27850027, 17952220, 40489757, 14544524, + 49631360, 34537070, + ]), + y_minus_x: FieldElement2625([ + 29253598, 15796703, 64244882, 23645547, 10057022, 3163536, 7332899, 29434304, + 46061167, 9934962, + ]), + xy2d: FieldElement2625([ + 5793284, 16271923, 42977250, 23438027, 29188559, 1206517, 52360934, 4559894, + 36984942, 22656481, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 39464893, 55615857, 83391519, 22517938, 28414020, 52096600, 24191032, 38096129, + 53770554, 39054999, + ]), + y_minus_x: FieldElement2625([ + 12650548, 32057319, 9052870, 11355358, 49428827, 25154267, 49678271, 12264342, + 10874051, 13524335, + ]), + xy2d: FieldElement2625([ + 25556948, 30508442, 714650, 2510400, 23394682, 23139102, 33119037, 5080568, + 44580805, 5376627, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 108129445, 29543378, 50095164, 30016803, 60382070, 35475328, 44787558, + 57661420, 71644630, 35123438, + ]), + y_minus_x: FieldElement2625([ + 64853442, 14606629, 45416424, 25514613, 28430648, 8775819, 36614302, 3044289, + 31848280, 12543772, + ]), + xy2d: FieldElement2625([ + 45080285, 2943892, 35251351, 6777305, 13784462, 29262229, 39731668, 31491700, + 7718481, 14474653, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69494160, 36008644, 44477543, 33601034, 62670928, 51428448, 67765827, 26317766, + 91425031, 28300864, + ]), + y_minus_x: FieldElement2625([ + 13741529, 10911568, 33875447, 24950694, 46931033, 32521134, 33040650, 20129900, + 46379407, 8321685, + ]), + xy2d: FieldElement2625([ + 21060490, 31341688, 15712756, 29218333, 1639039, 10656336, 23845965, 21679594, + 57124405, 608371, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 53436113, 18466845, 56219170, 25997372, 61071954, 11305546, 68232832, 60328286, + 94338261, 33578318, + ]), + y_minus_x: FieldElement2625([ + 43864724, 33260226, 55364135, 14712570, 37643165, 31524814, 12797023, 27114124, + 65475458, 16678953, + ]), + xy2d: FieldElement2625([ + 37608244, 4770661, 51054477, 14001337, 7830047, 9564805, 65600720, 28759386, + 49939598, 4904952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 91168402, 48171434, 86146020, 18514523, 86874956, 18648002, 72278074, 16191879, + 69237100, 29227598, + ]), + y_minus_x: FieldElement2625([ + 50127693, 4124965, 58568254, 22900634, 30336521, 19449185, 37302527, 916032, + 60226322, 30567899, + ]), + xy2d: FieldElement2625([ + 44477957, 12419371, 59974635, 26081060, 50629959, 16739174, 285431, 2763829, + 15736322, 4143876, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69488197, 11839344, 62998462, 27565766, 78383161, 34349388, 67321664, 18959768, + 23527083, 17096164, + ]), + y_minus_x: FieldElement2625([ + 33431108, 22423954, 49269897, 17927531, 8909498, 8376530, 34483524, 4087880, + 51919953, 19138217, + ]), + xy2d: FieldElement2625([ + 1767664, 7197987, 53903638, 31531796, 54017513, 448825, 5799055, 4357868, + 62334673, 17231393, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 6721947, 47388255, 43585475, 32003117, 93463156, 21691110, 90474010, 29604699, + 74499753, 36314231, + ]), + y_minus_x: FieldElement2625([ + 4409022, 2052381, 23373853, 10530217, 7676779, 20668478, 21302352, 29290375, + 1244379, 20634787, + ]), + xy2d: FieldElement2625([ + 62687625, 7169618, 4982368, 30596842, 30256824, 30776892, 14086412, 9208236, + 15886429, 16489664, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69104920, 43930080, 81455230, 46865633, 60234728, 17116020, 120524529, + 33952799, 36502408, 32841498, + ]), + y_minus_x: FieldElement2625([ + 41801399, 9795879, 64331450, 14878808, 33577029, 14780362, 13348553, 12076947, + 36272402, 5113181, + ]), + xy2d: FieldElement2625([ + 49338080, 11797795, 31950843, 13929123, 41220562, 12288343, 36767763, 26218045, + 13847710, 5387222, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 48526682, 30138214, 84933706, 64767897, 89853205, 56666252, 75871923, 37172217, + 47508201, 43925422, + ]), + y_minus_x: FieldElement2625([ + 20246567, 19185054, 22358228, 33010720, 18507282, 23140436, 14554436, 24808340, + 32232923, 16763880, + ]), + xy2d: FieldElement2625([ + 9648486, 10094563, 26416693, 14745928, 36734546, 27081810, 11094160, 15689506, + 3140038, 17044340, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50948773, 39027126, 31895587, 38299426, 75932378, 43920116, 39884063, 43003044, + 38334409, 33920726, + ]), + y_minus_x: FieldElement2625([ + 19153450, 11523972, 56012374, 27051289, 42461232, 5420646, 28344573, 8041113, + 719605, 11671788, + ]), + xy2d: FieldElement2625([ + 8678006, 2694440, 60300850, 2517371, 4964326, 11152271, 51675948, 18287915, + 27000812, 23358879, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 119059805, 40688742, 75748150, 30739554, 59873175, 43976173, 67672928, + 38890528, 73859840, 19033405, + ]), + y_minus_x: FieldElement2625([ + 11836410, 29574944, 26297893, 16080799, 23455045, 15735944, 1695823, 24735310, + 8169719, 16220347, + ]), + xy2d: FieldElement2625([ + 48993007, 8653646, 17578566, 27461813, 59083086, 17541668, 55964556, 30926767, + 61118155, 19388398, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 43800347, 22586119, 82322091, 23473217, 36255258, 22504427, 27884328, 36401716, + 69764724, 35292826, + ]), + y_minus_x: FieldElement2625([ + 39571412, 19301410, 41772562, 25551651, 57738101, 8129820, 21651608, 30315096, + 48021414, 22549153, + ]), + xy2d: FieldElement2625([ + 1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, + 10478196, 8544890, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 32173083, 50979553, 24896205, 37475929, 22579055, 63698010, 19270447, 45771905, + 84897880, 63712868, + ]), + y_minus_x: FieldElement2625([ + 36555903, 31326030, 51530034, 23407230, 13243888, 517024, 15479401, 29701199, + 30460519, 1052596, + ]), + xy2d: FieldElement2625([ + 55493970, 13323617, 32618793, 8175907, 51878691, 12596686, 27491595, 28942073, + 3179267, 24075541, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 99055914, 52742212, 62468279, 18214510, 51982886, 27514722, 52352086, 17142691, + 19072639, 24043372, + ]), + y_minus_x: FieldElement2625([ + 11685058, 11822410, 3158003, 19601838, 33402193, 29389366, 5977895, 28339415, + 473098, 5040608, + ]), + xy2d: FieldElement2625([ + 46817982, 8198641, 39698732, 11602122, 1290375, 30754672, 28326861, 1721092, + 47550222, 30422825, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 74990396, 10687936, 74687587, 7738377, 48157852, 31000479, 88929649, 8076148, + 39240368, 11538388, + ]), + y_minus_x: FieldElement2625([ + 47173198, 3899860, 18283497, 26752864, 51380203, 22305220, 8754524, 7446702, + 61432810, 5797015, + ]), + xy2d: FieldElement2625([ + 55813245, 29760862, 51326753, 25589858, 12708868, 25098233, 2014098, 24503858, + 64739691, 27677090, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 111745333, 55540121, 106535706, 34700805, 86065554, 50194990, 68301593, + 29840232, 82232482, 44365936, + ]), + y_minus_x: FieldElement2625([ + 14352079, 30134717, 48166819, 10822654, 32750596, 4699007, 67038501, 15776355, + 38222085, 21579878, + ]), + xy2d: FieldElement2625([ + 38867681, 25481956, 62129901, 28239114, 29416930, 1847569, 46454691, 17069576, + 4714546, 23953777, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 15200313, 41923004, 86787964, 15970073, 35236190, 35513882, 24611598, 29010600, + 55362987, 45894651, + ]), + y_minus_x: FieldElement2625([ + 12876937, 23074376, 33134380, 6590940, 60801088, 14872439, 9613953, 8241152, + 15370987, 9608631, + ]), + xy2d: FieldElement2625([ + 62965568, 21540023, 8446280, 33162829, 4407737, 13629032, 59383996, 15866073, + 38898243, 24740332, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 26660609, 51431209, 75502596, 33912478, 59707572, 34547419, 43204630, 34413128, + 87680086, 41974987, + ]), + y_minus_x: FieldElement2625([ + 14620696, 13067227, 51661590, 8264466, 14106269, 15080814, 33531827, 12516406, + 45534429, 21077682, + ]), + xy2d: FieldElement2625([ + 236881, 10476226, 57258, 18877408, 6472997, 2466984, 17258519, 7256740, + 8791136, 15069930, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 68385255, 24182513, 90058498, 17231624, 43615824, 61406677, 81820737, 38428660, + 36445723, 31223040, + ]), + y_minus_x: FieldElement2625([ + 5855666, 4990204, 53397016, 7294283, 59304582, 1924646, 65685689, 25642053, + 34039526, 9234252, + ]), + xy2d: FieldElement2625([ + 20590503, 24535444, 31529743, 26201766, 64402029, 10650547, 31559055, 21944845, + 18979185, 13396066, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 24474268, 38522535, 22267081, 37961786, 91172745, 25229251, 48291976, 13594781, + 33514650, 40576390, + ]), + y_minus_x: FieldElement2625([ + 55541958, 26988926, 45743778, 15928891, 40950559, 4315420, 41160136, 29637754, + 45628383, 12868081, + ]), + xy2d: FieldElement2625([ + 38473832, 13504660, 19988037, 31421671, 21078224, 6443208, 45662757, 2244499, + 54653067, 25465048, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 36513317, 13793478, 61256044, 33873567, 41385691, 60844964, 100195408, 8957936, + 51875216, 39094952, + ]), + y_minus_x: FieldElement2625([ + 55478669, 22050529, 58989363, 25911358, 2620055, 1022908, 43398120, 31985447, + 50980335, 18591624, + ]), + xy2d: FieldElement2625([ + 23152952, 775386, 27395463, 14006635, 57407746, 4649511, 1689819, 892185, + 55595587, 18348483, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76878974, 43141169, 93604957, 37878551, 68665374, 30004407, 94562682, 38317558, + 47929249, 39421565, + ]), + y_minus_x: FieldElement2625([ + 34343820, 1927589, 31726409, 28801137, 23962433, 17534932, 27846558, 5931263, + 37359161, 17445976, + ]), + xy2d: FieldElement2625([ + 27461885, 30576896, 22380809, 1815854, 44075111, 30522493, 7283489, 18406359, + 47582163, 7734628, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 59098581, 57518046, 55988459, 39750469, 29344157, 20123547, 74694158, 30377805, + 85658360, 48856500, + ]), + y_minus_x: FieldElement2625([ + 34450527, 27383209, 59436070, 22502750, 6258877, 13504381, 10458790, 27135971, + 58236621, 8424745, + ]), + xy2d: FieldElement2625([ + 24687186, 8613276, 36441818, 30320886, 1863891, 31723888, 19206233, 7134917, + 55824382, 32725512, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 11334880, 24336410, 75134156, 46261950, 84632755, 23078360, 77352601, 18868970, + 62042829, 50053268, + ]), + y_minus_x: FieldElement2625([ + 8911542, 6887158, 57524604, 26595841, 11145640, 24010752, 17303924, 19430194, + 6536640, 10543906, + ]), + xy2d: FieldElement2625([ + 38162480, 15479762, 49642029, 568875, 65611181, 11223453, 64439674, 16928857, + 39873154, 8876770, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41365946, 54541999, 118567760, 32707823, 101191041, 32758142, 33627041, + 15824473, 66504438, 24514614, + ]), + y_minus_x: FieldElement2625([ + 10330056, 70051, 7957388, 24551765, 9764901, 15609756, 27698697, 28664395, + 1657393, 3084098, + ]), + xy2d: FieldElement2625([ + 10477963, 26084172, 12119565, 20303627, 29016246, 28188843, 31280318, 14396151, + 36875289, 15272408, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54820536, 36723894, 28813182, 16658753, 92225296, 27923965, 109043770, + 54472724, 42094105, 35504935, + ]), + y_minus_x: FieldElement2625([ + 40928506, 9489186, 11053416, 18808271, 36055143, 5825629, 58724558, 24786899, + 15341278, 8373727, + ]), + xy2d: FieldElement2625([ + 28685821, 7759505, 52730348, 21551571, 35137043, 4079241, 298136, 23321830, + 64230656, 15190419, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 34175950, 47360767, 52771378, 51314432, 110213106, 10940926, 75778582, + 36296824, 108184414, 60233859, + ]), + y_minus_x: FieldElement2625([ + 65528476, 21825014, 41129205, 22109408, 49696989, 22641577, 9291593, 17306653, + 54954121, 6048604, + ]), + xy2d: FieldElement2625([ + 36803549, 14843443, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, + 11213262, 9168384, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 40828313, 44562278, 19408959, 32613674, 115624762, 29225850, 62020803, + 22449281, 20470156, 50710163, + ]), + y_minus_x: FieldElement2625([ + 43972811, 9282191, 14855179, 18164354, 59746048, 19145871, 44324911, 14461607, + 14042978, 5230683, + ]), + xy2d: FieldElement2625([ + 29969548, 30812838, 50396996, 25001989, 9175485, 31085458, 21556950, 3506042, + 61174973, 21104723, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 63964099, 42299092, 19704002, 38135710, 46678177, 6830682, 45824694, 42525944, + 38569674, 48880994, + ]), + y_minus_x: FieldElement2625([ + 47644235, 10110287, 49846336, 30050539, 43608476, 1355668, 51585814, 15300987, + 46594746, 9168259, + ]), + xy2d: FieldElement2625([ + 61755510, 4488612, 43305616, 16314346, 7780487, 17915493, 38160505, 9601604, + 33087103, 24543045, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 47665675, 18041531, 46311396, 21109108, 104393280, 43783891, 39664534, + 52108332, 61111992, 49219103, + ]), + y_minus_x: FieldElement2625([ + 23294591, 16921819, 44458082, 25083453, 27844203, 11461195, 13099750, 31094076, + 18151675, 13417686, + ]), + xy2d: FieldElement2625([ + 42385932, 29377914, 35958184, 5988918, 40250079, 6685064, 1661597, 21002991, + 15271675, 18101767, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 78541887, 20325766, 75348494, 28274914, 65123427, 32828713, 48410099, 35721975, + 60187562, 20114249, + ]), + y_minus_x: FieldElement2625([ + 35672693, 15575145, 30436815, 12192228, 44645511, 9395378, 57191156, 24915434, + 12215109, 12028277, + ]), + xy2d: FieldElement2625([ + 14098381, 6555944, 23007258, 5757252, 51681032, 20603929, 30123439, 4617780, + 50208775, 32898803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 63082644, 51868028, 79002030, 47273095, 52299401, 35401816, 51288864, 43708440, + 91082124, 20869957, + ]), + y_minus_x: FieldElement2625([ + 40577025, 29858441, 65199965, 2534300, 35238307, 17004076, 18341389, 22134481, + 32013173, 23450893, + ]), + xy2d: FieldElement2625([ + 41629544, 10876442, 55337778, 18929291, 54739296, 1838103, 21911214, 6354752, + 4425632, 32716610, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 56675456, 18941465, 89338721, 30463384, 53917697, 34331160, 116802352, + 55088400, 71833867, 47599401, + ]), + y_minus_x: FieldElement2625([ + 19268631, 26250011, 1555348, 8692754, 45634805, 23643767, 6347389, 32142648, + 47586572, 17444675, + ]), + xy2d: FieldElement2625([ + 42244775, 12986007, 56209986, 27995847, 55796492, 33405905, 19541417, 8180106, + 9282262, 10282508, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 108012627, 37982977, 58447667, 20360168, 71207265, 52943606, 15522533, 8372215, + 72651459, 22851748, + ]), + y_minus_x: FieldElement2625([ + 56546323, 14895632, 26814552, 16880582, 49628109, 31065071, 64326972, 6993760, + 49014979, 10114654, + ]), + xy2d: FieldElement2625([ + 47001790, 32625013, 31422703, 10427861, 59998115, 6150668, 38017109, 22025285, + 25953724, 33448274, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62874448, 59069571, 57989737, 36600431, 69210472, 54501569, 86498882, 39648727, + 63793584, 46385556, + ]), + y_minus_x: FieldElement2625([ + 51110167, 7578151, 5310217, 14408357, 33560244, 33329692, 31575953, 6326196, + 7381791, 31132593, + ]), + xy2d: FieldElement2625([ + 46206085, 3296810, 24736065, 17226043, 18374253, 7318640, 6295303, 8082724, + 51746375, 12339663, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 27724736, 35845589, 73197064, 19369633, 68901590, 39412065, 80957277, 15768921, + 92200031, 14856293, + ]), + y_minus_x: FieldElement2625([ + 48242193, 8331042, 24373479, 8541013, 66406866, 24284974, 12927299, 20858939, + 44926390, 24541532, + ]), + xy2d: FieldElement2625([ + 55685435, 28132841, 11632844, 3405020, 30536730, 21880393, 39848098, 13866389, + 30146206, 9142070, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 71032974, 18246915, 120400605, 23499470, 79400683, 32886065, 39406089, 9326383, + 58871006, 37725725, + ]), + y_minus_x: FieldElement2625([ + 51186905, 16037936, 6713787, 16606682, 45496729, 2790943, 26396185, 3731949, + 345228, 28091483, + ]), + xy2d: FieldElement2625([ + 45781307, 13448258, 25284571, 1143661, 20614966, 24705045, 2031538, 21163201, + 50855680, 19972348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 98125037, 16832002, 93480255, 52657630, 62081513, 14854136, 17477601, 37397089, + 28012649, 50703444, + ]), + y_minus_x: FieldElement2625([ + 62033029, 9368965, 58546785, 28953529, 51858910, 6970559, 57918991, 16292056, + 58241707, 3507939, + ]), + xy2d: FieldElement2625([ + 29439664, 3537914, 23333589, 6997794, 49553303, 22536363, 51899661, 18503164, + 57943934, 6580395, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54922984, 59429075, 83547131, 10826159, 58412047, 27318820, 84969307, 24280585, + 65013061, 42858998, + ]), + y_minus_x: FieldElement2625([ + 20714545, 29217521, 29088194, 7406487, 11426967, 28458727, 14792666, 18945815, + 5289420, 33077305, + ]), + xy2d: FieldElement2625([ + 50443312, 22903641, 60948518, 20248671, 9192019, 31751970, 17271489, 12349094, + 26939669, 29802138, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54218947, 9373457, 98704712, 16374214, 21471720, 13221525, 39825369, 54760304, + 63410056, 33672318, + ]), + y_minus_x: FieldElement2625([ + 22263325, 26994382, 3984569, 22379786, 51994855, 32987646, 28311252, 5358056, + 43789084, 541963, + ]), + xy2d: FieldElement2625([ + 16259200, 3261970, 2309254, 18019958, 50223152, 28972515, 24134069, 16848603, + 53771797, 20002236, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76487005, 20414245, 111371745, 20809166, 95307144, 59864765, 64709178, + 32837080, 67799289, 48430675, + ]), + y_minus_x: FieldElement2625([ + 24977353, 33240048, 58884894, 20089345, 28432342, 32378079, 54040059, 21257083, + 44727879, 6618998, + ]), + xy2d: FieldElement2625([ + 65570671, 11685645, 12944378, 13682314, 42719353, 19141238, 8044828, 19737104, + 32239828, 27901670, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 48505798, 38317421, 66182613, 42439735, 105805247, 30367115, 76890510, + 23204372, 32779358, 5095274, + ]), + y_minus_x: FieldElement2625([ + 34100715, 28339925, 34843976, 29869215, 9460460, 24227009, 42507207, 14506723, + 21639561, 30924196, + ]), + xy2d: FieldElement2625([ + 50707921, 20442216, 25239337, 15531969, 3987758, 29055114, 65819361, 26690896, + 17874573, 558605, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 53508716, 10240080, 76280747, 16131052, 46239610, 43154131, 100608350, + 38634582, 69194755, 38674192, + ]), + y_minus_x: FieldElement2625([ + 44903700, 31034903, 50727262, 414690, 42089314, 2170429, 30634760, 25190818, + 35108870, 27794547, + ]), + xy2d: FieldElement2625([ + 60263160, 15791201, 8550074, 32241778, 29928808, 21462176, 27534429, 26362287, + 44757485, 12961481, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 42616785, 57538092, 10368192, 11582341, 110820435, 31309143, 83642793, 8206995, + 104023076, 28394792, + ]), + y_minus_x: FieldElement2625([ + 55987368, 30172197, 2307365, 6362031, 66973409, 8868176, 50273234, 7031274, + 7589640, 8945490, + ]), + xy2d: FieldElement2625([ + 34956097, 8917966, 6661220, 21876816, 65916803, 17761038, 7251488, 22372252, + 24099108, 19098262, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 72128384, 25646961, 71352990, 18840075, 107284455, 40007595, 47990681, + 20265406, 127985831, 56828126, + ]), + y_minus_x: FieldElement2625([ + 10853575, 10721687, 26480089, 5861829, 44113045, 1972174, 65242217, 22996533, + 63745412, 27113307, + ]), + xy2d: FieldElement2625([ + 50106456, 5906789, 221599, 26991285, 7828207, 20305514, 24362660, 31546264, + 53242455, 7421391, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 75248772, 27007934, 99366509, 27663885, 97484582, 1886180, 113042620, 48995682, + 95935221, 29431402, + ]), + y_minus_x: FieldElement2625([ + 6267067, 9695052, 7709135, 16950835, 34239795, 31668296, 14795159, 25714308, + 13746020, 31812384, + ]), + xy2d: FieldElement2625([ + 28584883, 7787108, 60375922, 18503702, 22846040, 25983196, 63926927, 33190907, + 4771361, 25134474, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 92058101, 6376278, 39642383, 25379823, 48462709, 23623825, 100652432, 54967168, + 70678489, 44897024, + ]), + y_minus_x: FieldElement2625([ + 26514970, 4740088, 27912651, 3697550, 19331575, 22082093, 6809885, 4608608, + 7325975, 18753361, + ]), + xy2d: FieldElement2625([ + 55490446, 19000001, 42787651, 7655127, 65739590, 5214311, 39708324, 10258389, + 49462170, 25367739, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 11431185, 49377439, 93679108, 47883555, 85138853, 38350513, 35662684, 49135095, + 76389221, 29580744, + ]), + y_minus_x: FieldElement2625([ + 66948081, 23228174, 44253547, 29249434, 46247496, 19933429, 34297962, 22372809, + 51563772, 4387440, + ]), + xy2d: FieldElement2625([ + 46309467, 12194511, 3937617, 27748540, 39954043, 9340369, 42594872, 8548136, + 20617071, 26072431, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 66170039, 29623845, 58394552, 49679149, 91711988, 27329038, 53333511, 55233041, + 91454545, 10325459, + ]), + y_minus_x: FieldElement2625([ + 47253587, 31985546, 44906155, 8714033, 14007766, 6928528, 16318175, 32543743, + 4766742, 3552007, + ]), + xy2d: FieldElement2625([ + 45357481, 16823515, 1351762, 32751011, 63099193, 3950934, 3217514, 14481909, + 10988822, 29559670, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 15564288, 19242862, 70210106, 39238579, 97555643, 25503075, 79785990, 27049088, + 58813011, 46850436, + ]), + y_minus_x: FieldElement2625([ + 57666574, 6624295, 36809900, 21640754, 62437882, 31497052, 31521203, 9614054, + 37108040, 12074673, + ]), + xy2d: FieldElement2625([ + 4771172, 33419193, 14290748, 20464580, 27992297, 14998318, 65694928, 31997715, + 29832612, 17163397, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 7064865, 59567690, 115055764, 62041325, 48217593, 30641695, 92934105, 38847728, + 39986203, 46656021, + ]), + y_minus_x: FieldElement2625([ + 64810282, 2439669, 59642254, 1719964, 39841323, 17225986, 32512468, 28236839, + 36752793, 29363474, + ]), + xy2d: FieldElement2625([ + 37102324, 10162315, 33928688, 3981722, 50626726, 20484387, 14413973, 9515896, + 19568978, 9628812, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 33053784, 33753789, 83003454, 35137490, 94489106, 28973996, 49269969, 61002024, + 60817076, 36992171, + ]), + y_minus_x: FieldElement2625([ + 48129987, 3884492, 19469877, 12726490, 15913552, 13614290, 44147131, 70103, + 7463304, 4176122, + ]), + xy2d: FieldElement2625([ + 39984863, 10659916, 11482427, 17484051, 12771466, 26919315, 34389459, 28231680, + 24216881, 5944158, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76002989, 41005405, 64444714, 57343111, 106137209, 21165315, 19345745, + 48235228, 78741856, 5847884, + ]), + y_minus_x: FieldElement2625([ + 26942781, 31239115, 9129563, 28647825, 26024104, 11769399, 55590027, 6367193, + 57381634, 4782139, + ]), + xy2d: FieldElement2625([ + 19916442, 28726022, 44198159, 22140040, 25606323, 27581991, 33253852, 8220911, + 6358847, 31680575, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 67910273, 31472729, 16569427, 44619599, 29875703, 33651059, 75017251, 29073951, + 53570360, 34941586, + ]), + y_minus_x: FieldElement2625([ + 19646058, 5720633, 55692158, 12814208, 11607948, 12749789, 14147075, 15156355, + 45242033, 11835259, + ]), + xy2d: FieldElement2625([ + 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, + 40548314, 5052482, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64091413, 43612637, 69089700, 37518674, 22160965, 12322533, 60677741, 20936246, + 12228556, 26550755, + ]), + y_minus_x: FieldElement2625([ + 32944382, 14922211, 44263970, 5188527, 21913450, 24834489, 4001464, 13238564, + 60994061, 8653814, + ]), + xy2d: FieldElement2625([ + 22865569, 28901697, 27603667, 21009037, 14348957, 8234005, 24808405, 5719875, + 28483275, 2841751, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 117796741, 32441125, 66781144, 21446575, 21886281, 51556090, 65220896, + 33238773, 87040921, 20815228, + ]), + y_minus_x: FieldElement2625([ + 55452759, 10087520, 58243976, 28018288, 47830290, 30498519, 3999227, 13239134, + 62331395, 19644223, + ]), + xy2d: FieldElement2625([ + 1382174, 21859713, 17266789, 9194690, 53784508, 9720080, 20403944, 11284705, + 53095046, 3093229, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 83759766, 56070931, 66044684, 35125060, 58779117, 40907184, 66806439, 16271224, + 43059443, 26862581, + ]), + y_minus_x: FieldElement2625([ + 45197768, 27626490, 62497547, 27994275, 35364760, 22769138, 24123613, 15193618, + 45456747, 16815042, + ]), + xy2d: FieldElement2625([ + 57172930, 29264984, 41829040, 4372841, 2087473, 10399484, 31870908, 14690798, + 17361620, 11864968, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 55801216, 39764803, 80315437, 39360751, 105200035, 19587230, 54777658, + 26067830, 41530403, 50868174, + ]), + y_minus_x: FieldElement2625([ + 14668443, 21284197, 26039038, 15305210, 25515617, 4542480, 10453892, 6577524, + 9145645, 27110552, + ]), + xy2d: FieldElement2625([ + 5974855, 3053895, 57675815, 23169240, 35243739, 3225008, 59136222, 3936127, + 61456591, 30504127, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97734231, 28825031, 41552902, 20761565, 46624288, 41249530, 17097187, 50805368, + 106217947, 35358062, + ]), + y_minus_x: FieldElement2625([ + 63555773, 9865098, 61880298, 4272700, 61435032, 16864731, 14911343, 12196514, + 45703375, 7047411, + ]), + xy2d: FieldElement2625([ + 20093258, 9920966, 55970670, 28210574, 13161586, 12044805, 34252013, 4124600, + 34765036, 23296865, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 46320021, 14084653, 53577151, 41396578, 19119037, 19731827, 71861240, 24839791, + 45429205, 35842469, + ]), + y_minus_x: FieldElement2625([ + 40289628, 30270716, 29965058, 3039786, 52635099, 2540456, 29457502, 14625692, + 42289247, 12570231, + ]), + xy2d: FieldElement2625([ + 66045306, 22002608, 16920317, 12494842, 1278292, 27685323, 45948920, 30055751, + 55134159, 4724942, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 85069815, 21778897, 62967895, 23851901, 58232301, 32143814, 54201480, 24894499, + 104641427, 35458286, + ]), + y_minus_x: FieldElement2625([ + 23134274, 19275300, 56426866, 31942495, 20684484, 15770816, 54119114, 3190295, + 26955097, 14109738, + ]), + xy2d: FieldElement2625([ + 15308788, 5320727, 36995055, 19235554, 22902007, 7767164, 29425325, 22276870, + 31960941, 11934971, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 39713134, 41990227, 71218507, 12222638, 109589860, 14818667, 87747037, + 38429459, 77600255, 34934149, + ]), + y_minus_x: FieldElement2625([ + 53949449, 9197840, 3875503, 24618324, 65725151, 27674630, 33518458, 16176658, + 21432314, 12180697, + ]), + xy2d: FieldElement2625([ + 55321537, 11500837, 13787581, 19721842, 44678184, 10140204, 1465425, 12689540, + 56807545, 19681548, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 72522936, 18168390, 46101199, 43198001, 79943833, 34740580, 64485947, 32212200, + 26128230, 39587344, + ]), + y_minus_x: FieldElement2625([ + 40771450, 19788269, 32496024, 19900513, 17847800, 20885276, 3604024, 8316894, + 41233830, 23117073, + ]), + xy2d: FieldElement2625([ + 3296484, 6223048, 24680646, 21307972, 44056843, 5903204, 58246567, 28915267, + 12376616, 3188849, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29190450, 18895386, 27549112, 32370916, 70628929, 22857130, 32049514, 26245319, + 50999629, 57256556, + ]), + y_minus_x: FieldElement2625([ + 52364359, 24245275, 735817, 32955454, 46701176, 28496527, 25246077, 17758763, + 18640740, 32593455, + ]), + xy2d: FieldElement2625([ + 60180029, 17123636, 10361373, 5642961, 4910474, 12345252, 35470478, 33060001, + 10530746, 1053335, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 104951742, 52922057, 120679510, 54991489, 47651803, 56453479, 102755357, + 30605445, 24018830, 48581076, + ]), + y_minus_x: FieldElement2625([ + 44516310, 30409154, 64819587, 5953842, 53668675, 9425630, 25310643, 13003497, + 64794073, 18408815, + ]), + xy2d: FieldElement2625([ + 39688860, 32951110, 59064879, 31885314, 41016598, 13987818, 39811242, 187898, + 43942445, 31022696, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 45364447, 19743956, 68953703, 38575859, 123783328, 17642957, 76825530, + 49821353, 62038646, 34280530, + ]), + y_minus_x: FieldElement2625([ + 29370903, 27500434, 7334070, 18212173, 9385286, 2247707, 53446902, 28714970, + 30007387, 17731091, + ]), + xy2d: FieldElement2625([ + 66172485, 16086690, 23751945, 33011114, 65941325, 28365395, 9137108, 730663, + 9835848, 4555336, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 43732410, 34964877, 44855110, 54209249, 97976497, 49381408, 17693929, 34099128, + 55123565, 45977077, + ]), + y_minus_x: FieldElement2625([ + 31117226, 21338698, 53606025, 6561946, 57231997, 20796761, 61990178, 29457725, + 29120152, 13924425, + ]), + xy2d: FieldElement2625([ + 49707966, 19321222, 19675798, 30819676, 56101901, 27695611, 57724924, 22236731, + 7240930, 33317044, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 35747087, 22207651, 119210280, 27698212, 111764387, 54956091, 68331198, + 37943914, 70402500, 51557120, + ]), + y_minus_x: FieldElement2625([ + 50424044, 19110186, 11038543, 11054958, 53307689, 30215898, 42789283, 7733546, + 12796905, 27218610, + ]), + xy2d: FieldElement2625([ + 58349431, 22736595, 41689999, 10783768, 36493307, 23807620, 38855524, 3647835, + 3222231, 22393970, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 85714958, 35247531, 108769341, 51938590, 71221215, 43599452, 23603892, + 31506198, 59558087, 36039416, + ]), + y_minus_x: FieldElement2625([ + 9255298, 30423235, 54952701, 32550175, 13098012, 24339566, 16377219, 31451620, + 47306788, 30519729, + ]), + xy2d: FieldElement2625([ + 44379556, 7496159, 61366665, 11329248, 19991973, 30206930, 35390715, 9936965, + 37011176, 22935634, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 88987435, 28553134, 71447199, 47198328, 64071998, 13160959, 86817760, 5415496, + 59748361, 29445138, + ]), + y_minus_x: FieldElement2625([ + 27736842, 10103576, 12500508, 8502413, 63695848, 23920873, 10436917, 32004156, + 43449720, 25422331, + ]), + xy2d: FieldElement2625([ + 19492550, 21450067, 37426887, 32701801, 63900692, 12403436, 30066266, 8367329, + 13243957, 8709688, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 79123950, 36355692, 95306994, 10151020, 91926984, 28811298, 55914672, 27908697, + 72259831, 40828617, + ]), + y_minus_x: FieldElement2625([ + 2831347, 21062286, 1478974, 6122054, 23825128, 20820846, 31097298, 6083058, + 31021603, 23760822, + ]), + xy2d: FieldElement2625([ + 64578913, 31324785, 445612, 10720828, 53259337, 22048494, 43601132, 16354464, + 15067285, 19406725, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 74949787, 47592304, 100852864, 49488446, 66380650, 29911725, 88512851, + 34612017, 47729401, 21151211, + ]), + y_minus_x: FieldElement2625([ + 915865, 17085158, 15608284, 24765302, 42751837, 6060029, 49737545, 8410996, + 59888403, 16527024, + ]), + xy2d: FieldElement2625([ + 32922597, 32997445, 20336073, 17369864, 10903704, 28169945, 16957573, 52992, + 23834301, 6588044, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 32752011, 44787382, 70490858, 24839565, 22652987, 22810329, 17159698, 50243539, + 46794283, 32248439, + ]), + y_minus_x: FieldElement2625([ + 62419196, 9166775, 41398568, 22707125, 11576751, 12733943, 7924251, 30802151, + 1976122, 26305405, + ]), + xy2d: FieldElement2625([ + 21251203, 16309901, 64125849, 26771309, 30810596, 12967303, 156041, 30183180, + 12331344, 25317235, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 75760459, 29077399, 118132091, 28557436, 80111370, 36505236, 96163290, + 28447461, 77116999, 28886530, + ]), + y_minus_x: FieldElement2625([ + 31486061, 15114593, 52847614, 12951353, 14369431, 26166587, 16347320, 19892343, + 8684154, 23021480, + ]), + xy2d: FieldElement2625([ + 19443825, 11385320, 24468943, 23895364, 43189605, 2187568, 40845657, 27467510, + 31316347, 14219878, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 38514355, 1193784, 99354083, 11392484, 31092169, 49277233, 94254877, 40546840, + 29126554, 42761822, + ]), + y_minus_x: FieldElement2625([ + 32382916, 1110093, 18477781, 11028262, 39697101, 26006320, 62128346, 10843781, + 59151264, 19118701, + ]), + xy2d: FieldElement2625([ + 2814918, 7836403, 27519878, 25686276, 46214848, 22000742, 45614304, 8550129, + 28346258, 1994730, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 47530546, 41639976, 53108344, 29605809, 69894701, 17323124, 47591912, 40729325, + 22628101, 41669612, + ]), + y_minus_x: FieldElement2625([ + 36703732, 955510, 55975026, 18476362, 34661776, 20276352, 41457285, 3317159, + 57165847, 930271, + ]), + xy2d: FieldElement2625([ + 51805164, 26720662, 28856489, 1357446, 23421993, 1057177, 24091212, 32165462, + 44343487, 22903716, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 44357614, 28250434, 54201256, 54339997, 51297351, 25757378, 52269845, 50554643, + 65241844, 41953401, + ]), + y_minus_x: FieldElement2625([ + 35139535, 2106402, 62372504, 1362500, 12813763, 16200670, 22981545, 27263159, + 18009407, 17781660, + ]), + xy2d: FieldElement2625([ + 49887941, 24009210, 39324209, 14166834, 29815394, 7444469, 29551787, 29827013, + 19288548, 1325865, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82209002, 51273111, 110293748, 32549332, 107767535, 49063838, 79485593, + 30075285, 100274970, 25511681, + ]), + y_minus_x: FieldElement2625([ + 20909212, 13023121, 57899112, 16251777, 61330449, 25459517, 12412150, 10018715, + 2213263, 19676059, + ]), + xy2d: FieldElement2625([ + 32529814, 22479743, 30361438, 16864679, 57972923, 1513225, 22922121, 6382134, + 61341936, 8371347, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77032307, 44825931, 79725657, 37099153, 104219359, 31832804, 12891686, + 25361300, 40665920, 44040575, + ]), + y_minus_x: FieldElement2625([ + 44511638, 26541766, 8587002, 25296571, 4084308, 20584370, 361725, 2610596, + 43187334, 22099236, + ]), + xy2d: FieldElement2625([ + 5408392, 32417741, 62139741, 10561667, 24145918, 14240566, 31319731, 29318891, + 19985174, 30118346, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 53114388, 50171252, 81658109, 36895530, 99264821, 13648975, 49531796, 8849296, + 67173894, 41925115, + ]), + y_minus_x: FieldElement2625([ + 58787919, 21504805, 31204562, 5839400, 46481576, 32497154, 47665921, 6922163, + 12743482, 23753914, + ]), + xy2d: FieldElement2625([ + 64747493, 12678784, 28815050, 4759974, 43215817, 4884716, 23783145, 11038569, + 18800704, 255233, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 61839168, 31780545, 13957885, 41545147, 23132994, 34283205, 80502710, 42621388, + 86367551, 52355070, + ]), + y_minus_x: FieldElement2625([ + 64172210, 22726896, 56676774, 14516792, 63468078, 4372540, 35173943, 2209389, + 65584811, 2055793, + ]), + xy2d: FieldElement2625([ + 580882, 16705327, 5468415, 30871414, 36182444, 18858431, 59905517, 24560042, + 37087844, 7394434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 90947654, 35377159, 118479284, 48797157, 75426955, 29821327, 45436683, + 30062226, 62287122, 48354352, + ]), + y_minus_x: FieldElement2625([ + 13345610, 9759151, 3371034, 17416641, 16353038, 8577942, 31129804, 13496856, + 58052846, 7402517, + ]), + xy2d: FieldElement2625([ + 2286874, 29118501, 47066405, 31546095, 53412636, 5038121, 11006906, 17794080, + 8205060, 1607563, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 81522931, 25552299, 70440693, 63900646, 89358013, 27960243, 85473524, 30647473, + 30019586, 24525154, + ]), + y_minus_x: FieldElement2625([ + 39420813, 1585952, 56333811, 931068, 37988643, 22552112, 52698034, 12029092, + 9944378, 8024, + ]), + xy2d: FieldElement2625([ + 4368715, 29844802, 29874199, 18531449, 46878477, 22143727, 50994269, 32555346, + 58966475, 5640029, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77408455, 13746482, 11661824, 16234854, 74739102, 5998373, 76918751, 16859867, + 82328661, 19226648, + ]), + y_minus_x: FieldElement2625([ + 27425505, 27835351, 3055005, 10660664, 23458024, 595578, 51710259, 32381236, + 48766680, 9742716, + ]), + xy2d: FieldElement2625([ + 6744077, 2427284, 26042789, 2720740, 66260958, 1118973, 32324614, 7406442, + 12420155, 1994844, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 81121366, 62084143, 115833273, 23975961, 107732385, 29617991, 121184249, + 22644627, 91428792, 27108098, + ]), + y_minus_x: FieldElement2625([ + 16412671, 29047065, 10772640, 15929391, 50040076, 28895810, 10555944, 23070383, + 37006495, 28815383, + ]), + xy2d: FieldElement2625([ + 22397363, 25786748, 57815702, 20761563, 17166286, 23799296, 39775798, 6199365, + 21880021, 21303672, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62825538, 5368522, 35991846, 41717820, 103894664, 36763558, 83666014, 42445160, + 75949308, 38512191, + ]), + y_minus_x: FieldElement2625([ + 51661137, 709326, 60189418, 22684253, 37330941, 6522331, 45388683, 12130071, + 52312361, 5005756, + ]), + xy2d: FieldElement2625([ + 64994094, 19246303, 23019041, 15765735, 41839181, 6002751, 10183197, 20315106, + 50713577, 31378319, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 115191953, 35186435, 80575154, 59113763, 110577275, 16573535, 35094956, + 30497327, 22208661, 35554900, + ]), + y_minus_x: FieldElement2625([ + 3065054, 32141671, 41510189, 33192999, 49425798, 27851016, 58944651, 11248526, + 63417650, 26140247, + ]), + xy2d: FieldElement2625([ + 10379208, 27508878, 8877318, 1473647, 37817580, 21046851, 16690914, 2553332, + 63976176, 16400288, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82825513, 34808697, 115745037, 41000704, 58659945, 6344163, 45011593, 26268851, + 26894936, 42686498, + ]), + y_minus_x: FieldElement2625([ + 24158868, 12938817, 11085297, 25376834, 39045385, 29097348, 36532400, 64451, + 60291780, 30861549, + ]), + xy2d: FieldElement2625([ + 13488534, 7794716, 22236231, 5989356, 25426474, 20976224, 2350709, 30135921, + 62420857, 2364225, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 83443897, 9132433, 92749446, 40233319, 68834491, 42072368, 55301839, 21856974, + 15445874, 25756331, + ]), + y_minus_x: FieldElement2625([ + 29004188, 25687351, 28661401, 32914020, 54314860, 25611345, 31863254, 29418892, + 66830813, 17795152, + ]), + xy2d: FieldElement2625([ + 60986784, 18687766, 38493958, 14569918, 56250865, 29962602, 10343411, 26578142, + 37280576, 22738620, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 94190495, 37018415, 14099041, 29036828, 68725166, 27348827, 96651499, 15372178, + 84402661, 34515140, + ]), + y_minus_x: FieldElement2625([ + 20263915, 11434237, 61343429, 11236809, 13505955, 22697330, 50997518, 6493121, + 47724353, 7639713, + ]), + xy2d: FieldElement2625([ + 64278047, 18715199, 25403037, 25339236, 58791851, 17380732, 18006286, 17510682, + 29994676, 17746311, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76878673, 38757082, 110060329, 19923038, 106166724, 21992806, 42495722, + 53248081, 35924287, 34263895, + ]), + y_minus_x: FieldElement2625([ + 12286395, 13076066, 45333675, 32377809, 42105665, 4057651, 35090736, 24663557, + 16102006, 13205847, + ]), + xy2d: FieldElement2625([ + 13733362, 5599946, 10557076, 3195751, 61550873, 8536969, 41568694, 8525971, + 10151379, 10394400, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 71133505, 17416880, 89545125, 12276533, 58009849, 64422764, 86807091, 11743038, + 100915394, 42488844, + ]), + y_minus_x: FieldElement2625([ + 51229064, 29029191, 58528116, 30620370, 14634844, 32856154, 57659786, 3137093, + 55571978, 11721157, + ]), + xy2d: FieldElement2625([ + 17555920, 28540494, 8268605, 2331751, 44370049, 9761012, 9319229, 8835153, + 57903375, 32274386, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 66647436, 25724417, 87722981, 16688287, 59594098, 28747312, 89409167, 34059860, + 73217325, 27371016, + ]), + y_minus_x: FieldElement2625([ + 62038564, 12367916, 36445330, 3234472, 32617080, 25131790, 29880582, 20071101, + 40210373, 25686972, + ]), + xy2d: FieldElement2625([ + 35133562, 5726538, 26934134, 10237677, 63935147, 32949378, 24199303, 3795095, + 7592688, 18562353, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 21594413, 18590204, 84575271, 63031641, 32537082, 36294330, 73516586, 12018832, + 38852812, 37852843, + ]), + y_minus_x: FieldElement2625([ + 46458361, 21592935, 39872588, 570497, 3767144, 31836892, 13891941, 31985238, + 13717173, 10805743, + ]), + xy2d: FieldElement2625([ + 52432215, 17910135, 15287173, 11927123, 24177847, 25378864, 66312432, 14860608, + 40169934, 27690595, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 80071405, 38866230, 57048095, 45212711, 85964149, 25600230, 80395126, 54300159, + 62727806, 9882021, + ]), + y_minus_x: FieldElement2625([ + 18512060, 11319350, 46985740, 15090308, 18818594, 5271736, 44380960, 3666878, + 43141434, 30255002, + ]), + xy2d: FieldElement2625([ + 60319844, 30408388, 16192428, 13241070, 15898607, 19348318, 57023983, 26893321, + 64705764, 5276064, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97278672, 28236783, 93415069, 55358004, 94923826, 40623698, 74261714, 37239413, + 68558087, 13082860, + ]), + y_minus_x: FieldElement2625([ + 10342807, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, + 46092426, 25352431, + ]), + xy2d: FieldElement2625([ + 33958735, 3261607, 22745853, 7948688, 19370557, 18376767, 40936887, 6482813, + 56808784, 22494330, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 32869439, 61700319, 25609741, 49233102, 56421094, 51637792, 26112419, 36075440, + 44444575, 40459246, + ]), + y_minus_x: FieldElement2625([ + 29506904, 4457497, 3377935, 23757988, 36598817, 12935079, 1561737, 3841096, + 38105225, 26896789, + ]), + xy2d: FieldElement2625([ + 10340844, 26924055, 48452231, 31276001, 12621150, 20215377, 30878496, 21730062, + 41524312, 5181965, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 25940096, 20896407, 17324187, 56801490, 58437394, 15029093, 91505116, 17103509, + 64786011, 21165857, + ]), + y_minus_x: FieldElement2625([ + 45343161, 9916822, 65808455, 4079497, 66080518, 11909558, 1782390, 12641087, + 20603771, 26992690, + ]), + xy2d: FieldElement2625([ + 48226577, 21881051, 24849421, 11501709, 13161720, 28785558, 1925522, 11914390, + 4662781, 7820689, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 79349895, 33128449, 75241554, 42948365, 32846759, 31954812, 29749455, 45727356, + 83245615, 48818451, + ]), + y_minus_x: FieldElement2625([ + 56758909, 18873868, 58896884, 2330219, 49446315, 19008651, 10658212, 6671822, + 19012087, 3772772, + ]), + xy2d: FieldElement2625([ + 3753511, 30133366, 10617073, 2028709, 14841030, 26832768, 28718731, 17791548, + 20527770, 12988982, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 52286341, 27757162, 63400876, 12689772, 66209881, 22639565, 110034681, + 56543919, 70408527, 54683910, + ]), + y_minus_x: FieldElement2625([ + 50331161, 18301130, 57466446, 4978982, 3308785, 8755439, 6943197, 6461331, + 41525717, 8991217, + ]), + xy2d: FieldElement2625([ + 49882601, 1816361, 65435576, 27467992, 31783887, 25378441, 34160718, 7417949, + 36866577, 1507264, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29692644, 40384323, 56610063, 37889327, 88054838, 21647935, 38221255, 41763822, + 14606361, 22907359, + ]), + y_minus_x: FieldElement2625([ + 63627275, 8707080, 32188102, 5672294, 22096700, 1711240, 34088169, 9761486, + 4170404, 31469107, + ]), + xy2d: FieldElement2625([ + 55521375, 14855944, 62981086, 32022574, 40459774, 15084045, 22186522, 16002000, + 52832027, 25153633, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62297389, 47315460, 35404986, 31070512, 63796392, 41423478, 59995291, 23934339, + 80349708, 44520301, + ]), + y_minus_x: FieldElement2625([ + 59366301, 25297669, 52340529, 19898171, 43876480, 12387165, 4498947, 14147411, + 29514390, 4302863, + ]), + xy2d: FieldElement2625([ + 53695440, 21146572, 20757301, 19752600, 14785142, 8976368, 62047588, 31410058, + 17846987, 19582505, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64864393, 32799703, 62511833, 32488122, 60861691, 35009730, 112569999, + 24339641, 61886162, 46204698, + ]), + y_minus_x: FieldElement2625([ + 57202067, 17484121, 21134159, 12198166, 40044289, 708125, 387813, 13770293, + 47974538, 10958662, + ]), + xy2d: FieldElement2625([ + 22470984, 12369526, 23446014, 28113323, 45588061, 23855708, 55336367, 21979976, + 42025033, 4271861, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 109048144, 57055220, 47199530, 48916026, 61124505, 35713623, 67184238, + 62830334, 101691505, 42024103, + ]), + y_minus_x: FieldElement2625([ + 15854951, 4148314, 58214974, 7259001, 11666551, 13824734, 36577666, 2697371, + 24154791, 24093489, + ]), + xy2d: FieldElement2625([ + 15446137, 17747788, 29759746, 14019369, 30811221, 23944241, 35526855, 12840103, + 24913809, 9815020, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62399559, 27940162, 35267365, 21265538, 52665326, 44353845, 125114051, + 46993199, 85843991, 43020669, + ]), + y_minus_x: FieldElement2625([ + 11933045, 9281483, 5081055, 28370608, 64480701, 28648802, 59381042, 22658328, + 44380208, 16199063, + ]), + xy2d: FieldElement2625([ + 14576810, 379472, 40322331, 25237195, 37682355, 22741457, 67006097, 1876698, + 30801119, 2164795, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 15995067, 36754305, 13672554, 13712240, 47730029, 62461217, 121136116, + 51612593, 53616055, 34822483, + ]), + y_minus_x: FieldElement2625([ + 56818250, 29895392, 63822271, 10948817, 23037027, 3794475, 63638526, 20954210, + 50053494, 3565903, + ]), + xy2d: FieldElement2625([ + 29210069, 24135095, 61189071, 28601646, 10834810, 20226706, 50596761, 22733718, + 39946641, 19523900, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 121055819, 49063018, 83772567, 25398281, 38758921, 42573554, 37925442, + 29785008, 69352974, 19552452, + ]), + y_minus_x: FieldElement2625([ + 61955989, 29753495, 57802388, 27482848, 16243068, 14684434, 41435776, 17373631, + 13491505, 4641841, + ]), + xy2d: FieldElement2625([ + 10813398, 643330, 47920349, 32825515, 30292061, 16954354, 27548446, 25833190, + 14476988, 20787001, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77400943, 9984944, 73590300, 41834336, 59857349, 40587174, 27282936, 31910173, + 106304917, 12651322, + ]), + y_minus_x: FieldElement2625([ + 35923332, 32741048, 22271203, 11835308, 10201545, 15351028, 17099662, 3988035, + 21721536, 30405492, + ]), + xy2d: FieldElement2625([ + 10202177, 27008593, 35735631, 23979793, 34958221, 25434748, 54202543, 3852693, + 13216206, 14842320, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 51293205, 22953365, 60569911, 26295436, 60124204, 26972653, 35608016, 47320255, + 106783330, 43454614, + ]), + y_minus_x: FieldElement2625([ + 14465486, 19721101, 34974879, 18815558, 39665676, 12990491, 33046193, 15796406, + 60056998, 25514317, + ]), + xy2d: FieldElement2625([ + 30924398, 25274812, 6359015, 20738097, 16508376, 9071735, 41620263, 15413634, + 9524356, 26535554, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 12274182, 20378885, 99736504, 65323537, 73845487, 13267304, 72346523, 28444948, + 82772379, 37590215, + ]), + y_minus_x: FieldElement2625([ + 64157555, 8903984, 17349946, 601635, 50676049, 28941875, 53376124, 17665097, + 44850385, 4659090, + ]), + xy2d: FieldElement2625([ + 50192582, 28601458, 36715152, 18395610, 20774811, 15897498, 5736189, 15026997, + 64930608, 20098846, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 58249865, 31335375, 28571665, 56953346, 66634395, 23448733, 63307367, 33832526, + 23440561, 33264224, + ]), + y_minus_x: FieldElement2625([ + 10226222, 27625730, 15139955, 120818, 52241171, 5218602, 32937275, 11551483, + 50536904, 26111567, + ]), + xy2d: FieldElement2625([ + 17932739, 21117156, 43069306, 10749059, 11316803, 7535897, 22503767, 5561594, + 63462240, 3898660, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 74858752, 32584864, 50769132, 33537967, 42090752, 15122142, 65535333, 40706961, + 88940025, 34799664, + ]), + y_minus_x: FieldElement2625([ + 26958440, 18896406, 4314585, 8346991, 61431100, 11960071, 34519569, 32934396, + 36706772, 16838219, + ]), + xy2d: FieldElement2625([ + 54942968, 9166946, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, + 44770839, 13987524, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 109867800, 7778773, 88224864, 49127028, 62275597, 28196653, 62807965, 28429792, + 59639082, 30696363, + ]), + y_minus_x: FieldElement2625([ + 9681908, 26817309, 35157219, 13591837, 60225043, 386949, 31622781, 6439245, + 52527852, 4091396, + ]), + xy2d: FieldElement2625([ + 58682418, 1470726, 38999185, 31957441, 3978626, 28430809, 47486180, 12092162, + 29077877, 18812444, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 72378032, 26694705, 120987516, 25533715, 25932562, 35317984, 61502753, + 28048550, 47091016, 2357888, + ]), + y_minus_x: FieldElement2625([ + 32264008, 18146780, 61721128, 32394338, 65017541, 29607531, 23104803, 20684524, + 5727337, 189038, + ]), + xy2d: FieldElement2625([ + 14609104, 24599962, 61108297, 16931650, 52531476, 25810533, 40363694, 10942114, + 41219933, 18669734, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 87622345, 39112362, 51504250, 41383962, 93522806, 31535027, 45729895, 41026212, + 13913676, 28416557, + ]), + y_minus_x: FieldElement2625([ + 41534488, 11967825, 29233242, 12948236, 60354399, 4713226, 58167894, 14059179, + 12878652, 8511905, + ]), + xy2d: FieldElement2625([ + 41452044, 3393630, 64153449, 26478905, 64858154, 9366907, 36885446, 6812973, + 5568676, 30426776, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 78738868, 12144453, 69225203, 47160468, 94487748, 49231348, 49700110, 20050058, + 119822531, 8070816, + ]), + y_minus_x: FieldElement2625([ + 27117677, 23547054, 35826092, 27984343, 1127281, 12772488, 37262958, 10483305, + 55556115, 32525717, + ]), + xy2d: FieldElement2625([ + 10637467, 27866368, 5674780, 1072708, 40765276, 26572129, 65424888, 9177852, + 39615702, 15431202, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 87633990, 44446997, 121475255, 12779441, 104724694, 16150073, 105977209, + 14943140, 52052074, 25618500, + ]), + y_minus_x: FieldElement2625([ + 37084402, 5626925, 66557297, 23573344, 753597, 11981191, 25244767, 30314666, + 63752313, 9594023, + ]), + xy2d: FieldElement2625([ + 43356201, 2636869, 61944954, 23450613, 585133, 7877383, 11345683, 27062142, + 13352334, 22577348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 65177046, 28146973, 70413512, 54223994, 84124668, 62231772, 104433876, + 25801948, 53893326, 33235227, + ]), + y_minus_x: FieldElement2625([ + 20239939, 6607058, 6203985, 3483793, 48721888, 32775202, 46385121, 15077869, + 44358105, 14523816, + ]), + xy2d: FieldElement2625([ + 27406023, 27512775, 27423595, 29057038, 4996213, 10002360, 38266833, 29008937, + 36936121, 28748764, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 78483087, 12660714, 17861383, 21013599, 78044431, 34653658, 53222787, 24462691, + 106490683, 44912934, + ]), + y_minus_x: FieldElement2625([ + 54378055, 10311866, 1510375, 10778093, 64989409, 24408729, 32676002, 11149336, + 40985213, 4985767, + ]), + xy2d: FieldElement2625([ + 48012542, 341146, 60911379, 33315398, 15756972, 24757770, 66125820, 13794113, + 47694557, 17933176, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 73598907, 45494717, 25495922, 59382504, 75777235, 24803115, 70476466, 40524436, + 65417798, 58104073, + ]), + y_minus_x: FieldElement2625([ + 1656478, 13457317, 15370807, 6364910, 13605745, 8362338, 47934242, 28078708, + 50312267, 28522993, + ]), + xy2d: FieldElement2625([ + 44835530, 20030007, 67044178, 29220208, 48503227, 22632463, 46537798, 26546453, + 67009010, 23317098, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 84856310, 43593691, 86477162, 29503840, 46478228, 51067577, 99101545, 17696455, + 104957364, 28042459, + ]), + y_minus_x: FieldElement2625([ + 31932008, 28568291, 47496481, 16366579, 22023614, 88450, 11371999, 29810185, + 4882241, 22927527, + ]), + xy2d: FieldElement2625([ + 29796488, 37186, 19818052, 10115756, 55279832, 3352735, 18551198, 3272828, + 61917932, 29392022, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 12501267, 4044383, 58495907, 53716478, 101787674, 38691029, 47878485, 30024734, + 330069, 29895023, + ]), + y_minus_x: FieldElement2625([ + 6384877, 2899513, 17807477, 7663917, 64749976, 12363164, 25366522, 24980540, + 66837568, 12071498, + ]), + xy2d: FieldElement2625([ + 58743349, 29511910, 25133447, 29037077, 60897836, 2265926, 34339246, 1936674, + 61949167, 3829362, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 28425947, 27718999, 66531773, 28857233, 120000172, 40425360, 75030413, + 26986644, 26333139, 47822096, + ]), + y_minus_x: FieldElement2625([ + 56041645, 11871230, 27385719, 22994888, 62522949, 22365119, 10004785, 24844944, + 45347639, 8930323, + ]), + xy2d: FieldElement2625([ + 45911060, 17158396, 25654215, 31829035, 12282011, 11008919, 1541940, 4757911, + 40617363, 17145491, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 80646107, 25794941, 113612887, 44516357, 61186043, 20336366, 53952279, + 39771685, 118274028, 47369420, + ]), + y_minus_x: FieldElement2625([ + 49686272, 15157789, 18705543, 29619, 24409717, 33293956, 27361680, 9257833, + 65152338, 31777517, + ]), + xy2d: FieldElement2625([ + 42063564, 23362465, 15366584, 15166509, 54003778, 8423555, 37937324, 12361134, + 48422886, 4578289, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 91688613, 3711569, 68451186, 22374305, 107212592, 47679386, 44564334, 14074918, + 21964432, 41789689, + ]), + y_minus_x: FieldElement2625([ + 60580251, 31142934, 9442965, 27628844, 12025639, 32067012, 64127349, 31885225, + 13006805, 2355433, + ]), + xy2d: FieldElement2625([ + 50803946, 19949172, 60476436, 28412082, 16974358, 22643349, 27202043, 1719366, + 1141648, 20758196, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54244901, 53888877, 58790596, 56090772, 60298717, 28710537, 13475065, 30420460, + 32674894, 47269477, + ]), + y_minus_x: FieldElement2625([ + 11423316, 28086373, 32344215, 8962751, 24989809, 9241752, 53843611, 16086211, + 38367983, 17912338, + ]), + xy2d: FieldElement2625([ + 65699196, 12530727, 60740138, 10847386, 19531186, 19422272, 55399715, 7791793, + 39862921, 4383346, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 38137947, 38825878, 65842854, 23817442, 121762491, 50287029, 62246456, + 62202414, 27193555, 39799623, + ]), + y_minus_x: FieldElement2625([ + 51914908, 5362277, 65324971, 2695833, 4960227, 12840725, 23061898, 3260492, + 22510453, 8577507, + ]), + xy2d: FieldElement2625([ + 54476394, 11257345, 34415870, 13548176, 66387860, 10879010, 31168030, 13952092, + 37537372, 29918525, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 70986166, 23981692, 99525555, 38959755, 56104456, 19897796, 70868632, 45489751, + 72720723, 41718449, + ]), + y_minus_x: FieldElement2625([ + 50833043, 14667796, 15906460, 12155291, 44997715, 24514713, 32003001, 24722143, + 5773084, 25132323, + ]), + xy2d: FieldElement2625([ + 43320746, 25300131, 1950874, 8937633, 18686727, 16459170, 66203139, 12376319, + 31632953, 190926, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 109624102, 17415545, 58684872, 13378745, 81271271, 6901327, 58820115, 38062995, + 41767308, 29926903, + ]), + y_minus_x: FieldElement2625([ + 8884438, 27670423, 6023973, 10104341, 60227295, 28612898, 18722940, 18768427, + 65436375, 827624, + ]), + xy2d: FieldElement2625([ + 34388281, 17265135, 34605316, 7101209, 13354605, 2659080, 65308289, 19446395, + 42230385, 1541285, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 70010192, 32436744, 70989239, 57049475, 116596786, 29941649, 45306746, + 29986950, 87565708, 31669398, + ]), + y_minus_x: FieldElement2625([ + 27019610, 12299467, 53450576, 31951197, 54247203, 28692960, 47568713, 28538373, + 29439640, 15138866, + ]), + xy2d: FieldElement2625([ + 21536104, 26928012, 34661045, 22864223, 44700786, 5175813, 61688824, 17193268, + 7779327, 109896, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97388589, 48203181, 59063992, 39979989, 80748484, 32810922, 28698389, 45734550, + 23177718, 33000357, + ]), + y_minus_x: FieldElement2625([ + 26572828, 3405927, 35407164, 12890904, 47843196, 5335865, 60615096, 2378491, + 4439158, 20275085, + ]), + xy2d: FieldElement2625([ + 44392139, 3489069, 57883598, 33221678, 18875721, 32414337, 14819433, 20822905, + 49391106, 28092994, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62052362, 50120982, 83062524, 37322183, 56672364, 49181491, 66287909, 35731656, + 75658945, 18440266, + ]), + y_minus_x: FieldElement2625([ + 48635543, 16596774, 66727204, 15663610, 22860960, 15585581, 39264755, 29971692, + 43848403, 25125843, + ]), + xy2d: FieldElement2625([ + 34628313, 15707274, 58902952, 27902350, 29464557, 2713815, 44383727, 15860481, + 45206294, 1494192, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 47546754, 53021470, 41524990, 24254879, 80236705, 34314140, 21923481, 16529112, + 75851568, 46521448, + ]), + y_minus_x: FieldElement2625([ + 38643965, 1553204, 32536856, 23080703, 42417258, 33148257, 58194238, 30620535, + 37205105, 15553882, + ]), + xy2d: FieldElement2625([ + 21877890, 3230008, 9881174, 10539357, 62311749, 2841331, 11543572, 14513274, + 19375923, 20906471, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 75941133, 52613378, 80362373, 38692006, 72146734, 37633208, 24880817, 60886148, + 69971515, 9455042, + ]), + y_minus_x: FieldElement2625([ + 29306751, 5123106, 20245049, 19404543, 9592565, 8447059, 65031740, 30564351, + 15511448, 4789663, + ]), + xy2d: FieldElement2625([ + 46429108, 7004546, 8824831, 24119455, 63063159, 29803695, 61354101, 108892, + 23513200, 16652362, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 100961536, 37699212, 62632834, 26975308, 77878902, 26398889, 60458447, + 54172563, 115898528, 43767290, + ]), + y_minus_x: FieldElement2625([ + 2756062, 8598110, 7383731, 26694540, 22312758, 32449420, 21179800, 2600940, + 57120566, 21047965, + ]), + xy2d: FieldElement2625([ + 42463153, 13317461, 36659605, 17900503, 21365573, 22684775, 11344423, 864440, + 64609187, 16844368, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 107784906, 6148327, 49924452, 19080277, 85891792, 33278434, 44547329, 33765731, + 69828620, 38495428, + ]), + y_minus_x: FieldElement2625([ + 65784982, 3911312, 60160120, 14759764, 37081714, 7851206, 21690126, 8518463, + 26699843, 5276295, + ]), + xy2d: FieldElement2625([ + 53958991, 27125364, 9396248, 365013, 24703301, 23065493, 1321585, 149635, + 51656090, 7159368, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77096625, 30149672, 84616825, 43059961, 76840398, 31388917, 89464872, 41866607, + 89586081, 25151046, + ]), + y_minus_x: FieldElement2625([ + 18155857, 17049442, 19744715, 9006923, 15154154, 23015456, 24256459, 28689437, + 44560690, 9334108, + ]), + xy2d: FieldElement2625([ + 2986088, 28642539, 10776627, 30080588, 10620589, 26471229, 45695018, 14253544, + 44521715, 536905, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 71486582, 41670267, 91675941, 15495313, 78733938, 46619030, 74499414, 44144056, + 77946923, 51688439, + ]), + y_minus_x: FieldElement2625([ + 47766460, 867879, 9277171, 30335973, 52677291, 31567988, 19295825, 17757482, + 6378259, 699185, + ]), + xy2d: FieldElement2625([ + 7895007, 4057113, 60027092, 20476675, 49222032, 33231305, 66392824, 15693154, + 62063800, 20180469, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 59371282, 27685029, 119651408, 26147511, 78494517, 46756047, 31730677, + 22591592, 63190227, 23885106, + ]), + y_minus_x: FieldElement2625([ + 10188286, 17783598, 59772502, 13427542, 22223443, 14896287, 30743455, 7116568, + 45322357, 5427592, + ]), + xy2d: FieldElement2625([ + 696102, 13206899, 27047647, 22922350, 15285304, 23701253, 10798489, 28975712, + 19236242, 12477404, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 55879406, 44798227, 50054593, 25513566, 66320635, 58940896, 63211193, 44734935, + 43939347, 41288075, + ]), + y_minus_x: FieldElement2625([ + 17800790, 19518253, 40108434, 21787760, 23887826, 3149671, 23466177, 23016261, + 10322026, 15313801, + ]), + xy2d: FieldElement2625([ + 26246234, 11968874, 32263343, 28085704, 6830754, 20231401, 51314159, 33452449, + 42659621, 10890803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 35743198, 43825794, 54448238, 27287163, 83799070, 54046319, 119235514, + 50039361, 92289660, 28219547, + ]), + y_minus_x: FieldElement2625([ + 66522290, 10376443, 34522450, 22268075, 19801892, 10997610, 2276632, 9482883, + 316878, 13820577, + ]), + xy2d: FieldElement2625([ + 57226037, 29044064, 64993357, 16457135, 56008783, 11674995, 30756178, 26039378, + 30696929, 29841583, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 100097781, 23951019, 12499365, 41465219, 56491606, 21622917, 59766047, + 57123466, 34759345, 7392472, + ]), + y_minus_x: FieldElement2625([ + 58253184, 15927860, 9866406, 29905021, 64711949, 16898650, 36699387, 24419436, + 25112946, 30627788, + ]), + xy2d: FieldElement2625([ + 64604801, 33117465, 25621773, 27875660, 15085041, 28074555, 42223985, 20028237, + 5537437, 19640113, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 55883261, 2320284, 57524584, 10149186, 100773065, 5808646, 119341477, 31824763, + 98343453, 39645030, + ]), + y_minus_x: FieldElement2625([ + 57475529, 116425, 26083934, 2897444, 60744427, 30866345, 609720, 15878753, + 60138459, 24519663, + ]), + xy2d: FieldElement2625([ + 39351007, 247743, 51914090, 24551880, 23288160, 23542496, 43239268, 6503645, + 20650474, 1804084, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 106627923, 49010854, 76081380, 42024039, 82749485, 37994278, 70230858, + 56779150, 94951478, 33352103, + ]), + y_minus_x: FieldElement2625([ + 51801891, 2839643, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, + 55733782, 12714368, + ]), + xy2d: FieldElement2625([ + 20807691, 26283607, 29286140, 11421711, 39232341, 19686201, 45881388, 1035545, + 47375635, 12796919, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 79185725, 52807577, 58323861, 21705509, 42096072, 49955115, 49517368, 20654993, + 70589528, 51926048, + ]), + y_minus_x: FieldElement2625([ + 34747315, 5457596, 28548107, 7833186, 7303070, 21600887, 42745799, 17632556, + 33734809, 2771024, + ]), + xy2d: FieldElement2625([ + 45719598, 421931, 26597266, 6860826, 22486084, 26817260, 49971378, 29344205, + 42556581, 15673396, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 46924223, 35892647, 19788684, 57487908, 63107597, 24813538, 46837679, 38287685, + 70836007, 20619983, + ]), + y_minus_x: FieldElement2625([ + 6120100, 814863, 55314462, 32931715, 6812204, 17806661, 2019593, 7975683, + 31123697, 22595451, + ]), + xy2d: FieldElement2625([ + 30069250, 22119100, 30434653, 2958439, 18399564, 32578143, 12296868, 9204260, + 50676426, 9648164, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 32705413, 32003455, 97814521, 41005496, 55303257, 43186244, 70414129, 38803035, + 108209395, 22176929, + ]), + y_minus_x: FieldElement2625([ + 17219846, 2375039, 35537917, 27978816, 47649184, 9219902, 294711, 15298639, + 2662509, 17257359, + ]), + xy2d: FieldElement2625([ + 65935918, 25995736, 62742093, 29266687, 45762450, 25120105, 32087528, 32331655, + 32247247, 19164571, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 14312609, 34775988, 17395389, 58408721, 62163121, 58424228, 106019982, + 23916613, 51081240, 20175586, + ]), + y_minus_x: FieldElement2625([ + 65680039, 23875441, 57873182, 6549686, 59725795, 33085767, 23046501, 9803137, + 17597934, 2346211, + ]), + xy2d: FieldElement2625([ + 18510781, 15337574, 26171504, 981392, 44867312, 7827555, 43617730, 22231079, + 3059832, 21771562, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77250443, 39637338, 84938156, 31606788, 76938955, 13613135, 41552228, 28009845, + 33606651, 37146527, + ]), + y_minus_x: FieldElement2625([ + 33114149, 17665080, 40583177, 20211034, 33076704, 8716171, 1151462, 1521897, + 66126199, 26716628, + ]), + xy2d: FieldElement2625([ + 34169699, 29298616, 23947180, 33230254, 34035889, 21248794, 50471177, 3891703, + 26353178, 693168, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97483084, 35150011, 117333688, 46741361, 71709207, 33961335, 76694157, + 33153763, 31375463, 47924397, + ]), + y_minus_x: FieldElement2625([ + 52738210, 25781902, 1510300, 6434173, 48324075, 27291703, 32732229, 20445593, + 17901440, 16011505, + ]), + xy2d: FieldElement2625([ + 18171223, 21619806, 54608461, 15197121, 56070717, 18324396, 47936623, 17508055, + 8764034, 12309598, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 73084753, 28311243, 47649501, 23872684, 55567586, 14015781, 110551971, + 34782749, 17544095, 22960650, + ]), + y_minus_x: FieldElement2625([ + 5811932, 31839139, 3442886, 31285122, 48741515, 25194890, 49064820, 18144304, + 61543482, 12348899, + ]), + xy2d: FieldElement2625([ + 35709185, 11407554, 25755363, 6891399, 63851926, 14872273, 42259511, 8141294, + 56476330, 32968952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 121542424, 34248456, 62032718, 46854775, 81124121, 19103037, 124519055, + 22225380, 30944592, 1130208, + ]), + y_minus_x: FieldElement2625([ + 8247747, 26843490, 40546482, 25845122, 52706924, 18905521, 4652151, 2488540, + 23550156, 33283200, + ]), + xy2d: FieldElement2625([ + 17294297, 29765994, 7026747, 15626851, 22990044, 113481, 2267737, 27646286, + 66700045, 33416712, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 83199930, 17300505, 85708115, 40895109, 69246500, 32332774, 63744702, 48105367, + 70369388, 26388160, + ]), + y_minus_x: FieldElement2625([ + 62198760, 20221544, 18550886, 10864893, 50649539, 26262835, 44079994, 20349526, + 54360141, 2701325, + ]), + xy2d: FieldElement2625([ + 58534169, 16099414, 4629974, 17213908, 46322650, 27548999, 57090500, 9276970, + 11329923, 1862132, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 14763057, 17650824, 103299457, 3689865, 70620756, 43867957, 45157775, 45773662, + 58070900, 32614131, + ]), + y_minus_x: FieldElement2625([ + 8894987, 30108338, 6150752, 3013931, 301220, 15693451, 35127648, 30644714, + 51670695, 11595569, + ]), + xy2d: FieldElement2625([ + 15214943, 3537601, 40870142, 19495559, 4418656, 18323671, 13947275, 10730794, + 53619402, 29190761, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64570539, 41237224, 99867876, 33817540, 104232996, 25598978, 111885603, + 23365795, 68085971, 34254425, + ]), + y_minus_x: FieldElement2625([ + 54642373, 4195083, 57897332, 550903, 51543527, 12917919, 19118110, 33114591, + 36574330, 19216518, + ]), + xy2d: FieldElement2625([ + 31788442, 19046775, 4799988, 7372237, 8808585, 18806489, 9408236, 23502657, + 12493931, 28145115, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41428258, 5260743, 47873055, 27269961, 63412921, 16566086, 94327144, 36161552, + 29375954, 6024730, + ]), + y_minus_x: FieldElement2625([ + 842132, 30759739, 62345482, 24831616, 26332017, 21148791, 11831879, 6985184, + 57168503, 2854095, + ]), + xy2d: FieldElement2625([ + 62261602, 25585100, 2516241, 27706719, 9695690, 26333246, 16512644, 960770, + 12121869, 16648078, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 51890193, 48221527, 53772634, 35568148, 97707150, 33090294, 35603941, 25672367, + 20237805, 36392843, + ]), + y_minus_x: FieldElement2625([ + 47820798, 4453151, 15298546, 17376044, 22115042, 17581828, 12544293, 20083975, + 1068880, 21054527, + ]), + xy2d: FieldElement2625([ + 57549981, 17035596, 33238497, 13506958, 30505848, 32439836, 58621956, 30924378, + 12521377, 4845654, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 106019188, 44298538, 64150483, 43754095, 74868174, 54020263, 70518210, + 32681031, 127735421, 20668560, + ]), + y_minus_x: FieldElement2625([ + 43547042, 6230155, 46726851, 10655313, 43068279, 21933259, 10477733, 32314216, + 63995636, 13974497, + ]), + xy2d: FieldElement2625([ + 12966261, 15550616, 35069916, 31939085, 21025979, 32924988, 5642324, 7188737, + 18895762, 12629579, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 14741860, 18607545, 89286071, 21833194, 68388604, 41613031, 11758139, 34343875, + 32195180, 37450109, + ]), + y_minus_x: FieldElement2625([ + 10758205, 15755439, 62598914, 9243697, 62229442, 6879878, 64904289, 29988312, + 58126794, 4429646, + ]), + xy2d: FieldElement2625([ + 64654951, 15725972, 46672522, 23143759, 61304955, 22514211, 59972993, 21911536, + 18047435, 18272689, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41935825, 55801698, 29759954, 45331216, 111955344, 51288407, 78101976, + 54258026, 49488161, 57700395, + ]), + y_minus_x: FieldElement2625([ + 21987233, 700364, 42603816, 14972007, 59334599, 27836036, 32155025, 2581431, + 37149879, 8773374, + ]), + xy2d: FieldElement2625([ + 41540495, 454462, 53896929, 16126714, 25240068, 8594567, 20656846, 12017935, + 59234475, 19634276, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 73137027, 39817509, 103205921, 55807152, 66289943, 36016203, 102376553, + 61640820, 65387074, 30777706, + ]), + y_minus_x: FieldElement2625([ + 54829870, 16624276, 987579, 27631834, 32908202, 1248608, 7719845, 29387734, + 28408819, 6816612, + ]), + xy2d: FieldElement2625([ + 56750770, 25316602, 19549650, 21385210, 22082622, 16147817, 20613181, 13982702, + 56769294, 5067942, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 36602859, 29732664, 79183544, 13582411, 47230892, 35998382, 47389577, 12746131, + 72440074, 57002919, + ]), + y_minus_x: FieldElement2625([ + 30528792, 3601899, 65151774, 4619784, 39747042, 18118043, 24180792, 20984038, + 27679907, 31905504, + ]), + xy2d: FieldElement2625([ + 9402385, 19597367, 32834042, 10838634, 40528714, 20317236, 26653273, 24868867, + 22611443, 20839026, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 89299435, 34672460, 22736440, 48684895, 103757035, 27563109, 86298488, + 62459921, 71963721, 40176570, + ]), + y_minus_x: FieldElement2625([ + 58798126, 30600981, 58846284, 30166382, 56707132, 33282502, 13424425, 29987205, + 26404408, 13001963, + ]), + xy2d: FieldElement2625([ + 35867026, 18138731, 64114613, 8939345, 11562230, 20713762, 41044498, 21932711, + 51703708, 11020692, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 68974887, 59159374, 59210213, 23253421, 12483314, 47031979, 70284499, 21130268, + 28761761, 34961166, + ]), + y_minus_x: FieldElement2625([ + 66660290, 31776765, 13018550, 3194501, 57528444, 22392694, 24760584, 29207344, + 25577410, 20175752, + ]), + xy2d: FieldElement2625([ + 42818486, 4759344, 66418211, 31701615, 2066746, 10693769, 37513074, 9884935, + 57739938, 4745409, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 57967561, 39604145, 47577802, 29213020, 102956929, 43498706, 51646855, + 55797011, 78040786, 21622500, + ]), + y_minus_x: FieldElement2625([ + 50547351, 14112679, 59096219, 4817317, 59068400, 22139825, 44255434, 10856640, + 46638094, 13434653, + ]), + xy2d: FieldElement2625([ + 22759470, 23480998, 50342599, 31683009, 13637441, 23386341, 1765143, 20900106, + 28445306, 28189722, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29875044, 46048045, 69904399, 63322533, 68819482, 48735613, 56913146, 24765756, + 9074233, 34721612, + ]), + y_minus_x: FieldElement2625([ + 40903181, 11014232, 57266213, 30918946, 40200743, 7532293, 48391976, 24018933, + 3843902, 9367684, + ]), + xy2d: FieldElement2625([ + 56139269, 27150720, 9591133, 9582310, 11349256, 108879, 16235123, 8601684, + 66969667, 4242894, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 89201818, 53917740, 65066069, 21585919, 99295616, 55591475, 60534521, 36025091, + 106800361, 16625499, + ]), + y_minus_x: FieldElement2625([ + 56051142, 3042015, 13770083, 24296510, 584235, 33009577, 59338006, 2602724, + 39757248, 14247412, + ]), + xy2d: FieldElement2625([ + 6314156, 23289540, 34336361, 15957556, 56951134, 168749, 58490057, 14290060, + 27108877, 32373552, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 58522248, 26383465, 80350645, 44514587, 34117848, 19759835, 100656839, + 22495542, 107069276, 34536304, + ]), + y_minus_x: FieldElement2625([ + 22833421, 9293594, 34459416, 19935764, 57971897, 14756818, 44180005, 19583651, + 56629059, 17356469, + ]), + xy2d: FieldElement2625([ + 59340277, 3326785, 38997067, 10783823, 19178761, 14905060, 22680049, 13906969, + 51175174, 3797898, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 88830182, 29341685, 54902740, 42864613, 63226624, 19901321, 90849087, 30845199, + 87600846, 59066711, + ]), + y_minus_x: FieldElement2625([ + 9209251, 18419377, 53852306, 27386633, 66377847, 15289672, 25947805, 15286587, + 30997318, 26851369, + ]), + xy2d: FieldElement2625([ + 7392013, 16618386, 23946583, 25514540, 53843699, 32020573, 52911418, 31232855, + 17649997, 33304352, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 57807757, 52915036, 97718388, 30504888, 41933794, 32270679, 51867297, 24028707, + 64875610, 41216577, + ]), + y_minus_x: FieldElement2625([ + 49550191, 1763593, 33994528, 15908609, 37067994, 21380136, 7335079, 25082233, + 63934189, 3440182, + ]), + xy2d: FieldElement2625([ + 47219164, 27577423, 42997570, 23865561, 10799742, 16982475, 40449, 29122597, + 4862399, 1133, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 34252636, 25680474, 61686474, 48415381, 50789832, 41510573, 74366924, 33866292, + 36513872, 26175010, + ]), + y_minus_x: FieldElement2625([ + 63335436, 31988495, 28985339, 7499440, 24445838, 9325937, 29727763, 16527196, + 18278453, 15405622, + ]), + xy2d: FieldElement2625([ + 62726958, 8508651, 47210498, 29880007, 61124410, 15149969, 53795266, 843522, + 45233802, 13626196, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69390312, 20067376, 56193445, 30944521, 68988221, 49718638, 56324981, 37508223, + 80449702, 15928662, + ]), + y_minus_x: FieldElement2625([ + 31727126, 26374577, 48671360, 25270779, 2875792, 17164102, 41838969, 26539605, + 43656557, 5964752, + ]), + xy2d: FieldElement2625([ + 4100401, 27594980, 49929526, 6017713, 48403027, 12227140, 40424029, 11344143, + 2538215, 25983677, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 57675240, 6123112, 78268667, 31397823, 97125143, 48520672, 46633880, 35039852, + 66479607, 17595569, + ]), + y_minus_x: FieldElement2625([ + 40304287, 4260918, 11851389, 9658551, 35091757, 16367491, 46903439, 20363143, + 11659921, 22439314, + ]), + xy2d: FieldElement2625([ + 26180377, 10015009, 36264640, 24973138, 5418196, 9480663, 2231568, 23384352, + 33100371, 32248261, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82229958, 28352560, 56718958, 48982252, 39598926, 17561924, 88779810, 38041106, + 61177053, 19088051, + ]), + y_minus_x: FieldElement2625([ + 16166467, 24070699, 56004733, 6023907, 35182066, 32189508, 2340059, 17299464, + 56373093, 23514607, + ]), + xy2d: FieldElement2625([ + 28042865, 29997343, 54982337, 12259705, 63391366, 26608532, 6766452, 24864833, + 18036435, 5803270, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 66291264, 40318343, 78912424, 35140016, 78067310, 30883266, 23855390, 4598332, + 60949433, 19436993, + ]), + y_minus_x: FieldElement2625([ + 36077558, 19298237, 17332028, 31170912, 31312681, 27587249, 696308, 50292, + 47013125, 11763583, + ]), + xy2d: FieldElement2625([ + 66514282, 31040148, 34874710, 12643979, 12650761, 14811489, 665117, 20940800, + 47335652, 22840869, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97573435, 55845991, 62981386, 20819953, 86944190, 60003250, 109821551, + 35630203, 50088706, 34546902, + ]), + y_minus_x: FieldElement2625([ + 18357166, 26559999, 7766381, 16342475, 37783946, 411173, 14578841, 8080033, + 55534529, 22952821, + ]), + xy2d: FieldElement2625([ + 19598397, 10334610, 12555054, 2555664, 18821899, 23214652, 21873262, 16014234, + 26224780, 16452269, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 36884920, 5145195, 73053412, 49940397, 71085598, 35564328, 122839923, 25936244, + 46575034, 37253081, + ]), + y_minus_x: FieldElement2625([ + 14187449, 3448569, 56472628, 22743496, 44444983, 30120835, 7268409, 22663988, + 27394300, 12015369, + ]), + xy2d: FieldElement2625([ + 19695742, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, 32241655, + 53849736, 30151970, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97968948, 12735207, 65220619, 28854697, 50133957, 35811371, 126051714, + 45852742, 58558339, 23160969, + ]), + y_minus_x: FieldElement2625([ + 61389038, 22309106, 65198214, 15569034, 26642876, 25966672, 61319509, 18435777, + 62132699, 12651792, + ]), + xy2d: FieldElement2625([ + 64260450, 9953420, 11531313, 28271553, 26895122, 20857343, 53990043, 17036529, + 9768697, 31021214, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 109498250, 35449081, 66821165, 28850346, 82457582, 25397901, 32767512, + 46319882, 72048958, 44232657, + ]), + y_minus_x: FieldElement2625([ + 18860224, 15980149, 48121624, 31991861, 40875851, 22482575, 59264981, 13944023, + 42736516, 16582018, + ]), + xy2d: FieldElement2625([ + 51604604, 4970267, 37215820, 4175592, 46115652, 31354675, 55404809, 15444559, + 56105103, 7989036, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 98599278, 39122492, 64696060, 35736814, 34772016, 38086117, 35030594, 39754637, + 47422750, 52308692, + ]), + y_minus_x: FieldElement2625([ + 49800177, 17674491, 35586086, 33551600, 34221481, 16375548, 8680158, 17182719, + 28550067, 26697300, + ]), + xy2d: FieldElement2625([ + 38981977, 27866340, 16837844, 31733974, 60258182, 12700015, 37068883, 4364037, + 1155602, 5988841, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 88999280, 20281524, 121593716, 12154347, 59276991, 48854927, 90257846, + 29083950, 91727270, 41837612, + ]), + y_minus_x: FieldElement2625([ + 33972757, 23041680, 9975415, 6841041, 35549071, 16356535, 3070187, 26528504, + 1466168, 10740210, + ]), + xy2d: FieldElement2625([ + 65599446, 18066246, 53605478, 22898515, 32799043, 909394, 53169961, 27774712, + 34944214, 18227391, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 71069668, 19286628, 39082773, 51190812, 47704004, 46701299, 82676190, 34505938, + 63848542, 32980496, + ]), + y_minus_x: FieldElement2625([ + 24740822, 5052253, 37014733, 8961360, 25877428, 6165135, 42740684, 14397371, + 59728495, 27410326, + ]), + xy2d: FieldElement2625([ + 38220480, 3510802, 39005586, 32395953, 55870735, 22922977, 51667400, 19101303, + 65483377, 27059617, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 67902144, 24323953, 75945165, 27318724, 39747955, 31184838, 100261706, + 62223612, 57202662, 32932579, + ]), + y_minus_x: FieldElement2625([ + 5666214, 525582, 20782575, 25516013, 42570364, 14657739, 16099374, 1468826, + 60937436, 18367850, + ]), + xy2d: FieldElement2625([ + 62249590, 29775088, 64191105, 26806412, 7778749, 11688288, 36704511, 23683193, + 65549940, 23690785, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 10896313, 25834728, 67933138, 34027032, 114757419, 36564017, 25248957, + 48337770, 36527387, 17796587, + ]), + y_minus_x: FieldElement2625([ + 10566929, 12612572, 35164652, 11118702, 54475488, 12362878, 21752402, 8822496, + 24003793, 14264025, + ]), + xy2d: FieldElement2625([ + 27713843, 26198459, 56100623, 9227529, 27050101, 2504721, 23886875, 20436907, + 13958494, 27821979, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 110736080, 38421656, 39861735, 37454952, 29838368, 25342141, 102328328, + 23512649, 74449384, 51698795, + ]), + y_minus_x: FieldElement2625([ + 4646495, 25543308, 44342840, 22021777, 23184552, 8566613, 31366726, 32173371, + 52042079, 23179239, + ]), + xy2d: FieldElement2625([ + 49838347, 12723031, 50115803, 14878793, 21619651, 27356856, 27584816, 3093888, + 58265170, 3849920, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 58043933, 35657603, 92670503, 51983125, 61869038, 43137389, 99585908, 24536476, + 72111157, 18004172, + ]), + y_minus_x: FieldElement2625([ + 55051311, 22376525, 21115584, 20189277, 8808711, 21523724, 16489529, 13378448, + 41263148, 12741425, + ]), + xy2d: FieldElement2625([ + 61162478, 10645102, 36197278, 15390283, 63821882, 26435754, 24306471, 15852464, + 28834118, 25908360, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 49773097, 24447374, 109686448, 42989383, 58636779, 32971069, 54018092, + 34010272, 87570721, 39045736, + ]), + y_minus_x: FieldElement2625([ + 13669229, 17458950, 54626889, 23351392, 52539093, 21661233, 42112877, 11293806, + 38520660, 24132599, + ]), + xy2d: FieldElement2625([ + 28497909, 6272777, 34085870, 14470569, 8906179, 32328802, 18504673, 19389266, + 29867744, 24758489, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50901822, 47071627, 39309233, 19856633, 24009063, 60734973, 60741262, 53933471, + 22853427, 29542421, + ]), + y_minus_x: FieldElement2625([ + 24191359, 16712145, 53177067, 15217830, 14542237, 1646131, 18603514, 22516545, + 12876622, 31441985, + ]), + xy2d: FieldElement2625([ + 17902668, 4518229, 66697162, 30725184, 26878216, 5258055, 54248111, 608396, + 16031844, 3723494, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 105584936, 12763726, 46662418, 41131935, 33001347, 54091119, 17558840, + 59235974, 23896952, 29240187, + ]), + y_minus_x: FieldElement2625([ + 47103464, 21542479, 31520463, 605201, 2543521, 5991821, 64163800, 7229063, + 57189218, 24727572, + ]), + xy2d: FieldElement2625([ + 28816026, 298879, 38943848, 17633493, 19000927, 31888542, 54428030, 30605106, + 49057085, 31471516, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 16000882, 33209536, 70601955, 55661665, 37604267, 20394642, 79686603, 49595699, + 47393623, 7847706, + ]), + y_minus_x: FieldElement2625([ + 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, 34252933, 27035413, + 57088296, 3852847, + ]), + xy2d: FieldElement2625([ + 55678375, 15697595, 45987307, 29133784, 5386313, 15063598, 16514493, 17622322, + 29330898, 18478208, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41609110, 29175637, 51885955, 26653220, 83724594, 35606215, 70412565, 33569921, + 106668931, 45868821, + ]), + y_minus_x: FieldElement2625([ + 15683501, 27551389, 18109119, 23573784, 15337967, 27556609, 50391428, 15921865, + 16103996, 29823217, + ]), + xy2d: FieldElement2625([ + 43939021, 22773182, 13588191, 31925625, 63310306, 32479502, 47835256, 5402698, + 37293151, 23713330, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 90299521, 35939014, 34394523, 37016585, 104314072, 32025298, 55842007, 8911516, + 109011869, 36294143, + ]), + y_minus_x: FieldElement2625([ + 21374101, 30000182, 33584214, 9874410, 15377179, 11831242, 33578960, 6134906, + 4931255, 11987849, + ]), + xy2d: FieldElement2625([ + 67101132, 30575573, 50885377, 7277596, 105524, 33232381, 35628324, 13861387, + 37032554, 10117929, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 37607694, 22809559, 40945095, 13051538, 41483300, 38644074, 127892224, + 40258509, 79998882, 15728939, + ]), + y_minus_x: FieldElement2625([ + 45136504, 21783052, 66157804, 29135591, 14704839, 2695116, 903376, 23126293, + 12885166, 8311031, + ]), + xy2d: FieldElement2625([ + 49592363, 5352193, 10384213, 19742774, 7506450, 13453191, 26423267, 4384730, + 1888765, 28119028, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 108400371, 64001550, 120723127, 30371924, 98005322, 19632702, 101966083, + 20846561, 47644429, 30214188, + ]), + y_minus_x: FieldElement2625([ + 43500868, 30888657, 66582772, 4651135, 5765089, 4618330, 6092245, 14845197, + 17151279, 23700316, + ]), + xy2d: FieldElement2625([ + 42278406, 20820711, 51942885, 10367249, 37577956, 33289075, 22825804, 26467153, + 50242379, 16176524, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 43525570, 40119392, 87172552, 37352659, 129477549, 40913655, 69115045, + 23191005, 38362610, 56911354, + ]), + y_minus_x: FieldElement2625([ + 56482264, 29068029, 53788301, 28429114, 3432135, 27161203, 23632036, 31613822, + 32808309, 1099883, + ]), + xy2d: FieldElement2625([ + 15030958, 5768825, 39657628, 30667132, 60681485, 18193060, 51830967, 26745081, + 2051440, 18328567, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 63746522, 26315059, 74626753, 43379423, 90664713, 33849800, 72257261, 52954675, + 44422508, 50188091, + ]), + y_minus_x: FieldElement2625([ + 4577067, 16802144, 13249840, 18250104, 19958762, 19017158, 18559669, 22794883, + 8402477, 23690159, + ]), + xy2d: FieldElement2625([ + 38702534, 32502850, 40318708, 32646733, 49896449, 22523642, 9453450, 18574360, + 17983009, 9967138, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41346351, 40079153, 93694351, 43523701, 24709297, 34774792, 65430873, 7806336, + 84616260, 37205991, + ]), + y_minus_x: FieldElement2625([ + 56688388, 29436320, 14584638, 15971087, 51340543, 8861009, 26556809, 27979875, + 48555541, 22197296, + ]), + xy2d: FieldElement2625([ + 2839082, 14284142, 4029895, 3472686, 14402957, 12689363, 40466743, 8459446, + 61503401, 25932490, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62269556, 30018987, 76853824, 2871047, 92222842, 36741449, 109106914, 32705364, + 84366947, 25576692, + ]), + y_minus_x: FieldElement2625([ + 18164541, 22959256, 49953981, 32012014, 19237077, 23809137, 23357532, 18337424, + 26908269, 12150756, + ]), + xy2d: FieldElement2625([ + 36843994, 25906566, 5112248, 26517760, 65609056, 26580174, 43167, 28016731, + 34806789, 16215818, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 60209940, 43378825, 54804084, 29153342, 102820586, 27277595, 99683352, + 46087336, 59605791, 24879084, + ]), + y_minus_x: FieldElement2625([ + 39765323, 17038963, 39957339, 22831480, 946345, 16291093, 254968, 7168080, + 21676107, 31611404, + ]), + xy2d: FieldElement2625([ + 21260942, 25129680, 50276977, 21633609, 43430902, 3968120, 63456915, 27338965, + 63552672, 25641356, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 16544735, 46804798, 50304435, 49100673, 62525860, 46311689, 64646555, 24874095, + 48201831, 23891632, + ]), + y_minus_x: FieldElement2625([ + 64693606, 17976703, 18312302, 4964443, 51836334, 20900867, 26820650, 16690659, + 25459437, 28989823, + ]), + xy2d: FieldElement2625([ + 41964155, 11425019, 28423002, 22533875, 60963942, 17728207, 9142794, 31162830, + 60676445, 31909614, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 44004193, 39807907, 16964146, 29785560, 109103755, 54812425, 39651637, + 50764205, 73444554, 40804420, + ]), + y_minus_x: FieldElement2625([ + 36775618, 13979674, 7503222, 21186118, 55152142, 28932738, 36836594, 2682241, + 25993170, 21075909, + ]), + xy2d: FieldElement2625([ + 4364628, 5930691, 32304656, 23509878, 59054082, 15091130, 22857016, 22955477, + 31820367, 15075278, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 98987979, 24635738, 84367624, 33645057, 126175891, 28636721, 91271651, + 23903545, 116247489, 46387475, + ]), + y_minus_x: FieldElement2625([ + 19073683, 14851414, 42705695, 21694263, 7625277, 11091125, 47489674, 2074448, + 57694925, 14905376, + ]), + xy2d: FieldElement2625([ + 24483648, 21618865, 64589997, 22007013, 65555733, 15355505, 41826784, 9253128, + 27628530, 25998952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 84706452, 41895034, 86464480, 34106618, 26198469, 30377849, 71702187, 24396849, + 120106852, 48851446, + ]), + y_minus_x: FieldElement2625([ + 510886, 14337390, 35323607, 16638631, 6328095, 2713355, 46891447, 21690211, + 8683220, 2921426, + ]), + xy2d: FieldElement2625([ + 18606791, 11874196, 27155355, 28272950, 43077121, 6265445, 41930624, 32275507, + 4674689, 13890525, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 13609605, 13069022, 106845367, 20498522, 91469449, 43147405, 82086020, + 43389536, 71498550, 33842827, + ]), + y_minus_x: FieldElement2625([ + 9922506, 33035038, 13613106, 5883594, 48350519, 33120168, 54804801, 8317627, + 23388070, 16052080, + ]), + xy2d: FieldElement2625([ + 12719997, 11937594, 35138804, 28525742, 26900119, 8561328, 46953177, 21921452, + 52354592, 22741539, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 83070703, 47704840, 93825794, 32888599, 111423399, 47157999, 78938436, + 41022275, 38286735, 34483706, + ]), + y_minus_x: FieldElement2625([ + 11038231, 21972036, 39798381, 26237869, 56610336, 17246600, 43629330, 24182562, + 45715720, 2465073, + ]), + xy2d: FieldElement2625([ + 20017144, 29231206, 27915241, 1529148, 12396362, 15675764, 13817261, 23896366, + 2463390, 28932292, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50749967, 20890520, 122152544, 38550884, 65852441, 34628003, 76692421, + 12851106, 71112760, 46228148, + ]), + y_minus_x: FieldElement2625([ + 65377275, 18398561, 63845933, 16143081, 19294135, 13385325, 14741514, 24450706, + 7903885, 2348101, + ]), + xy2d: FieldElement2625([ + 24536016, 17039225, 12715591, 29692277, 1511292, 10047386, 63266518, 26425272, + 38731325, 10048126, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54486638, 27349611, 97827688, 2591311, 56491836, 12192839, 85982162, 59811773, + 34811106, 15221631, + ]), + y_minus_x: FieldElement2625([ + 40630742, 22450567, 11546243, 31701949, 9180879, 7656409, 45764914, 2095754, + 29769758, 6593415, + ]), + xy2d: FieldElement2625([ + 35114656, 30646970, 4176911, 3264766, 12538965, 32686321, 26312344, 27435754, + 30958053, 8292160, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 98538667, 53149747, 96282394, 15632447, 12174511, 64348770, 99917693, 37531617, + 93251999, 30405555, + ]), + y_minus_x: FieldElement2625([ + 22648882, 1402143, 44308880, 13746058, 7936347, 365344, 58440231, 31879998, + 63350620, 31249806, + ]), + xy2d: FieldElement2625([ + 51616947, 8012312, 64594134, 20851969, 43143017, 23300402, 65496150, 32018862, + 50444388, 8194477, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 27338047, 26047012, 59694639, 10140404, 48082437, 26964542, 94386054, 42409807, + 95681149, 36559595, + ]), + y_minus_x: FieldElement2625([ + 26287105, 4821776, 25476601, 29408529, 63344350, 17765447, 49100281, 1182478, + 41014043, 20474836, + ]), + xy2d: FieldElement2625([ + 59937691, 3178079, 23970071, 6201893, 49913287, 29065239, 45232588, 19571804, + 32208682, 32356184, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50451143, 36372074, 56822501, 14811297, 73133531, 46903936, 39793359, 56611021, + 39436277, 22014573, + ]), + y_minus_x: FieldElement2625([ + 15941010, 24148500, 45741813, 8062054, 31876073, 33315803, 51830470, 32110002, + 15397330, 29424239, + ]), + xy2d: FieldElement2625([ + 8934485, 20068965, 43822466, 20131190, 34662773, 14047985, 31170398, 32113411, + 39603297, 15087183, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 115860466, 31397939, 24524912, 16876564, 82629290, 27193655, 118715321, + 11461894, 83897392, 27685489, + ]), + y_minus_x: FieldElement2625([ + 65161459, 16013772, 21750665, 3714552, 49707082, 17498998, 63338576, 23231111, + 31322513, 21938797, + ]), + xy2d: FieldElement2625([ + 21426636, 27904214, 53460576, 28206894, 38296674, 28633461, 48833472, 18933017, + 13040861, 21441484, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 78402740, 46032517, 107081326, 48638180, 104910306, 14748870, 14555558, + 20137329, 68722574, 38451366, + ]), + y_minus_x: FieldElement2625([ + 41213962, 15323293, 58619073, 25496531, 25967125, 20128972, 2825959, 28657387, + 43137087, 22287016, + ]), + xy2d: FieldElement2625([ + 51184079, 28324551, 49665331, 6410663, 3622847, 10243618, 20615400, 12405433, + 43355834, 25118015, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 127126414, 46110638, 114026375, 9025185, 50036385, 4333800, 71487300, 35986461, + 23097948, 32988414, + ]), + y_minus_x: FieldElement2625([ + 4565804, 17528778, 20084411, 25711615, 1724998, 189254, 24767264, 10103221, + 48596551, 2424777, + ]), + xy2d: FieldElement2625([ + 366633, 21577626, 8173089, 26664313, 30788633, 5745705, 59940186, 1344108, + 63466311, 12412658, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 110215918, 41244716, 82038279, 33386174, 102006892, 53695876, 91271559, + 51782359, 63967361, 44733816, + ]), + y_minus_x: FieldElement2625([ + 18289503, 18829478, 8056944, 16430056, 45379140, 7842513, 61107423, 32067534, + 48424218, 22110928, + ]), + xy2d: FieldElement2625([ + 476239, 6601091, 60956074, 23831056, 17503544, 28690532, 27672958, 13403813, + 11052904, 5219329, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 87787372, 25178693, 34436965, 42403554, 129207969, 48129182, 98295834, + 29580701, 9014761, 58529808, + ]), + y_minus_x: FieldElement2625([ + 53464795, 23204192, 51146355, 5075807, 65594203, 22019831, 34006363, 9160279, + 8473550, 30297594, + ]), + xy2d: FieldElement2625([ + 24900749, 14435722, 17209120, 18261891, 44516588, 9878982, 59419555, 17218610, + 42540382, 11788947, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 63990690, 22159237, 53306774, 48351872, 76761311, 26708527, 47071426, 43965164, + 42540393, 32095740, + ]), + y_minus_x: FieldElement2625([ + 51449703, 16736705, 44641714, 10215877, 58011687, 7563910, 11871841, 21049238, + 48595538, 8464117, + ]), + xy2d: FieldElement2625([ + 43708233, 8348506, 52522913, 32692717, 63158658, 27181012, 14325288, 8628612, + 33313881, 25183915, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 46921853, 28586496, 89476219, 38825978, 66011746, 28765593, 109412060, + 23317576, 58168128, 61290594, + ]), + y_minus_x: FieldElement2625([ + 60160060, 31759219, 34483180, 17533252, 32635413, 26180187, 15989196, 20716244, + 28358191, 29300528, + ]), + xy2d: FieldElement2625([ + 43547083, 30755372, 34757181, 31892468, 57961144, 10429266, 50471180, 4072015, + 61757200, 5596588, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 105981130, 30164382, 79421759, 39767609, 3117141, 49632997, 29266238, 36111653, + 68877164, 15373192, + ]), + y_minus_x: FieldElement2625([ + 59865506, 30307471, 62515396, 26001078, 66980936, 32642186, 66017961, 29049440, + 42448372, 3442909, + ]), + xy2d: FieldElement2625([ + 36898293, 5124042, 14181784, 8197961, 18964734, 21615339, 22597930, 7176455, + 48523386, 13365929, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 59231455, 32054473, 75433536, 38244510, 73370723, 34444877, 24538106, 24984246, + 57419264, 30522764, + ]), + y_minus_x: FieldElement2625([ + 25008885, 22782833, 62803832, 23916421, 16265035, 15721635, 683793, 21730648, + 15723478, 18390951, + ]), + xy2d: FieldElement2625([ + 57448220, 12374378, 40101865, 26528283, 59384749, 21239917, 11879681, 5400171, + 519526, 32318556, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 22258378, 50776631, 59239045, 14613015, 44588609, 30603508, 46754982, 40870398, + 16648396, 41160072, + ]), + y_minus_x: FieldElement2625([ + 59027556, 25089834, 58885552, 9719709, 19259459, 18206220, 23994941, 28272877, + 57640015, 4763277, + ]), + xy2d: FieldElement2625([ + 45409620, 9220968, 51378240, 1084136, 41632757, 30702041, 31088446, 25789909, + 55752334, 728111, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 26047201, 55357393, 127317403, 50587064, 91200930, 9158118, 62835319, 20998873, + 104852291, 28056158, + ]), + y_minus_x: FieldElement2625([ + 17510331, 33231575, 5854288, 8403524, 17133918, 30441820, 38997856, 12327944, + 10750447, 10014012, + ]), + xy2d: FieldElement2625([ + 56796096, 3936951, 9156313, 24656749, 16498691, 32559785, 39627812, 32887699, + 3424690, 7540221, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97431206, 26590321, 78469868, 29411114, 74542167, 4989747, 127146306, 50791643, + 57864597, 48812477, + ]), + y_minus_x: FieldElement2625([ + 13054543, 30774935, 19155473, 469045, 54626067, 4566041, 5631406, 2711395, + 1062915, 28418087, + ]), + xy2d: FieldElement2625([ + 47868616, 22299832, 37599834, 26054466, 61273100, 13005410, 61042375, 12194496, + 32960380, 1459310, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 86960860, 40582355, 90778216, 43574797, 75695366, 26896524, 67503060, 27452546, + 85746866, 55933926, + ]), + y_minus_x: FieldElement2625([ + 31395515, 15098109, 26581030, 8030562, 50580950, 28547297, 9012485, 25970078, + 60465776, 28111795, + ]), + xy2d: FieldElement2625([ + 57916680, 31207054, 65111764, 4529533, 25766844, 607986, 67095642, 9677542, + 34813975, 27098423, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64664330, 33404494, 96457765, 8186664, 68982624, 12489862, 103283149, 25714738, + 59256019, 58970434, + ]), + y_minus_x: FieldElement2625([ + 51872508, 18120922, 7766469, 746860, 26346930, 23332670, 39775412, 10754587, + 57677388, 5203575, + ]), + xy2d: FieldElement2625([ + 31834314, 14135496, 66338857, 5159117, 20917671, 16786336, 59640890, 26216907, + 31809242, 7347066, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 57502122, 21680191, 87523322, 46588417, 80825387, 21862550, 86906833, 21343176, + 82301739, 31466941, + ]), + y_minus_x: FieldElement2625([ + 54445282, 31372712, 1168161, 29749623, 26747876, 19416341, 10609329, 12694420, + 33473243, 20172328, + ]), + xy2d: FieldElement2625([ + 33184999, 11180355, 15832085, 22169002, 65475192, 225883, 15089336, 22530529, + 60973201, 14480052, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 98417562, 27934433, 98139703, 31657332, 82783410, 26971548, 72605071, 13685226, + 27595050, 42291707, + ]), + y_minus_x: FieldElement2625([ + 46790012, 18404192, 10933842, 17376410, 8335351, 26008410, 36100512, 20943827, + 26498113, 66511, + ]), + xy2d: FieldElement2625([ + 22644435, 24792703, 50437087, 4884561, 64003250, 19995065, 30540765, 29267685, + 53781076, 26039336, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 106199862, 9834843, 85726071, 30873119, 63706907, 53801357, 75314402, 13585436, + 117090263, 48669869, + ]), + y_minus_x: FieldElement2625([ + 23711543, 32881517, 31206560, 25191721, 6164646, 23844445, 33572981, 32128335, + 8236920, 16492939, + ]), + xy2d: FieldElement2625([ + 43198286, 20038905, 40809380, 29050590, 25005589, 25867162, 19574901, 10071562, + 6708380, 27332008, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69210217, 28624377, 86811594, 35922006, 118790560, 34602105, 72409880, + 42883131, 29955600, 55430554, + ]), + y_minus_x: FieldElement2625([ + 3096359, 9271816, 45488000, 18032587, 52260867, 25961494, 41216721, 20918836, + 57191288, 6216607, + ]), + xy2d: FieldElement2625([ + 34493015, 338662, 41913253, 2510421, 37895298, 19734218, 24822829, 27407865, + 40341383, 7525078, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 44042196, 53123240, 83242349, 25658253, 130828162, 34333218, 66198527, + 30771936, 47722230, 45548532, + ]), + y_minus_x: FieldElement2625([ + 21691500, 19929806, 66467532, 19187410, 3285880, 30070836, 42044197, 9718257, + 59631427, 13381417, + ]), + xy2d: FieldElement2625([ + 18445390, 29352196, 14979845, 11622458, 65381754, 29971451, 23111647, 27179185, + 28535281, 15779576, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 30098034, 36644094, 124983340, 16662133, 45801924, 44862842, 53040409, + 12021729, 77064149, 17251075, + ]), + y_minus_x: FieldElement2625([ + 9734894, 18977602, 59635230, 24415696, 2060391, 11313496, 48682835, 9924398, + 20194861, 13380996, + ]), + xy2d: FieldElement2625([ + 40730762, 25589224, 44941042, 15789296, 49053522, 27385639, 65123949, 15707770, + 26342023, 10146099, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41091971, 33334488, 88448054, 33513043, 86854119, 30675731, 37471583, 35781471, + 21612325, 33008704, + ]), + y_minus_x: FieldElement2625([ + 54031477, 1184227, 23562814, 27583990, 46757619, 27205717, 25764460, 12243797, + 46252298, 11649657, + ]), + xy2d: FieldElement2625([ + 57077370, 11262625, 27384172, 2271902, 26947504, 17556661, 39943, 6114064, + 33514190, 2333242, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 112784121, 54687041, 75228644, 40774344, 45278341, 58092729, 60429112, + 54438225, 91459440, 20104430, + ]), + y_minus_x: FieldElement2625([ + 62992557, 22282898, 43222677, 4843614, 37020525, 690622, 35572776, 23147595, + 8317859, 12352766, + ]), + xy2d: FieldElement2625([ + 18200138, 19078521, 34021104, 30857812, 43406342, 24451920, 43556767, 31266881, + 20712162, 6719373, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 26656189, 39629685, 59250307, 35440503, 105873684, 37816756, 78226393, + 29791221, 26224234, 30256974, + ]), + y_minus_x: FieldElement2625([ + 49939907, 18700334, 63713187, 17184554, 47154818, 14050419, 21728352, 9493610, + 18620611, 17125804, + ]), + xy2d: FieldElement2625([ + 53785524, 13325348, 11432106, 5964811, 18609221, 6062965, 61839393, 23828875, + 36407290, 17074774, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 43248307, 55875704, 94070219, 35195292, 34695751, 16816491, 79357372, 28313792, + 80844205, 35488493, + ]), + y_minus_x: FieldElement2625([ + 25089769, 6742589, 17081145, 20148166, 21909292, 17486451, 51972569, 29789085, + 45830866, 5473615, + ]), + xy2d: FieldElement2625([ + 31883658, 25593331, 1083431, 21982029, 22828470, 13290673, 59983779, 12469655, + 29111212, 28103418, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 91353792, 52058456, 107954750, 36345970, 52111264, 50221109, 91476329, + 39943270, 56813276, 34006814, + ]), + y_minus_x: FieldElement2625([ + 41468082, 30136590, 5217915, 16224624, 19987036, 29472163, 42872612, 27639183, + 15766061, 8407814, + ]), + xy2d: FieldElement2625([ + 46701865, 13990230, 15495425, 16395525, 5377168, 15166495, 58191841, 29165478, + 59040954, 2276717, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 30157899, 46478498, 116505677, 42800183, 87003891, 36922573, 43281276, + 38650650, 89849239, 26251014, + ]), + y_minus_x: FieldElement2625([ + 2041139, 19298082, 7783686, 13876377, 41161879, 20201972, 24051123, 13742383, + 51471265, 13295221, + ]), + xy2d: FieldElement2625([ + 33338218, 25048699, 12532112, 7977527, 9106186, 31839181, 49388668, 28941459, + 62657506, 18884987, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 47063564, 39008528, 52762315, 40001577, 28862070, 35438083, 64639597, 29412551, + 74879432, 43175028, + ]), + y_minus_x: FieldElement2625([ + 23208049, 7979712, 33071466, 8149229, 1758231, 22719437, 30945527, 31860109, + 33606523, 18786461, + ]), + xy2d: FieldElement2625([ + 1439939, 17283952, 66028874, 32760649, 4625401, 10647766, 62065063, 1220117, + 30494170, 22113633, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 62071265, 20526136, 64138304, 30492664, 82749837, 26852765, 40369837, 34480481, + 65424524, 20220784, + ]), + y_minus_x: FieldElement2625([ + 13908495, 30005160, 30919927, 27280607, 45587000, 7989038, 9021034, 9078865, + 3353509, 4033511, + ]), + xy2d: FieldElement2625([ + 37445433, 18440821, 32259990, 33209950, 24295848, 20642309, 23161162, 8839127, + 27485041, 7356032, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76769853, 34259874, 79088928, 28184277, 65480320, 14661172, 60762722, 36179446, + 95539899, 50337029, + ]), + y_minus_x: FieldElement2625([ + 43269631, 25243016, 41163352, 7480957, 49427195, 25200248, 44562891, 14150564, + 15970762, 4099461, + ]), + xy2d: FieldElement2625([ + 29262576, 16756590, 26350592, 24760869, 8529670, 22346382, 13617292, 23617289, + 11465738, 8317062, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41615764, 26591503, 99609063, 24135380, 44070139, 31252209, 82007500, 37402886, + 88078197, 28396915, + ]), + y_minus_x: FieldElement2625([ + 46724414, 19206718, 48772458, 13884721, 34069410, 2842113, 45498038, 29904543, + 11177094, 14989547, + ]), + xy2d: FieldElement2625([ + 42612143, 21838415, 16959895, 2278463, 12066309, 10137771, 13515641, 2581286, + 38621356, 9930239, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 49357223, 31456605, 83653163, 54099563, 118302919, 18605349, 18345766, + 53705111, 83400343, 28240393, + ]), + y_minus_x: FieldElement2625([ + 33879670, 2553287, 32678213, 9875984, 8534129, 6889387, 57432090, 6957616, + 4368891, 9788741, + ]), + xy2d: FieldElement2625([ + 16660737, 7281060, 56278106, 12911819, 20108584, 25452756, 45386327, 24941283, + 16250551, 22443329, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 47343357, 35944957, 117666696, 14161978, 69014150, 39969338, 71798447, + 10604806, 104027325, 4782745, + ]), + y_minus_x: FieldElement2625([ + 65754325, 14736940, 59741422, 20261545, 7710541, 19398842, 57127292, 4383044, + 22546403, 437323, + ]), + xy2d: FieldElement2625([ + 31665558, 21373968, 50922033, 1491338, 48740239, 3294681, 27343084, 2786261, + 36475274, 19457415, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 52641566, 32870716, 33734756, 41002983, 19294359, 14334329, 47418233, 35909750, + 47824192, 27440058, + ]), + y_minus_x: FieldElement2625([ + 15121312, 17758270, 6377019, 27523071, 56310752, 20596586, 18952176, 15496498, + 37728731, 11754227, + ]), + xy2d: FieldElement2625([ + 64471568, 20071356, 8488726, 19250536, 12728760, 31931939, 7141595, 11724556, + 22761615, 23420291, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 16918416, 11729663, 49025285, 36577418, 103201995, 53769203, 38367677, + 21327038, 32851221, 11717399, + ]), + y_minus_x: FieldElement2625([ + 11166615, 7338049, 60386341, 4531519, 37640192, 26252376, 31474878, 3483633, + 65915689, 29523600, + ]), + xy2d: FieldElement2625([ + 66923210, 9921304, 31456609, 20017994, 55095045, 13348922, 33142652, 6546660, + 47123585, 29606055, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 101757113, 44821142, 55911756, 25655328, 31703693, 37410335, 58571732, + 20721383, 36336829, 18068118, + ]), + y_minus_x: FieldElement2625([ + 49102387, 12709067, 3991746, 27075244, 45617340, 23004006, 35973516, 17504552, + 10928916, 3011958, + ]), + xy2d: FieldElement2625([ + 60151107, 17960094, 31696058, 334240, 29576716, 14796075, 36277808, 20749251, + 18008030, 10258577, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 44660220, 49210000, 74127342, 29144428, 36794597, 32352840, 65255398, 34921551, + 92236737, 6671742, + ]), + y_minus_x: FieldElement2625([ + 29701166, 19180498, 56230743, 9279287, 67091296, 13127209, 21382910, 11042292, + 25838796, 4642684, + ]), + xy2d: FieldElement2625([ + 46678630, 14955536, 42982517, 8124618, 61739576, 27563961, 30468146, 19653792, + 18423288, 4177476, + ]), + }, + ]), + ]); + +/// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = + NafLookupTable8([ + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 93076338, 52752828, 29566454, 37215328, 54414518, 37569218, 94653489, 21800160, + 61029707, 35602036, + ]), + y_minus_x: FieldElement2625([ + 54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692, 5043384, + 19500929, 18085054, + ]), + xy2d: FieldElement2625([ + 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918, 11864899, + 42594502, 29115885, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82745136, 23865874, 24204772, 25642034, 67725840, 16869169, 94896463, 52336674, + 28944398, 32004408, + ]), + y_minus_x: FieldElement2625([ + 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576, 21778470, + 7689661, 11199574, + ]), + xy2d: FieldElement2625([ + 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774, 10017326, + 49359771, 23634074, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77970208, 11473153, 27284546, 35535607, 37044514, 46132292, 99976748, 48069538, + 118779423, 44373810, + ]), + y_minus_x: FieldElement2625([ + 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196, 12483687, + 54440373, 5581305, + ]), + xy2d: FieldElement2625([ + 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349, 13850243, + 43430843, 17738489, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 72262591, 43463716, 68832610, 30776557, 97632468, 39071304, 86589715, 38784565, + 43156424, 18378665, + ]), + y_minus_x: FieldElement2625([ + 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025, 16520125, + 30598449, 7715701, + ]), + xy2d: FieldElement2625([ + 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204, 1370707, + 29794553, 32145132, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 44589852, 26862249, 14201701, 24808930, 43598457, 42399157, 85583074, 32192981, + 54046167, 47376308, + ]), + y_minus_x: FieldElement2625([ + 60653668, 25714560, 3374701, 28813570, 40010246, 22982724, 31655027, 26342105, + 18853321, 19333481, + ]), + xy2d: FieldElement2625([ + 4566811, 20590564, 38133974, 21313742, 59506191, 30723862, 58594505, 23123294, + 2207752, 30344648, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 41954014, 62923042, 96790006, 41423232, 60254202, 24130566, 121780363, 32891430, + 103106264, 17421994, + ]), + y_minus_x: FieldElement2625([ + 25576264, 30851218, 7349803, 21739588, 16472781, 9300885, 3844789, 15725684, + 171356, 6466918, + ]), + xy2d: FieldElement2625([ + 23103977, 13316479, 9739013, 17404951, 817874, 18515490, 8965338, 19466374, + 36393951, 16193876, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 100695917, 36735143, 64714733, 47558118, 50205389, 17283591, 84347261, 38283886, + 49034350, 9256799, + ]), + y_minus_x: FieldElement2625([ + 41926547, 29380300, 32336397, 5036987, 45872047, 11360616, 22616405, 9761698, + 47281666, 630304, + ]), + xy2d: FieldElement2625([ + 53388152, 2639452, 42871404, 26147950, 9494426, 27780403, 60554312, 17593437, + 64659607, 19263131, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 63957664, 28508356, 76391577, 40420576, 102310665, 32691407, 48168288, 15033783, + 92213982, 25659555, + ]), + y_minus_x: FieldElement2625([ + 42782475, 15950225, 35307649, 18961608, 55446126, 28463506, 1573891, 30928545, + 2198789, 17749813, + ]), + xy2d: FieldElement2625([ + 64009494, 10324966, 64867251, 7453182, 61661885, 30818928, 53296841, 17317989, + 34647629, 21263748, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 17735022, 27114469, 76149336, 40765111, 43325570, 26153544, 26948151, 45905235, + 38656900, 62179684, + ]), + y_minus_x: FieldElement2625([ + 2154119, 14782993, 28737794, 11906199, 36205504, 26488101, 19338132, 16910143, + 50209922, 29794297, + ]), + xy2d: FieldElement2625([ + 29935700, 6336041, 20999566, 30405369, 13628497, 24612108, 61639745, 22359641, + 56973806, 18684690, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29792811, 31379227, 113441390, 20675662, 58452680, 54138549, 42892249, 32958636, + 31674345, 24275271, + ]), + y_minus_x: FieldElement2625([ + 7606599, 22131225, 17376912, 15235046, 32822971, 7512882, 30227203, 14344178, + 9952094, 8804749, + ]), + xy2d: FieldElement2625([ + 32575079, 3961822, 36404898, 17773250, 67073898, 1319543, 30641032, 7823672, + 63309858, 18878784, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77823924, 52933642, 26572931, 18690221, 109143683, 23989794, 79129572, 53326100, + 38888709, 55889506, + ]), + y_minus_x: FieldElement2625([ + 37146997, 554126, 63326061, 20925660, 49205290, 8620615, 53375504, 25938867, + 8752612, 31225894, + ]), + xy2d: FieldElement2625([ + 4529887, 12416158, 60388162, 30157900, 15427957, 27628808, 61150927, 12724463, + 23658330, 23690055, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 102043267, 54823614, 45810225, 19657305, 54297192, 7413280, 66851983, 39718512, + 25005048, 18002658, + ]), + y_minus_x: FieldElement2625([ + 5403481, 24654166, 61855580, 13522652, 14989680, 1879017, 43913069, 25724172, + 20315901, 421248, + ]), + xy2d: FieldElement2625([ + 34818947, 1705239, 25347020, 7938434, 51632025, 1720023, 54809726, 32655885, + 64907986, 5517607, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 88543525, 16557377, 80359887, 30047148, 91602876, 27723948, 62710290, 52707861, + 7715736, 61648232, + ]), + y_minus_x: FieldElement2625([ + 14461032, 6393639, 22681353, 14533514, 52493587, 3544717, 57780998, 24657863, + 59891807, 31628125, + ]), + xy2d: FieldElement2625([ + 60864886, 31199953, 18524951, 11247802, 43517645, 21165456, 26204394, 27268421, + 63221077, 29979135, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 97491378, 10077555, 94805128, 42472719, 30231379, 17961119, 76201413, 41182329, + 41405214, 31798052, + ]), + y_minus_x: FieldElement2625([ + 13670592, 720327, 7131696, 19360499, 66651570, 16947532, 3061924, 22871019, + 39814495, 20141336, + ]), + xy2d: FieldElement2625([ + 44847187, 28379568, 38472030, 23697331, 49441718, 3215393, 1669253, 30451034, + 62323912, 29368533, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 74923758, 35244493, 27222384, 30715870, 48444195, 28125622, 116052444, 32330148, + 92609232, 35372537, + ]), + y_minus_x: FieldElement2625([ + 39340596, 15199968, 52787715, 18781603, 18787729, 5464578, 11652644, 8722118, + 57056621, 5153960, + ]), + xy2d: FieldElement2625([ + 5733861, 14534448, 59480402, 15892910, 30737296, 188529, 491756, 17646733, + 33071791, 15771063, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 85239571, 21331573, 119690709, 30172286, 44350959, 55826224, 68258766, 16209406, + 20222151, 32139086, + ]), + y_minus_x: FieldElement2625([ + 52372801, 13847470, 52690845, 3802477, 48387139, 10595589, 13745896, 3112846, + 50361463, 2761905, + ]), + xy2d: FieldElement2625([ + 45982696, 12273933, 15897066, 704320, 31367969, 3120352, 11710867, 16405685, + 19410991, 10591627, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 82008850, 34439758, 89319886, 49124188, 34309215, 29866047, 80308709, 27738519, + 71739865, 46909287, + ]), + y_minus_x: FieldElement2625([ + 36631997, 23300851, 59535242, 27474493, 59924914, 29067704, 17551261, 13583017, + 37580567, 31071178, + ]), + xy2d: FieldElement2625([ + 22641770, 21277083, 10843473, 1582748, 37504588, 634914, 15612385, 18139122, + 59415250, 22563863, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76721854, 52814714, 41722368, 35285867, 53022548, 38255176, 93163883, 27627617, + 87963092, 33729456, + ]), + y_minus_x: FieldElement2625([ + 61915349, 11733561, 59403492, 31381562, 29521830, 16845409, 54973419, 26057054, + 49464700, 796779, + ]), + xy2d: FieldElement2625([ + 3855018, 8248512, 12652406, 88331, 2948262, 971326, 15614761, 9441028, 29507685, + 8583792, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 76968870, 14808584, 76708906, 57649718, 23400175, 24077237, 63783137, 37471119, + 56750251, 30681804, + ]), + y_minus_x: FieldElement2625([ + 33709664, 3740344, 52888604, 25059045, 46197996, 22678812, 45207164, 6431243, + 21300862, 27646257, + ]), + xy2d: FieldElement2625([ + 49811511, 9216232, 25043921, 18738174, 29145960, 3024227, 65580502, 530149, + 66809973, 22275500, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 23499366, 24936714, 38355445, 35908587, 82540167, 39280880, 46809413, 41143783, + 72530804, 49676198, + ]), + y_minus_x: FieldElement2625([ + 45162189, 23851397, 9380591, 15192763, 36034862, 15525765, 5277811, 25040629, + 33286237, 31693326, + ]), + xy2d: FieldElement2625([ + 62424427, 13336013, 49368582, 1581264, 30884213, 15048226, 66823504, 4736577, + 53805192, 29608355, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 25190215, 26304748, 58928336, 42665707, 64280342, 38580230, 61299598, 20659504, + 30387592, 32519377, + ]), + y_minus_x: FieldElement2625([ + 14480213, 17057820, 2286692, 32980967, 14693157, 22197912, 49247898, 9909859, + 236428, 16857435, + ]), + xy2d: FieldElement2625([ + 7877514, 29872867, 45886243, 25902853, 41998762, 6241604, 35694938, 15657879, + 56797932, 8609105, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54245189, 32562161, 57887697, 19509733, 45323534, 37472546, 27606727, 59528498, + 74398957, 44973176, + ]), + y_minus_x: FieldElement2625([ + 28964163, 20950093, 44929966, 26145892, 34786807, 18058153, 18187179, 27016486, + 42438836, 14869174, + ]), + xy2d: FieldElement2625([ + 55703901, 1222455, 64329400, 24533246, 11330890, 9135834, 3589529, 19555234, + 53275553, 1207212, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 33323313, 35603165, 79328585, 6017848, 71286345, 23804207, 86644124, 44008367, + 55775078, 31816581, + ]), + y_minus_x: FieldElement2625([ + 64814718, 27217688, 29891310, 4504619, 8548709, 21986323, 62140656, 12555980, + 34377058, 21436823, + ]), + xy2d: FieldElement2625([ + 49069441, 9880212, 33350825, 24576421, 24446077, 15616561, 19302117, 9370836, + 55172180, 28526191, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 95404934, 26757208, 123864063, 4572839, 69249194, 43584425, 53559055, 41742046, + 41167331, 24643278, + ]), + y_minus_x: FieldElement2625([ + 35101859, 30958612, 66105296, 3168612, 22836264, 10055966, 22893634, 13045780, + 28576558, 30704591, + ]), + xy2d: FieldElement2625([ + 59987873, 21166324, 43296694, 15387892, 39447987, 19996270, 5059183, 19972934, + 30207804, 29631666, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 67444156, 16132892, 88330413, 37924284, 68147855, 57949418, 91481571, 24889160, + 62329722, 50712214, + ]), + y_minus_x: FieldElement2625([ + 56922508, 1347520, 23300731, 27393371, 42651667, 8512932, 27610931, 24436993, + 3998295, 3835244, + ]), + xy2d: FieldElement2625([ + 16327050, 22776956, 14746360, 22599650, 23700920, 11727222, 25900154, 21823218, + 34907363, 25105813, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 59807886, 12089757, 115624210, 41476837, 67589715, 26361580, 71355762, 44268661, + 67753061, 13128476, + ]), + y_minus_x: FieldElement2625([ + 7174885, 26592113, 59892333, 6465478, 4145835, 17673606, 38764952, 22293290, + 1360980, 25805937, + ]), + xy2d: FieldElement2625([ + 40179568, 6331649, 42386021, 20205884, 15635073, 6103612, 56391180, 6789942, + 7597240, 24095312, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54776568, 36935932, 18757261, 41429535, 67215081, 34700142, 86560976, 61204154, + 26496794, 19612129, + ]), + y_minus_x: FieldElement2625([ + 46701540, 24101444, 49515651, 25946994, 45338156, 9941093, 55509371, 31298943, + 1347425, 15381335, + ]), + xy2d: FieldElement2625([ + 53576449, 26135856, 17092785, 3684747, 57829121, 27109516, 2987881, 10987137, + 52269096, 15465522, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 80033010, 26264316, 72380996, 10039544, 94605936, 30615493, 60406855, 30400829, + 120765849, 45301372, + ]), + y_minus_x: FieldElement2625([ + 35668062, 24246990, 47788280, 25128298, 37456967, 19518969, 43459670, 10724644, + 7294162, 4471290, + ]), + xy2d: FieldElement2625([ + 33813988, 3549109, 101112, 21464449, 4858392, 3029943, 59999440, 21424738, + 34313875, 1512799, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29494960, 28240930, 51093230, 28823678, 92791151, 54796794, 77571888, 37795542, + 75765856, 10649531, + ]), + y_minus_x: FieldElement2625([ + 63536751, 7572551, 62249759, 25202639, 32046232, 32318941, 29315141, 15424555, + 24706712, 28857648, + ]), + xy2d: FieldElement2625([ + 47618751, 5819839, 19528172, 20715950, 40655763, 20611047, 4960954, 6496879, + 2790858, 28045273, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 85174457, 55843901, 111946683, 31021158, 32797785, 48944265, 78338887, 31144772, + 82688001, 38470222, + ]), + y_minus_x: FieldElement2625([ + 49664705, 3638040, 57888693, 19234931, 40104182, 28143840, 28667142, 18386877, + 18584835, 3592929, + ]), + xy2d: FieldElement2625([ + 12065039, 18867394, 6430594, 17107159, 1727094, 13096957, 61520237, 27056604, + 27026997, 13543966, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 68512926, 37577278, 94695528, 14209106, 95849194, 30038709, 51818051, 20241476, + 68980056, 42251074, + ]), + y_minus_x: FieldElement2625([ + 17325298, 33376175, 65271265, 4931225, 31708266, 6292284, 23064744, 22072792, + 43945505, 9236924, + ]), + xy2d: FieldElement2625([ + 51955585, 20268063, 61151838, 26383348, 4766519, 20788033, 21173534, 27030753, + 9509140, 7790046, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 24124086, 38918775, 28620390, 10538620, 59433851, 19581010, 60862718, 43500219, + 77600721, 32213801, + ]), + y_minus_x: FieldElement2625([ + 7062127, 13930079, 2259902, 6463144, 32137099, 24748848, 41557343, 29331342, + 47345194, 13022814, + ]), + xy2d: FieldElement2625([ + 18921826, 392002, 55817981, 6420686, 8000611, 22415972, 14722962, 26246290, + 20604450, 8079345, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 67710253, 26257798, 51499391, 46550521, 30228769, 53940987, 76234206, 43362242, + 77953697, 21034392, + ]), + y_minus_x: FieldElement2625([ + 25817710, 8020883, 50134679, 21244805, 47057788, 8766556, 29308546, 22307963, + 49449920, 23874253, + ]), + xy2d: FieldElement2625([ + 11081015, 13522660, 12474691, 29260223, 48687631, 9341946, 16850694, 18637605, + 6199839, 14303642, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64518173, 19894035, 117213833, 43031641, 79641718, 39533880, 66531934, 41205092, + 117735515, 13989682, + ]), + y_minus_x: FieldElement2625([ + 6921800, 4421166, 59739491, 30510778, 43106355, 30941531, 9363541, 3394240, + 50874187, 23872585, + ]), + xy2d: FieldElement2625([ + 54293979, 23466866, 47184247, 20627378, 8313211, 5865878, 5948507, 32290343, + 52583140, 23139870, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 111574723, 24134616, 49842442, 23485580, 34844037, 45228427, 67103167, 25858409, + 38508586, 35097070, + ]), + y_minus_x: FieldElement2625([ + 19879846, 15259900, 25020018, 14261729, 22075205, 25189303, 787540, 31325033, + 62422289, 16131171, + ]), + xy2d: FieldElement2625([ + 39487053, 27893575, 34654176, 25620816, 60209846, 23603919, 8931189, 12275052, + 38626469, 33438928, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 105416367, 9568747, 62672739, 49685015, 106242995, 4547918, 18403901, 38581738, + 60829966, 33150322, + ]), + y_minus_x: FieldElement2625([ + 7950033, 25841033, 47276506, 3884935, 62418883, 2342083, 50269031, 14194015, + 27013685, 3320257, + ]), + xy2d: FieldElement2625([ + 35270691, 18076829, 46994271, 4273335, 43595882, 31742297, 58328702, 4594760, + 49180851, 18144010, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 30194115, 50068680, 49746331, 27470090, 40428285, 23271051, 70252167, 16153483, + 123511881, 27809602, + ]), + y_minus_x: FieldElement2625([ + 27113466, 6865046, 4512771, 29327742, 29021084, 7405965, 33302911, 9322435, + 4307527, 32438240, + ]), + xy2d: FieldElement2625([ + 29337813, 24673346, 10359233, 30347534, 57709483, 9930840, 60607771, 24076133, + 20985293, 22480923, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 14579237, 33467236, 85745988, 15769997, 101228358, 21649866, 82685456, 59023858, + 86175344, 24337101, + ]), + y_minus_x: FieldElement2625([ + 4472119, 14702190, 10432042, 22460027, 708461, 18783996, 34234374, 30870323, + 63796457, 10370850, + ]), + xy2d: FieldElement2625([ + 36957127, 19555637, 16244231, 24367549, 58999881, 13440043, 35147632, 8718974, + 43101064, 18487380, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 21818223, 34477173, 23913863, 22441963, 129271975, 14842154, 43035020, 9485973, + 53819529, 22318987, + ]), + y_minus_x: FieldElement2625([ + 10874834, 4351765, 66252340, 17269436, 64427034, 30735311, 5883785, 28998531, + 44403022, 26064601, + ]), + xy2d: FieldElement2625([ + 64017630, 9755550, 37507935, 22752543, 4031638, 29903925, 47267417, 32706846, + 39147952, 21635901, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 81365001, 44927611, 97395185, 43985591, 66242539, 38517499, 52937891, 37374973, + 73352483, 38476849, + ]), + y_minus_x: FieldElement2625([ + 43460763, 24260930, 21493330, 30888969, 23329454, 24545577, 58286855, 12750266, + 22391140, 26198125, + ]), + xy2d: FieldElement2625([ + 20477567, 24078713, 1674568, 4102219, 25208396, 13972305, 30389482, 19572626, + 1485666, 17679765, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 100511110, 23887606, 116505658, 30877106, 45483774, 25222431, 67931340, 37154158, + 32618865, 18610785, + ]), + y_minus_x: FieldElement2625([ + 48647066, 166413, 55454758, 8889513, 21027475, 32728181, 43100067, 4690060, + 7520989, 16421303, + ]), + xy2d: FieldElement2625([ + 14868391, 20996450, 64836606, 1042490, 27060176, 10253541, 53431276, 19516737, + 41808946, 2239538, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50228416, 29594943, 62030348, 10307368, 70970997, 20292574, 126292474, 51543890, + 67827181, 15848795, + ]), + y_minus_x: FieldElement2625([ + 5548701, 17911007, 33137864, 32764443, 31146554, 17931096, 64023370, 7290289, + 6361313, 32861205, + ]), + xy2d: FieldElement2625([ + 63374742, 30320053, 4091667, 30955480, 44819449, 2212055, 52638826, 22391938, + 38484599, 7051029, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 50485560, 7033600, 57711425, 10740562, 72347547, 42328739, 7593987, 46950560, + 85560721, 41970063, + ]), + y_minus_x: FieldElement2625([ + 40930651, 3776911, 39108529, 2508077, 19371703, 7626128, 4092943, 15778278, + 42044145, 24540103, + ]), + xy2d: FieldElement2625([ + 44128555, 8867576, 8645499, 22222278, 11497130, 4344907, 10788462, 23382703, + 3547104, 15368835, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 81786515, 51902785, 74560130, 22753403, 52379722, 41395524, 57994925, 6818020, + 57707296, 16352835, + ]), + y_minus_x: FieldElement2625([ + 21622574, 18581624, 36511951, 1212467, 36930308, 7910192, 20622927, 2438677, + 52628762, 29068327, + ]), + xy2d: FieldElement2625([ + 6797431, 2854059, 4269865, 8037366, 32016522, 15223213, 34765784, 15297582, + 3559197, 26425254, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 107761639, 61759660, 79235166, 8794359, 48418924, 60111631, 87862210, 33613219, + 68436482, 40229362, + ]), + y_minus_x: FieldElement2625([ + 52388944, 32880897, 37676257, 8253690, 32826330, 2707379, 25088512, 17182878, + 15053907, 11601568, + ]), + xy2d: FieldElement2625([ + 43894091, 25425955, 50962615, 28097648, 30129084, 13258436, 39364589, 8197601, + 58181660, 15003422, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 13470722, 47835674, 31012390, 30525035, 89789519, 50713267, 39648035, 13815677, + 94028755, 62582101, + ]), + y_minus_x: FieldElement2625([ + 54478677, 14782829, 56712503, 7094748, 41775828, 29409658, 9084386, 30179063, + 64014926, 32519086, + ]), + xy2d: FieldElement2625([ + 6314429, 20018828, 12535891, 19610611, 10074031, 28087963, 50489447, 26314252, + 24553876, 32746308, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 105768482, 46629424, 103418946, 65789027, 85765355, 28316167, 56299027, 22780838, + 122676432, 32376204, + ]), + y_minus_x: FieldElement2625([ + 5654403, 26425050, 39347935, 963424, 5032477, 19850195, 30011537, 11153401, + 63182039, 13343989, + ]), + xy2d: FieldElement2625([ + 1130444, 29814849, 40569426, 8144467, 24179188, 6267924, 63847147, 2912740, + 63870704, 29186744, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 49722534, 11073633, 52865263, 50829611, 33921405, 38614719, 32360242, 35465390, + 50107050, 45035301, + ]), + y_minus_x: FieldElement2625([ + 2003571, 2472803, 46902183, 1716406, 58609069, 15922982, 43766122, 27456369, + 33468339, 29346282, + ]), + xy2d: FieldElement2625([ + 18834217, 8245144, 29896065, 3490830, 62967493, 7220277, 146130, 18459164, + 57533060, 30070422, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 77805507, 38474121, 73459597, 18553340, 107508318, 52705654, 33655873, 27331956, + 44498407, 13768350, + ]), + y_minus_x: FieldElement2625([ + 23652128, 27647291, 43351590, 13262712, 65238054, 26296349, 11902126, 2949002, + 34445239, 25602117, + ]), + xy2d: FieldElement2625([ + 55906958, 19046111, 28501158, 28224561, 14495533, 14714956, 32929972, 2643566, + 17034893, 11645825, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 38181639, 29751709, 73650473, 17760526, 80753587, 17992258, 72670209, 41214427, + 87524152, 37630124, + ]), + y_minus_x: FieldElement2625([ + 6498441, 12053607, 10375600, 14764370, 24795955, 16159258, 57849421, 16071837, + 31008329, 3792564, + ]), + xy2d: FieldElement2625([ + 47930485, 9176956, 54248931, 8732776, 58000258, 10333519, 96092, 29273884, + 13051277, 20121493, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 54190492, 49837594, 61282066, 10734597, 67926686, 36967416, 115462142, 30339271, + 37200685, 30036936, + ]), + y_minus_x: FieldElement2625([ + 21193614, 19929501, 18841215, 29565554, 64002173, 11123558, 14111648, 6069945, + 30307604, 25935103, + ]), + xy2d: FieldElement2625([ + 58539773, 2098685, 38301131, 15844175, 41633654, 16934366, 15145895, 5543861, + 64050790, 6595361, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 34107945, 34731353, 51956038, 5614778, 79079051, 30288154, 47460410, 22186730, + 30689695, 19628976, + ]), + y_minus_x: FieldElement2625([ + 25043248, 19224237, 46048097, 32289319, 29339134, 12397721, 37385860, 12978240, + 57951631, 31419653, + ]), + xy2d: FieldElement2625([ + 46038439, 28501736, 62566522, 12609283, 35236982, 30457796, 64113609, 14800343, + 6412849, 6276813, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 124528774, 39505727, 83050803, 41361190, 116071796, 37845759, 61633481, 38385016, + 71255100, 31629488, + ]), + y_minus_x: FieldElement2625([ + 249426, 17196749, 35434953, 13884216, 11701636, 24553269, 51821986, 12900910, + 34844073, 16150118, + ]), + xy2d: FieldElement2625([ + 2520516, 14697628, 15319213, 22684490, 62866663, 29666431, 13872507, 7473319, + 12419515, 2958466, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 101517167, 22298305, 98222207, 59471046, 61547444, 50370568, 97111094, 42539051, + 14298448, 49873561, + ]), + y_minus_x: FieldElement2625([ + 19427905, 12004555, 9971383, 28189868, 32306269, 23648270, 34176633, 10760437, + 53354280, 5634974, + ]), + xy2d: FieldElement2625([ + 30044319, 23677863, 60273406, 14563839, 9734978, 19808149, 30899064, 30835691, + 22828539, 23633348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 25513026, 37111929, 37113703, 29589233, 77394412, 34745965, 95889446, 61766763, + 92876242, 37566563, + ]), + y_minus_x: FieldElement2625([ + 42139852, 9176396, 16274786, 33467453, 52558621, 7190768, 1490604, 31312359, + 44767199, 18491072, + ]), + xy2d: FieldElement2625([ + 4272877, 21431483, 45594743, 13027605, 59232641, 24151956, 38390319, 12906718, + 45915869, 15503563, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 29874396, 35808736, 25494239, 37976524, 43036007, 37144111, 18198811, 35141252, + 53490316, 47742788, + ]), + y_minus_x: FieldElement2625([ + 59518553, 28520621, 59946871, 29462027, 3630300, 29398589, 60425462, 24588735, + 53129947, 28399367, + ]), + xy2d: FieldElement2625([ + 18192774, 12787801, 32021061, 9158184, 48389348, 16385092, 11799402, 9492011, + 43154220, 15950102, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 68768204, 54638026, 33464925, 53430209, 66037964, 35360373, 22565155, 39168685, + 46605438, 51897954, + ]), + y_minus_x: FieldElement2625([ + 57660336, 29715319, 64414626, 32753338, 16894121, 935644, 53848937, 22684138, + 10541713, 14174330, + ]), + xy2d: FieldElement2625([ + 22888141, 12700209, 40301697, 6435658, 56329485, 5524686, 56715961, 6520808, + 15754965, 9355803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 79549820, 26746924, 54931884, 38547877, 49672847, 19708985, 52599424, 12757151, + 93328625, 39524327, + ]), + y_minus_x: FieldElement2625([ + 33888606, 13911610, 18921581, 1162763, 46616901, 13799218, 29525142, 21929286, + 59295464, 503508, + ]), + xy2d: FieldElement2625([ + 57865531, 22043577, 17998312, 3038439, 52838371, 9832208, 43311531, 660991, + 25265267, 18977724, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 64010269, 23727746, 42277281, 48089313, 102316973, 34946803, 127880577, 38411468, + 114816699, 43712746, + ]), + y_minus_x: FieldElement2625([ + 56859315, 32558245, 41017090, 22610758, 13704990, 23215119, 2475037, 32344984, + 12799418, 11135856, + ]), + xy2d: FieldElement2625([ + 1867214, 27167702, 19772099, 16925005, 15366693, 25797692, 10829276, 15372827, + 26582557, 31642714, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 57265197, 20059797, 107314987, 30587501, 60553812, 25602102, 29690666, 37127097, + 103070929, 51772159, + ]), + y_minus_x: FieldElement2625([ + 56432653, 6329655, 42770975, 4187982, 30677076, 9335071, 60103332, 14755050, + 9451294, 574767, + ]), + xy2d: FieldElement2625([ + 52859018, 2867107, 56258365, 15719081, 5959372, 8703738, 29137781, 21575537, + 20249840, 31808689, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 74749335, 47235127, 9995910, 52200224, 92069015, 8964515, 33248715, 21201554, + 57573145, 31605506, + ]), + y_minus_x: FieldElement2625([ + 56307055, 23891752, 3613811, 30787942, 49031222, 26667524, 26985478, 31973510, + 26785294, 29587427, + ]), + xy2d: FieldElement2625([ + 30891460, 5254655, 47414930, 12769216, 42912782, 11830405, 7411958, 1394027, + 18778535, 18209370, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 61227949, 26179350, 57501473, 13585864, 102855675, 40344975, 54134826, 59707765, + 74122694, 12256219, + ]), + y_minus_x: FieldElement2625([ + 5975515, 16302413, 24341148, 28270615, 18786096, 22405501, 28243950, 28328004, + 53412289, 4381960, + ]), + xy2d: FieldElement2625([ + 9394648, 8758552, 26189703, 16642536, 35993528, 5117040, 5977877, 13955594, + 19244020, 24493735, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 111388362, 51822507, 30193028, 3993472, 110736308, 44014764, 107346699, 48464072, + 92830877, 56442511, + ]), + y_minus_x: FieldElement2625([ + 7236795, 30433657, 63588571, 620817, 11118384, 24979014, 66780154, 19877679, + 16217590, 26311105, + ]), + xy2d: FieldElement2625([ + 42540794, 21657271, 16455973, 23630199, 3992015, 21894417, 44876052, 19291718, + 55429803, 30442389, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625([ + 69421833, 26972132, 58859271, 20240912, 119664007, 29643940, 93968457, 34515112, + 110902491, 44996669, + ]), + y_minus_x: FieldElement2625([ + 3428668, 27807272, 41139948, 24786894, 4167808, 21423270, 52199622, 8021269, + 53172251, 18070808, + ]), + xy2d: FieldElement2625([ + 30631113, 26363656, 21279866, 23275794, 18311406, 466071, 42527968, 7989982, + 29641567, 29446694, + ]), + }, + ]); diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/field.rs new file mode 100644 index 0000000..c8f3e5e --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/field.rs @@ -0,0 +1,578 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(32\\)-bit +//! limbs with \\(64\\)-bit products. +//! +//! This code was originally derived from Adam Langley's Golang ed25519 +//! implementation, and was then rewritten to use unsigned limbs instead +//! of signed limbs. + +use core::fmt::Debug; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Sub, SubAssign}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use zeroize::Zeroize; + +/// A `FieldElement2625` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// In the 32-bit implementation, a `FieldElement` is represented in +/// radix \\(2\^{25.5}\\) as ten `u32`s. This means that a field +/// element \\(x\\) is represented as +/// $$ +/// x = \sum\_{i=0}\^9 x\_i 2\^{\lceil i \frac {51} 2 \rceil} +/// = x\_0 + x\_1 2\^{26} + x\_2 2\^{51} + x\_3 2\^{77} + \cdots + x\_9 2\^{230}; +/// $$ +/// the coefficients are alternately bounded by \\(2\^{25}\\) and +/// \\(2\^{26}\\). The limbs are allowed to grow between reductions up +/// to \\(2\^{25+b}\\) or \\(2\^{26+b}\\), where \\(b = 1.75\\). +/// +/// # Note +/// +/// The `curve25519_dalek::field` module provides a type alias +/// `curve25519_dalek::field::FieldElement` to either `FieldElement51` +/// or `FieldElement2625`. +/// +/// The backend-specific type `FieldElement2625` should not be used +/// outside of the `curve25519_dalek::field` module. +#[derive(Copy, Clone)] +pub struct FieldElement2625(pub (crate) [u32; 10]); + +impl Debug for FieldElement2625 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "FieldElement2625({:?})", &self.0[..]) + } +} + +impl Zeroize for FieldElement2625 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl<'b> AddAssign<&'b FieldElement2625> for FieldElement2625 { + fn add_assign(&mut self, _rhs: &'b FieldElement2625) { + for i in 0..10 { + self.0[i] += _rhs.0[i]; + } + } +} + +impl<'a, 'b> Add<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn add(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut output = *self; + output += _rhs; + output + } +} + +impl<'b> SubAssign<&'b FieldElement2625> for FieldElement2625 { + fn sub_assign(&mut self, _rhs: &'b FieldElement2625) { + // See comment in FieldElement51::Sub + // + // Compute a - b as ((a + 2^4 * p) - b) to avoid underflow. + let b = &_rhs.0; + self.0 = FieldElement2625::reduce([ + ((self.0[0] + (0x3ffffed << 4)) - b[0]) as u64, + ((self.0[1] + (0x1ffffff << 4)) - b[1]) as u64, + ((self.0[2] + (0x3ffffff << 4)) - b[2]) as u64, + ((self.0[3] + (0x1ffffff << 4)) - b[3]) as u64, + ((self.0[4] + (0x3ffffff << 4)) - b[4]) as u64, + ((self.0[5] + (0x1ffffff << 4)) - b[5]) as u64, + ((self.0[6] + (0x3ffffff << 4)) - b[6]) as u64, + ((self.0[7] + (0x1ffffff << 4)) - b[7]) as u64, + ((self.0[8] + (0x3ffffff << 4)) - b[8]) as u64, + ((self.0[9] + (0x1ffffff << 4)) - b[9]) as u64, + ]).0; + } +} + +impl<'a, 'b> Sub<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn sub(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut output = *self; + output -= _rhs; + output + } +} + +impl<'b> MulAssign<&'b FieldElement2625> for FieldElement2625 { + fn mul_assign(&mut self, _rhs: &'b FieldElement2625) { + let result = (self as &FieldElement2625) * _rhs; + self.0 = result.0; + } +} + +impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { + type Output = FieldElement2625; + fn mul(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { + /// Helper function to multiply two 32-bit integers with 64 bits + /// of output. + #[inline(always)] + fn m(x: u32, y: u32) -> u64 { (x as u64) * (y as u64) } + + // Alias self, _rhs for more readable formulas + let x: &[u32;10] = &self.0; let y: &[u32;10] = &_rhs.0; + + // We assume that the input limbs x[i], y[i] are bounded by: + // + // x[i], y[i] < 2^(26 + b) if i even + // x[i], y[i] < 2^(25 + b) if i odd + // + // where b is a (real) parameter representing the excess bits of + // the limbs. We track the bitsizes of all variables through + // the computation and solve at the end for the allowable + // headroom bitsize b (which determines how many additions we + // can perform between reductions or multiplications). + + let y1_19 = 19 * y[1]; // This fits in a u32 + let y2_19 = 19 * y[2]; // iff 26 + b + lg(19) < 32 + let y3_19 = 19 * y[3]; // if b < 32 - 26 - 4.248 = 1.752 + let y4_19 = 19 * y[4]; + let y5_19 = 19 * y[5]; // below, b<2.5: this is a bottleneck, + let y6_19 = 19 * y[6]; // could be avoided by promoting to + let y7_19 = 19 * y[7]; // u64 here instead of in m() + let y8_19 = 19 * y[8]; + let y9_19 = 19 * y[9]; + + // What happens when we multiply x[i] with y[j] and place the + // result into the (i+j)-th limb? + // + // x[i] represents the value x[i]*2^ceil(i*51/2) + // y[j] represents the value y[j]*2^ceil(j*51/2) + // z[i+j] represents the value z[i+j]*2^ceil((i+j)*51/2) + // x[i]*y[j] represents the value x[i]*y[i]*2^(ceil(i*51/2)+ceil(j*51/2)) + // + // Since the radix is already accounted for, the result placed + // into the (i+j)-th limb should be + // + // x[i]*y[i]*2^(ceil(i*51/2)+ceil(j*51/2) - ceil((i+j)*51/2)). + // + // The value of ceil(i*51/2)+ceil(j*51/2) - ceil((i+j)*51/2) is + // 1 when both i and j are odd, and 0 otherwise. So we add + // + // x[i]*y[j] if either i or j is even + // 2*x[i]*y[j] if i and j are both odd + // + // by using precomputed multiples of x[i] for odd i: + + let x1_2 = 2 * x[1]; // This fits in a u32 iff 25 + b + 1 < 32 + let x3_2 = 2 * x[3]; // iff b < 6 + let x5_2 = 2 * x[5]; + let x7_2 = 2 * x[7]; + let x9_2 = 2 * x[9]; + + let z0 = m(x[0],y[0]) + m(x1_2,y9_19) + m(x[2],y8_19) + m(x3_2,y7_19) + m(x[4],y6_19) + m(x5_2,y5_19) + m(x[6],y4_19) + m(x7_2,y3_19) + m(x[8],y2_19) + m(x9_2,y1_19); + let z1 = m(x[0],y[1]) + m(x[1],y[0]) + m(x[2],y9_19) + m(x[3],y8_19) + m(x[4],y7_19) + m(x[5],y6_19) + m(x[6],y5_19) + m(x[7],y4_19) + m(x[8],y3_19) + m(x[9],y2_19); + let z2 = m(x[0],y[2]) + m(x1_2,y[1]) + m(x[2],y[0]) + m(x3_2,y9_19) + m(x[4],y8_19) + m(x5_2,y7_19) + m(x[6],y6_19) + m(x7_2,y5_19) + m(x[8],y4_19) + m(x9_2,y3_19); + let z3 = m(x[0],y[3]) + m(x[1],y[2]) + m(x[2],y[1]) + m(x[3],y[0]) + m(x[4],y9_19) + m(x[5],y8_19) + m(x[6],y7_19) + m(x[7],y6_19) + m(x[8],y5_19) + m(x[9],y4_19); + let z4 = m(x[0],y[4]) + m(x1_2,y[3]) + m(x[2],y[2]) + m(x3_2,y[1]) + m(x[4],y[0]) + m(x5_2,y9_19) + m(x[6],y8_19) + m(x7_2,y7_19) + m(x[8],y6_19) + m(x9_2,y5_19); + let z5 = m(x[0],y[5]) + m(x[1],y[4]) + m(x[2],y[3]) + m(x[3],y[2]) + m(x[4],y[1]) + m(x[5],y[0]) + m(x[6],y9_19) + m(x[7],y8_19) + m(x[8],y7_19) + m(x[9],y6_19); + let z6 = m(x[0],y[6]) + m(x1_2,y[5]) + m(x[2],y[4]) + m(x3_2,y[3]) + m(x[4],y[2]) + m(x5_2,y[1]) + m(x[6],y[0]) + m(x7_2,y9_19) + m(x[8],y8_19) + m(x9_2,y7_19); + let z7 = m(x[0],y[7]) + m(x[1],y[6]) + m(x[2],y[5]) + m(x[3],y[4]) + m(x[4],y[3]) + m(x[5],y[2]) + m(x[6],y[1]) + m(x[7],y[0]) + m(x[8],y9_19) + m(x[9],y8_19); + let z8 = m(x[0],y[8]) + m(x1_2,y[7]) + m(x[2],y[6]) + m(x3_2,y[5]) + m(x[4],y[4]) + m(x5_2,y[3]) + m(x[6],y[2]) + m(x7_2,y[1]) + m(x[8],y[0]) + m(x9_2,y9_19); + let z9 = m(x[0],y[9]) + m(x[1],y[8]) + m(x[2],y[7]) + m(x[3],y[6]) + m(x[4],y[5]) + m(x[5],y[4]) + m(x[6],y[3]) + m(x[7],y[2]) + m(x[8],y[1]) + m(x[9],y[0]); + + // How big is the contribution to z[i+j] from x[i], y[j]? + // + // Using the bounds above, we get: + // + // i even, j even: x[i]*y[j] < 2^(26+b)*2^(26+b) = 2*2^(51+2*b) + // i odd, j even: x[i]*y[j] < 2^(25+b)*2^(26+b) = 1*2^(51+2*b) + // i even, j odd: x[i]*y[j] < 2^(26+b)*2^(25+b) = 1*2^(51+2*b) + // i odd, j odd: 2*x[i]*y[j] < 2*2^(25+b)*2^(25+b) = 1*2^(51+2*b) + // + // We perform inline reduction mod p by replacing 2^255 by 19 + // (since 2^255 - 19 = 0 mod p). This adds a factor of 19, so + // we get the bounds (z0 is the biggest one, but calculated for + // posterity here in case finer estimation is needed later): + // + // z0 < ( 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 249*2^(51 + 2*b) + // z1 < ( 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 154*2^(51 + 2*b) + // z2 < ( 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 195*2^(51 + 2*b) + // z3 < ( 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 118*2^(51 + 2*b) + // z4 < ( 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 141*2^(51 + 2*b) + // z5 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 82*2^(51 + 2*b) + // z6 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 87*2^(51 + 2*b) + // z7 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 )*2^(51 + 2b) = 46*2^(51 + 2*b) + // z6 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 )*2^(51 + 2b) = 33*2^(51 + 2*b) + // z7 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 )*2^(51 + 2b) = 10*2^(51 + 2*b) + // + // So z[0] fits into a u64 if 51 + 2*b + lg(249) < 64 + // if b < 2.5. + FieldElement2625::reduce([z0, z1, z2, z3, z4, z5, z6, z7, z8, z9]) + } +} + +impl<'a> Neg for &'a FieldElement2625 { + type Output = FieldElement2625; + fn neg(self) -> FieldElement2625 { + let mut output = *self; + output.negate(); + output + } +} + +impl ConditionallySelectable for FieldElement2625 { + fn conditional_select( + a: &FieldElement2625, + b: &FieldElement2625, + choice: Choice, + ) -> FieldElement2625 { + FieldElement2625([ + u32::conditional_select(&a.0[0], &b.0[0], choice), + u32::conditional_select(&a.0[1], &b.0[1], choice), + u32::conditional_select(&a.0[2], &b.0[2], choice), + u32::conditional_select(&a.0[3], &b.0[3], choice), + u32::conditional_select(&a.0[4], &b.0[4], choice), + u32::conditional_select(&a.0[5], &b.0[5], choice), + u32::conditional_select(&a.0[6], &b.0[6], choice), + u32::conditional_select(&a.0[7], &b.0[7], choice), + u32::conditional_select(&a.0[8], &b.0[8], choice), + u32::conditional_select(&a.0[9], &b.0[9], choice), + ]) + } + + fn conditional_assign(&mut self, other: &FieldElement2625, choice: Choice) { + self.0[0].conditional_assign(&other.0[0], choice); + self.0[1].conditional_assign(&other.0[1], choice); + self.0[2].conditional_assign(&other.0[2], choice); + self.0[3].conditional_assign(&other.0[3], choice); + self.0[4].conditional_assign(&other.0[4], choice); + self.0[5].conditional_assign(&other.0[5], choice); + self.0[6].conditional_assign(&other.0[6], choice); + self.0[7].conditional_assign(&other.0[7], choice); + self.0[8].conditional_assign(&other.0[8], choice); + self.0[9].conditional_assign(&other.0[9], choice); + } + + fn conditional_swap(a: &mut FieldElement2625, b: &mut FieldElement2625, choice: Choice) { + u32::conditional_swap(&mut a.0[0], &mut b.0[0], choice); + u32::conditional_swap(&mut a.0[1], &mut b.0[1], choice); + u32::conditional_swap(&mut a.0[2], &mut b.0[2], choice); + u32::conditional_swap(&mut a.0[3], &mut b.0[3], choice); + u32::conditional_swap(&mut a.0[4], &mut b.0[4], choice); + u32::conditional_swap(&mut a.0[5], &mut b.0[5], choice); + u32::conditional_swap(&mut a.0[6], &mut b.0[6], choice); + u32::conditional_swap(&mut a.0[7], &mut b.0[7], choice); + u32::conditional_swap(&mut a.0[8], &mut b.0[8], choice); + u32::conditional_swap(&mut a.0[9], &mut b.0[9], choice); + } +} + +impl FieldElement2625 { + /// Invert the sign of this field element + pub fn negate(&mut self) { + // Compute -b as ((2^4 * p) - b) to avoid underflow. + let neg = FieldElement2625::reduce([ + ((0x3ffffed << 4) - self.0[0]) as u64, + ((0x1ffffff << 4) - self.0[1]) as u64, + ((0x3ffffff << 4) - self.0[2]) as u64, + ((0x1ffffff << 4) - self.0[3]) as u64, + ((0x3ffffff << 4) - self.0[4]) as u64, + ((0x1ffffff << 4) - self.0[5]) as u64, + ((0x3ffffff << 4) - self.0[6]) as u64, + ((0x1ffffff << 4) - self.0[7]) as u64, + ((0x3ffffff << 4) - self.0[8]) as u64, + ((0x1ffffff << 4) - self.0[9]) as u64, + ]); + self.0 = neg.0; + } + + /// Construct zero. + pub fn zero() -> FieldElement2625 { + FieldElement2625([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) + } + + /// Construct one. + pub fn one() -> FieldElement2625 { + FieldElement2625([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) + } + + /// Construct -1. + pub fn minus_one() -> FieldElement2625 { + FieldElement2625([ + 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, + 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, + ]) + } + + /// Given `k > 0`, return `self^(2^k)`. + pub fn pow2k(&self, k: u32) -> FieldElement2625 { + debug_assert!( k > 0 ); + let mut z = self.square(); + for _ in 1..k { + z = z.square(); + } + z + } + + /// Given unreduced coefficients `z[0], ..., z[9]` of any size, + /// carry and reduce them mod p to obtain a `FieldElement2625` + /// whose coefficients have excess `b < 0.007`. + /// + /// In other words, each coefficient of the result is bounded by + /// either `2^(25 + 0.007)` or `2^(26 + 0.007)`, as appropriate. + fn reduce(mut z: [u64; 10]) -> FieldElement2625 { + + const LOW_25_BITS: u64 = (1 << 25) - 1; + const LOW_26_BITS: u64 = (1 << 26) - 1; + + /// Carry the value from limb i = 0..8 to limb i+1 + #[inline(always)] + fn carry(z: &mut [u64; 10], i: usize) { + debug_assert!(i < 9); + if i % 2 == 0 { + // Even limbs have 26 bits + z[i+1] += z[i] >> 26; + z[i] &= LOW_26_BITS; + } else { + // Odd limbs have 25 bits + z[i+1] += z[i] >> 25; + z[i] &= LOW_25_BITS; + } + } + + // Perform two halves of the carry chain in parallel. + carry(&mut z, 0); carry(&mut z, 4); + carry(&mut z, 1); carry(&mut z, 5); + carry(&mut z, 2); carry(&mut z, 6); + carry(&mut z, 3); carry(&mut z, 7); + // Since z[3] < 2^64, c < 2^(64-25) = 2^39, + // so z[4] < 2^26 + 2^39 < 2^39.0002 + carry(&mut z, 4); carry(&mut z, 8); + // Now z[4] < 2^26 + // and z[5] < 2^25 + 2^13.0002 < 2^25.0004 (good enough) + + // Last carry has a multiplication by 19: + z[0] += 19*(z[9] >> 25); + z[9] &= LOW_25_BITS; + + // Since z[9] < 2^64, c < 2^(64-25) = 2^39, + // so z[0] + 19*c < 2^26 + 2^43.248 < 2^43.249. + carry(&mut z, 0); + // Now z[1] < 2^25 - 2^(43.249 - 26) + // < 2^25.007 (good enough) + // and we're done. + + FieldElement2625([ + z[0] as u32, z[1] as u32, z[2] as u32, z[3] as u32, z[4] as u32, + z[5] as u32, z[6] as u32, z[7] as u32, z[8] as u32, z[9] as u32, + ]) + } + + /// Load a `FieldElement51` from the low 255 bits of a 256-bit + /// input. + /// + /// # Warning + /// + /// This function does not check that the input used the canonical + /// representative. It masks the high bit, but it will happily + /// decode 2^255 - 18 to 1. Applications that require a canonical + /// encoding of every field element should decode, re-encode to + /// the canonical encoding, and check that the input was + /// canonical. + pub fn from_bytes(data: &[u8; 32]) -> FieldElement2625 { //FeFromBytes + #[inline] + fn load3(b: &[u8]) -> u64 { + (b[0] as u64) | ((b[1] as u64) << 8) | ((b[2] as u64) << 16) + } + + #[inline] + fn load4(b: &[u8]) -> u64 { + (b[0] as u64) | ((b[1] as u64) << 8) | ((b[2] as u64) << 16) | ((b[3] as u64) << 24) + } + + let mut h = [0u64;10]; + const LOW_23_BITS: u64 = (1 << 23) - 1; + h[0] = load4(&data[ 0..]); + h[1] = load3(&data[ 4..]) << 6; + h[2] = load3(&data[ 7..]) << 5; + h[3] = load3(&data[10..]) << 3; + h[4] = load3(&data[13..]) << 2; + h[5] = load4(&data[16..]); + h[6] = load3(&data[20..]) << 7; + h[7] = load3(&data[23..]) << 5; + h[8] = load3(&data[26..]) << 4; + h[9] = (load3(&data[29..]) & LOW_23_BITS) << 2; + + FieldElement2625::reduce(h) + } + + /// Serialize this `FieldElement51` to a 32-byte array. The + /// encoding is canonical. + pub fn to_bytes(&self) -> [u8; 32] { + + let inp = &self.0; + // Reduce the value represented by `in` to the range [0,2*p) + let mut h: [u32; 10] = FieldElement2625::reduce([ + // XXX this cast is annoying + inp[0] as u64, inp[1] as u64, inp[2] as u64, inp[3] as u64, inp[4] as u64, + inp[5] as u64, inp[6] as u64, inp[7] as u64, inp[8] as u64, inp[9] as u64, + ]).0; + + // Let h be the value to encode. + // + // Write h = pq + r with 0 <= r < p. We want to compute r = h mod p. + // + // Since h < 2*p, q = 0 or 1, with q = 0 when h < p and q = 1 when h >= p. + // + // Notice that h >= p <==> h + 19 >= p + 19 <==> h + 19 >= 2^255. + // Therefore q can be computed as the carry bit of h + 19. + + let mut q: u32 = (h[0] + 19) >> 26; + q = (h[1] + q) >> 25; + q = (h[2] + q) >> 26; + q = (h[3] + q) >> 25; + q = (h[4] + q) >> 26; + q = (h[5] + q) >> 25; + q = (h[6] + q) >> 26; + q = (h[7] + q) >> 25; + q = (h[8] + q) >> 26; + q = (h[9] + q) >> 25; + + debug_assert!( q == 0 || q == 1 ); + + // Now we can compute r as r = h - pq = r - (2^255-19)q = r + 19q - 2^255q + + const LOW_25_BITS: u32 = (1 << 25) - 1; + const LOW_26_BITS: u32 = (1 << 26) - 1; + + h[0] += 19*q; + + // Now carry the result to compute r + 19q... + h[1] += h[0] >> 26; + h[0] = h[0] & LOW_26_BITS; + h[2] += h[1] >> 25; + h[1] = h[1] & LOW_25_BITS; + h[3] += h[2] >> 26; + h[2] = h[2] & LOW_26_BITS; + h[4] += h[3] >> 25; + h[3] = h[3] & LOW_25_BITS; + h[5] += h[4] >> 26; + h[4] = h[4] & LOW_26_BITS; + h[6] += h[5] >> 25; + h[5] = h[5] & LOW_25_BITS; + h[7] += h[6] >> 26; + h[6] = h[6] & LOW_26_BITS; + h[8] += h[7] >> 25; + h[7] = h[7] & LOW_25_BITS; + h[9] += h[8] >> 26; + h[8] = h[8] & LOW_26_BITS; + + // ... but instead of carrying the value + // (h[9] >> 25) = q*2^255 into another limb, + // discard it, subtracting the value from h. + debug_assert!( (h[9] >> 25) == 0 || (h[9] >> 25) == 1); + h[9] = h[9] & LOW_25_BITS; + + let mut s = [0u8; 32]; + s[0] = (h[0] >> 0) as u8; + s[1] = (h[0] >> 8) as u8; + s[2] = (h[0] >> 16) as u8; + s[3] = ((h[0] >> 24) | (h[1] << 2)) as u8; + s[4] = (h[1] >> 6) as u8; + s[5] = (h[1] >> 14) as u8; + s[6] = ((h[1] >> 22) | (h[2] << 3)) as u8; + s[7] = (h[2] >> 5) as u8; + s[8] = (h[2] >> 13) as u8; + s[9] = ((h[2] >> 21) | (h[3] << 5)) as u8; + s[10] = (h[3] >> 3) as u8; + s[11] = (h[3] >> 11) as u8; + s[12] = ((h[3] >> 19) | (h[4] << 6)) as u8; + s[13] = (h[4] >> 2) as u8; + s[14] = (h[4] >> 10) as u8; + s[15] = (h[4] >> 18) as u8; + s[16] = (h[5] >> 0) as u8; + s[17] = (h[5] >> 8) as u8; + s[18] = (h[5] >> 16) as u8; + s[19] = ((h[5] >> 24) | (h[6] << 1)) as u8; + s[20] = (h[6] >> 7) as u8; + s[21] = (h[6] >> 15) as u8; + s[22] = ((h[6] >> 23) | (h[7] << 3)) as u8; + s[23] = (h[7] >> 5) as u8; + s[24] = (h[7] >> 13) as u8; + s[25] = ((h[7] >> 21) | (h[8] << 4)) as u8; + s[26] = (h[8] >> 4) as u8; + s[27] = (h[8] >> 12) as u8; + s[28] = ((h[8] >> 20) | (h[9] << 6)) as u8; + s[29] = (h[9] >> 2) as u8; + s[30] = (h[9] >> 10) as u8; + s[31] = (h[9] >> 18) as u8; + + // Check that high bit is cleared + debug_assert!((s[31] & 0b1000_0000u8) == 0u8); + + s + } + + fn square_inner(&self) -> [u64; 10] { + // Optimized version of multiplication for the case of squaring. + // Pre- and post- conditions identical to multiplication function. + let x = &self.0; + let x0_2 = 2 * x[0]; + let x1_2 = 2 * x[1]; + let x2_2 = 2 * x[2]; + let x3_2 = 2 * x[3]; + let x4_2 = 2 * x[4]; + let x5_2 = 2 * x[5]; + let x6_2 = 2 * x[6]; + let x7_2 = 2 * x[7]; + let x5_19 = 19 * x[5]; + let x6_19 = 19 * x[6]; + let x7_19 = 19 * x[7]; + let x8_19 = 19 * x[8]; + let x9_19 = 19 * x[9]; + + /// Helper function to multiply two 32-bit integers with 64 bits + /// of output. + #[inline(always)] + fn m(x: u32, y: u32) -> u64 { (x as u64) * (y as u64) } + + // This block is rearranged so that instead of doing a 32-bit multiplication by 38, we do a + // 64-bit multiplication by 2 on the results. This is because lg(38) is too big: we would + // have less than 1 bit of headroom left, which is too little. + let mut z = [0u64;10]; + z[0] = m(x[0],x[0]) + m(x2_2,x8_19) + m(x4_2,x6_19) + (m(x1_2,x9_19) + m(x3_2,x7_19) + m(x[5],x5_19))*2; + z[1] = m(x0_2,x[1]) + m(x3_2,x8_19) + m(x5_2,x6_19) + (m(x[2],x9_19) + m(x[4],x7_19))*2; + z[2] = m(x0_2,x[2]) + m(x1_2,x[1]) + m(x4_2,x8_19) + m(x[6],x6_19) + (m(x3_2,x9_19) + m(x5_2,x7_19))*2; + z[3] = m(x0_2,x[3]) + m(x1_2,x[2]) + m(x5_2,x8_19) + (m(x[4],x9_19) + m(x[6],x7_19))*2; + z[4] = m(x0_2,x[4]) + m(x1_2,x3_2) + m(x[2],x[2]) + m(x6_2,x8_19) + (m(x5_2,x9_19) + m(x[7],x7_19))*2; + z[5] = m(x0_2,x[5]) + m(x1_2,x[4]) + m(x2_2,x[3]) + m(x7_2,x8_19) + m(x[6],x9_19)*2; + z[6] = m(x0_2,x[6]) + m(x1_2,x5_2) + m(x2_2,x[4]) + m(x3_2,x[3]) + m(x[8],x8_19) + m(x7_2,x9_19)*2; + z[7] = m(x0_2,x[7]) + m(x1_2,x[6]) + m(x2_2,x[5]) + m(x3_2,x[4]) + m(x[8],x9_19)*2; + z[8] = m(x0_2,x[8]) + m(x1_2,x7_2) + m(x2_2,x[6]) + m(x3_2,x5_2) + m(x[4],x[4]) + m(x[9],x9_19)*2; + z[9] = m(x0_2,x[9]) + m(x1_2,x[8]) + m(x2_2,x[7]) + m(x3_2,x[6]) + m(x4_2,x[5]) ; + + z + } + + /// Compute `self^2`. + pub fn square(&self) -> FieldElement2625 { + FieldElement2625::reduce(self.square_inner()) + } + + /// Compute `2*self^2`. + pub fn square2(&self) -> FieldElement2625 { + let mut coeffs = self.square_inner(); + for i in 0..self.0.len() { + coeffs[i] += coeffs[i]; + } + FieldElement2625::reduce(coeffs) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/mod.rs new file mode 100644 index 0000000..401ce74 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/mod.rs @@ -0,0 +1,22 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier. +//! +//! This code is intended to be portable, but it requires that +//! multiplication of two \\(32\\)-bit values to a \\(64\\)-bit result +//! is constant-time on the target platform. + +pub mod field; + +pub mod scalar; + +pub mod constants; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/scalar.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/scalar.rs new file mode 100644 index 0000000..8dd54bd --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u32/scalar.rs @@ -0,0 +1,529 @@ +//! Arithmetic mod 2^252 + 27742317777372353535851937790883648493 +//! with 9 29-bit unsigned limbs +//! +//! To see that this is safe for intermediate results, note that +//! the largest limb in a 9 by 9 product of 29-bit limbs will be +//! (0x1fffffff^2) * 9 = 0x23fffffdc0000009 (62 bits). +//! +//! For a one level Karatsuba decomposition, the specific ranges +//! depend on how the limbs are combined, but will stay within +//! -0x1ffffffe00000008 (62 bits with sign bit) to +//! 0x43fffffbc0000011 (63 bits), which is still safe. + +use core::fmt::Debug; +use core::ops::{Index, IndexMut}; + +use zeroize::Zeroize; + +use constants; + +/// The `Scalar29` struct represents an element in ℤ/lℤ as 9 29-bit limbs +#[derive(Copy,Clone)] +pub struct Scalar29(pub [u32; 9]); + +impl Debug for Scalar29 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "Scalar29: {:?}", &self.0[..]) + } +} + +impl Zeroize for Scalar29 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl Index for Scalar29 { + type Output = u32; + fn index(&self, _index: usize) -> &u32 { + &(self.0[_index]) + } +} + +impl IndexMut for Scalar29 { + fn index_mut(&mut self, _index: usize) -> &mut u32 { + &mut (self.0[_index]) + } +} + +/// u32 * u32 = u64 multiply helper +#[inline(always)] +fn m(x: u32, y: u32) -> u64 { + (x as u64) * (y as u64) +} + +impl Scalar29 { + /// Return the zero scalar. + pub fn zero() -> Scalar29 { + Scalar29([0,0,0,0,0,0,0,0,0]) + } + + /// Unpack a 32 byte / 256 bit scalar into 9 29-bit limbs. + pub fn from_bytes(bytes: &[u8; 32]) -> Scalar29 { + let mut words = [0u32; 8]; + for i in 0..8 { + for j in 0..4 { + words[i] |= (bytes[(i * 4) + j] as u32) << (j * 8); + } + } + + let mask = (1u32 << 29) - 1; + let top_mask = (1u32 << 24) - 1; + let mut s = Scalar29::zero(); + + s[ 0] = words[0] & mask; + s[ 1] = ((words[0] >> 29) | (words[1] << 3)) & mask; + s[ 2] = ((words[1] >> 26) | (words[2] << 6)) & mask; + s[ 3] = ((words[2] >> 23) | (words[3] << 9)) & mask; + s[ 4] = ((words[3] >> 20) | (words[4] << 12)) & mask; + s[ 5] = ((words[4] >> 17) | (words[5] << 15)) & mask; + s[ 6] = ((words[5] >> 14) | (words[6] << 18)) & mask; + s[ 7] = ((words[6] >> 11) | (words[7] << 21)) & mask; + s[ 8] = (words[7] >> 8) & top_mask; + + s + } + + /// Reduce a 64 byte / 512 bit scalar mod l. + pub fn from_bytes_wide(bytes: &[u8; 64]) -> Scalar29 { + let mut words = [0u32; 16]; + for i in 0..16 { + for j in 0..4 { + words[i] |= (bytes[(i * 4) + j] as u32) << (j * 8); + } + } + + let mask = (1u32 << 29) - 1; + let mut lo = Scalar29::zero(); + let mut hi = Scalar29::zero(); + + lo[0] = words[ 0] & mask; + lo[1] = ((words[ 0] >> 29) | (words[ 1] << 3)) & mask; + lo[2] = ((words[ 1] >> 26) | (words[ 2] << 6)) & mask; + lo[3] = ((words[ 2] >> 23) | (words[ 3] << 9)) & mask; + lo[4] = ((words[ 3] >> 20) | (words[ 4] << 12)) & mask; + lo[5] = ((words[ 4] >> 17) | (words[ 5] << 15)) & mask; + lo[6] = ((words[ 5] >> 14) | (words[ 6] << 18)) & mask; + lo[7] = ((words[ 6] >> 11) | (words[ 7] << 21)) & mask; + lo[8] = ((words[ 7] >> 8) | (words[ 8] << 24)) & mask; + hi[0] = ((words[ 8] >> 5) | (words[ 9] << 27)) & mask; + hi[1] = (words[ 9] >> 2) & mask; + hi[2] = ((words[ 9] >> 31) | (words[10] << 1)) & mask; + hi[3] = ((words[10] >> 28) | (words[11] << 4)) & mask; + hi[4] = ((words[11] >> 25) | (words[12] << 7)) & mask; + hi[5] = ((words[12] >> 22) | (words[13] << 10)) & mask; + hi[6] = ((words[13] >> 19) | (words[14] << 13)) & mask; + hi[7] = ((words[14] >> 16) | (words[15] << 16)) & mask; + hi[8] = words[15] >> 13 ; + + lo = Scalar29::montgomery_mul(&lo, &constants::R); // (lo * R) / R = lo + hi = Scalar29::montgomery_mul(&hi, &constants::RR); // (hi * R^2) / R = hi * R + + Scalar29::add(&hi, &lo) // (hi * R) + lo + } + + /// Pack the limbs of this `Scalar29` into 32 bytes. + pub fn to_bytes(&self) -> [u8; 32] { + let mut s = [0u8; 32]; + + s[0] = (self.0[ 0] >> 0) as u8; + s[1] = (self.0[ 0] >> 8) as u8; + s[2] = (self.0[ 0] >> 16) as u8; + s[3] = ((self.0[ 0] >> 24) | (self.0[ 1] << 5)) as u8; + s[4] = (self.0[ 1] >> 3) as u8; + s[5] = (self.0[ 1] >> 11) as u8; + s[6] = (self.0[ 1] >> 19) as u8; + s[7] = ((self.0[ 1] >> 27) | (self.0[ 2] << 2)) as u8; + s[8] = (self.0[ 2] >> 6) as u8; + s[9] = (self.0[ 2] >> 14) as u8; + s[10] = ((self.0[ 2] >> 22) | (self.0[ 3] << 7)) as u8; + s[11] = (self.0[ 3] >> 1) as u8; + s[12] = (self.0[ 3] >> 9) as u8; + s[13] = (self.0[ 3] >> 17) as u8; + s[14] = ((self.0[ 3] >> 25) | (self.0[ 4] << 4)) as u8; + s[15] = (self.0[ 4] >> 4) as u8; + s[16] = (self.0[ 4] >> 12) as u8; + s[17] = (self.0[ 4] >> 20) as u8; + s[18] = ((self.0[ 4] >> 28) | (self.0[ 5] << 1)) as u8; + s[19] = (self.0[ 5] >> 7) as u8; + s[20] = (self.0[ 5] >> 15) as u8; + s[21] = ((self.0[ 5] >> 23) | (self.0[ 6] << 6)) as u8; + s[22] = (self.0[ 6] >> 2) as u8; + s[23] = (self.0[ 6] >> 10) as u8; + s[24] = (self.0[ 6] >> 18) as u8; + s[25] = ((self.0[ 6] >> 26) | (self.0[ 7] << 3)) as u8; + s[26] = (self.0[ 7] >> 5) as u8; + s[27] = (self.0[ 7] >> 13) as u8; + s[28] = (self.0[ 7] >> 21) as u8; + s[29] = (self.0[ 8] >> 0) as u8; + s[30] = (self.0[ 8] >> 8) as u8; + s[31] = (self.0[ 8] >> 16) as u8; + + s + } + + /// Compute `a + b` (mod l). + pub fn add(a: &Scalar29, b: &Scalar29) -> Scalar29 { + let mut sum = Scalar29::zero(); + let mask = (1u32 << 29) - 1; + + // a + b + let mut carry: u32 = 0; + for i in 0..9 { + carry = a[i] + b[i] + (carry >> 29); + sum[i] = carry & mask; + } + + // subtract l if the sum is >= l + Scalar29::sub(&sum, &constants::L) + } + + /// Compute `a - b` (mod l). + pub fn sub(a: &Scalar29, b: &Scalar29) -> Scalar29 { + let mut difference = Scalar29::zero(); + let mask = (1u32 << 29) - 1; + + // a - b + let mut borrow: u32 = 0; + for i in 0..9 { + borrow = a[i].wrapping_sub(b[i] + (borrow >> 31)); + difference[i] = borrow & mask; + } + + // conditionally add l if the difference is negative + let underflow_mask = ((borrow >> 31) ^ 1).wrapping_sub(1); + let mut carry: u32 = 0; + for i in 0..9 { + carry = (carry >> 29) + difference[i] + (constants::L[i] & underflow_mask); + difference[i] = carry & mask; + } + + difference + } + + /// Compute `a * b`. + /// + /// This is implemented with a one-level refined Karatsuba decomposition + #[inline(always)] + pub (crate) fn mul_internal(a: &Scalar29, b: &Scalar29) -> [u64; 17] { + let mut z = [0u64; 17]; + + z[0] = m(a[0],b[0]); // c00 + z[1] = m(a[0],b[1]) + m(a[1],b[0]); // c01 + z[2] = m(a[0],b[2]) + m(a[1],b[1]) + m(a[2],b[0]); // c02 + z[3] = m(a[0],b[3]) + m(a[1],b[2]) + m(a[2],b[1]) + m(a[3],b[0]); // c03 + z[4] = m(a[0],b[4]) + m(a[1],b[3]) + m(a[2],b[2]) + m(a[3],b[1]) + m(a[4],b[0]); // c04 + z[5] = m(a[1],b[4]) + m(a[2],b[3]) + m(a[3],b[2]) + m(a[4],b[1]); // c05 + z[6] = m(a[2],b[4]) + m(a[3],b[3]) + m(a[4],b[2]); // c06 + z[7] = m(a[3],b[4]) + m(a[4],b[3]); // c07 + z[8] = (m(a[4],b[4])).wrapping_sub(z[3]); // c08 - c03 + + z[10] = z[5].wrapping_sub(m(a[5],b[5])); // c05mc10 + z[11] = z[6].wrapping_sub(m(a[5],b[6]) + m(a[6],b[5])); // c06mc11 + z[12] = z[7].wrapping_sub(m(a[5],b[7]) + m(a[6],b[6]) + m(a[7],b[5])); // c07mc12 + z[13] = m(a[5],b[8]) + m(a[6],b[7]) + m(a[7],b[6]) + m(a[8],b[5]); // c13 + z[14] = m(a[6],b[8]) + m(a[7],b[7]) + m(a[8],b[6]); // c14 + z[15] = m(a[7],b[8]) + m(a[8],b[7]); // c15 + z[16] = m(a[8],b[8]); // c16 + + z[ 5] = z[10].wrapping_sub(z[ 0]); // c05mc10 - c00 + z[ 6] = z[11].wrapping_sub(z[ 1]); // c06mc11 - c01 + z[ 7] = z[12].wrapping_sub(z[ 2]); // c07mc12 - c02 + z[ 8] = z[ 8].wrapping_sub(z[13]); // c08mc13 - c03 + z[ 9] = z[14].wrapping_add(z[ 4]); // c14 + c04 + z[10] = z[15].wrapping_add(z[10]); // c15 + c05mc10 + z[11] = z[16].wrapping_add(z[11]); // c16 + c06mc11 + + let aa = [ + a[0]+a[5], + a[1]+a[6], + a[2]+a[7], + a[3]+a[8] + ]; + + let bb = [ + b[0]+b[5], + b[1]+b[6], + b[2]+b[7], + b[3]+b[8] + ]; + + z[ 5] = (m(aa[0],bb[0])) .wrapping_add(z[ 5]); // c20 + c05mc10 - c00 + z[ 6] = (m(aa[0],bb[1]) + m(aa[1],bb[0])) .wrapping_add(z[ 6]); // c21 + c06mc11 - c01 + z[ 7] = (m(aa[0],bb[2]) + m(aa[1],bb[1]) + m(aa[2],bb[0])) .wrapping_add(z[ 7]); // c22 + c07mc12 - c02 + z[ 8] = (m(aa[0],bb[3]) + m(aa[1],bb[2]) + m(aa[2],bb[1]) + m(aa[3],bb[0])) .wrapping_add(z[ 8]); // c23 + c08mc13 - c03 + z[ 9] = (m(aa[0], b[4]) + m(aa[1],bb[3]) + m(aa[2],bb[2]) + m(aa[3],bb[1]) + m(a[4],bb[0])).wrapping_sub(z[ 9]); // c24 - c14 - c04 + z[10] = ( m(aa[1], b[4]) + m(aa[2],bb[3]) + m(aa[3],bb[2]) + m(a[4],bb[1])).wrapping_sub(z[10]); // c25 - c15 - c05mc10 + z[11] = ( m(aa[2], b[4]) + m(aa[3],bb[3]) + m(a[4],bb[2])).wrapping_sub(z[11]); // c26 - c16 - c06mc11 + z[12] = ( m(aa[3], b[4]) + m(a[4],bb[3])).wrapping_sub(z[12]); // c27 - c07mc12 + + z + } + + /// Compute `a^2`. + #[inline(always)] + fn square_internal(a: &Scalar29) -> [u64; 17] { + let aa = [ + a[0]*2, + a[1]*2, + a[2]*2, + a[3]*2, + a[4]*2, + a[5]*2, + a[6]*2, + a[7]*2 + ]; + + [ + m( a[0],a[0]), + m(aa[0],a[1]), + m(aa[0],a[2]) + m( a[1],a[1]), + m(aa[0],a[3]) + m(aa[1],a[2]), + m(aa[0],a[4]) + m(aa[1],a[3]) + m( a[2],a[2]), + m(aa[0],a[5]) + m(aa[1],a[4]) + m(aa[2],a[3]), + m(aa[0],a[6]) + m(aa[1],a[5]) + m(aa[2],a[4]) + m( a[3],a[3]), + m(aa[0],a[7]) + m(aa[1],a[6]) + m(aa[2],a[5]) + m(aa[3],a[4]), + m(aa[0],a[8]) + m(aa[1],a[7]) + m(aa[2],a[6]) + m(aa[3],a[5]) + m( a[4],a[4]), + m(aa[1],a[8]) + m(aa[2],a[7]) + m(aa[3],a[6]) + m(aa[4],a[5]), + m(aa[2],a[8]) + m(aa[3],a[7]) + m(aa[4],a[6]) + m( a[5],a[5]), + m(aa[3],a[8]) + m(aa[4],a[7]) + m(aa[5],a[6]), + m(aa[4],a[8]) + m(aa[5],a[7]) + m( a[6],a[6]), + m(aa[5],a[8]) + m(aa[6],a[7]), + m(aa[6],a[8]) + m( a[7],a[7]), + m(aa[7],a[8]), + m( a[8],a[8]), + ] + } + + /// Compute `limbs/R` (mod l), where R is the Montgomery modulus 2^261 + #[inline(always)] + pub (crate) fn montgomery_reduce(limbs: &[u64; 17]) -> Scalar29 { + + #[inline(always)] + fn part1(sum: u64) -> (u64, u32) { + let p = (sum as u32).wrapping_mul(constants::LFACTOR) & ((1u32 << 29) - 1); + ((sum + m(p,constants::L[0])) >> 29, p) + } + + #[inline(always)] + fn part2(sum: u64) -> (u64, u32) { + let w = (sum as u32) & ((1u32 << 29) - 1); + (sum >> 29, w) + } + + // note: l5,l6,l7 are zero, so their multiplies can be skipped + let l = &constants::L; + + // the first half computes the Montgomery adjustment factor n, and begins adding n*l to make limbs divisible by R + let (carry, n0) = part1( limbs[ 0]); + let (carry, n1) = part1(carry + limbs[ 1] + m(n0,l[1])); + let (carry, n2) = part1(carry + limbs[ 2] + m(n0,l[2]) + m(n1,l[1])); + let (carry, n3) = part1(carry + limbs[ 3] + m(n0,l[3]) + m(n1,l[2]) + m(n2,l[1])); + let (carry, n4) = part1(carry + limbs[ 4] + m(n0,l[4]) + m(n1,l[3]) + m(n2,l[2]) + m(n3,l[1])); + let (carry, n5) = part1(carry + limbs[ 5] + m(n1,l[4]) + m(n2,l[3]) + m(n3,l[2]) + m(n4,l[1])); + let (carry, n6) = part1(carry + limbs[ 6] + m(n2,l[4]) + m(n3,l[3]) + m(n4,l[2]) + m(n5,l[1])); + let (carry, n7) = part1(carry + limbs[ 7] + m(n3,l[4]) + m(n4,l[3]) + m(n5,l[2]) + m(n6,l[1])); + let (carry, n8) = part1(carry + limbs[ 8] + m(n0,l[8]) + m(n4,l[4]) + m(n5,l[3]) + m(n6,l[2]) + m(n7,l[1])); + + // limbs is divisible by R now, so we can divide by R by simply storing the upper half as the result + let (carry, r0) = part2(carry + limbs[ 9] + m(n1,l[8]) + m(n5,l[4]) + m(n6,l[3]) + m(n7,l[2]) + m(n8,l[1])); + let (carry, r1) = part2(carry + limbs[10] + m(n2,l[8]) + m(n6,l[4]) + m(n7,l[3]) + m(n8,l[2])); + let (carry, r2) = part2(carry + limbs[11] + m(n3,l[8]) + m(n7,l[4]) + m(n8,l[3])); + let (carry, r3) = part2(carry + limbs[12] + m(n4,l[8]) + m(n8,l[4])); + let (carry, r4) = part2(carry + limbs[13] + m(n5,l[8]) ); + let (carry, r5) = part2(carry + limbs[14] + m(n6,l[8]) ); + let (carry, r6) = part2(carry + limbs[15] + m(n7,l[8]) ); + let (carry, r7) = part2(carry + limbs[16] + m(n8,l[8])); + let r8 = carry as u32; + + // result may be >= l, so attempt to subtract l + Scalar29::sub(&Scalar29([r0,r1,r2,r3,r4,r5,r6,r7,r8]), l) + } + + /// Compute `a * b` (mod l). + #[inline(never)] + pub fn mul(a: &Scalar29, b: &Scalar29) -> Scalar29 { + let ab = Scalar29::montgomery_reduce(&Scalar29::mul_internal(a, b)); + Scalar29::montgomery_reduce(&Scalar29::mul_internal(&ab, &constants::RR)) + } + + /// Compute `a^2` (mod l). + #[inline(never)] + #[allow(dead_code)] // XXX we don't expose square() via the Scalar API + pub fn square(&self) -> Scalar29 { + let aa = Scalar29::montgomery_reduce(&Scalar29::square_internal(self)); + Scalar29::montgomery_reduce(&Scalar29::mul_internal(&aa, &constants::RR)) + } + + /// Compute `(a * b) / R` (mod l), where R is the Montgomery modulus 2^261 + #[inline(never)] + pub fn montgomery_mul(a: &Scalar29, b: &Scalar29) -> Scalar29 { + Scalar29::montgomery_reduce(&Scalar29::mul_internal(a, b)) + } + + /// Compute `(a^2) / R` (mod l) in Montgomery form, where R is the Montgomery modulus 2^261 + #[inline(never)] + pub fn montgomery_square(&self) -> Scalar29 { + Scalar29::montgomery_reduce(&Scalar29::square_internal(self)) + } + + /// Puts a Scalar29 in to Montgomery form, i.e. computes `a*R (mod l)` + #[inline(never)] + pub fn to_montgomery(&self) -> Scalar29 { + Scalar29::montgomery_mul(self, &constants::RR) + } + + /// Takes a Scalar29 out of Montgomery form, i.e. computes `a/R (mod l)` + pub fn from_montgomery(&self) -> Scalar29 { + let mut limbs = [0u64; 17]; + for i in 0..9 { + limbs[i] = self[i] as u64; + } + Scalar29::montgomery_reduce(&limbs) + } +} + +#[cfg(test)] +mod test { + use super::*; + + /// Note: x is 2^253-1 which is slightly larger than the largest scalar produced by + /// this implementation (l-1), and should verify there are no overflows for valid scalars + /// + /// x = 2^253-1 = 14474011154664524427946373126085988481658748083205070504932198000989141204991 + /// x = 7237005577332262213973186563042994240801631723825162898930247062703686954002 mod l + /// x = 5147078182513738803124273553712992179887200054963030844803268920753008712037*R mod l in Montgomery form + pub static X: Scalar29 = Scalar29( + [0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, + 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, + 0x001fffff]); + + /// x^2 = 3078544782642840487852506753550082162405942681916160040940637093560259278169 mod l + pub static XX: Scalar29 = Scalar29( + [0x00217559, 0x000b3401, 0x103ff43b, 0x1462a62c, + 0x1d6f9f38, 0x18e7a42f, 0x09a3dcee, 0x008dbe18, + 0x0006ce65]); + + /// x^2 = 2912514428060642753613814151688322857484807845836623976981729207238463947987*R mod l in Montgomery form + pub static XX_MONT: Scalar29 = Scalar29( + [0x152b4d2e, 0x0571d53b, 0x1da6d964, 0x188663b6, + 0x1d1b5f92, 0x19d50e3f, 0x12306c29, 0x0c6f26fe, + 0x00030edb]); + + /// y = 6145104759870991071742105800796537629880401874866217824609283457819451087098 + pub static Y: Scalar29 = Scalar29( + [0x1e1458fa, 0x165ba838, 0x1d787b36, 0x0e577f3a, + 0x1d2baf06, 0x1d689a19, 0x1fff3047, 0x117704ab, + 0x000d9601]); + + /// x*y = 36752150652102274958925982391442301741 + pub static XY: Scalar29 = Scalar29( + [0x0ba7632d, 0x017736bb, 0x15c76138, 0x0c69daa1, + 0x000001ba, 0x00000000, 0x00000000, 0x00000000, + 0x00000000]); + + /// x*y = 3783114862749659543382438697751927473898937741870308063443170013240655651591*R mod l in Montgomery form + pub static XY_MONT: Scalar29 = Scalar29( + [0x077b51e1, 0x1c64e119, 0x02a19ef5, 0x18d2129e, + 0x00de0430, 0x045a7bc8, 0x04cfc7c9, 0x1c002681, + 0x000bdc1c]); + + /// a = 2351415481556538453565687241199399922945659411799870114962672658845158063753 + pub static A: Scalar29 = Scalar29( + [0x07b3be89, 0x02291b60, 0x14a99f03, 0x07dc3787, + 0x0a782aae, 0x16262525, 0x0cfdb93f, 0x13f5718d, + 0x000532da]); + + /// b = 4885590095775723760407499321843594317911456947580037491039278279440296187236 + pub static B: Scalar29 = Scalar29( + [0x15421564, 0x1e69fd72, 0x093d9692, 0x161785be, + 0x1587d69f, 0x09d9dada, 0x130246c0, 0x0c0a8e72, + 0x000acd25]); + + /// a+b = 0 + /// a-b = 4702830963113076907131374482398799845891318823599740229925345317690316127506 + pub static AB: Scalar29 = Scalar29( + [0x0f677d12, 0x045236c0, 0x09533e06, 0x0fb86f0f, + 0x14f0555c, 0x0c4c4a4a, 0x19fb727f, 0x07eae31a, + 0x000a65b5]); + + // c = (2^512 - 1) % l = 1627715501170711445284395025044413883736156588369414752970002579683115011840 + pub static C: Scalar29 = Scalar29( + [0x049c0f00, 0x00308f1a, 0x0164d1e9, 0x1c374ed1, + 0x1be65d00, 0x19e90bfa, 0x08f73bb1, 0x036f8613, + 0x00039941]); + + #[test] + fn mul_max() { + let res = Scalar29::mul(&X, &X); + for i in 0..9 { + assert!(res[i] == XX[i]); + } + } + + #[test] + fn square_max() { + let res = X.square(); + for i in 0..9 { + assert!(res[i] == XX[i]); + } + } + + #[test] + fn montgomery_mul_max() { + let res = Scalar29::montgomery_mul(&X, &X); + for i in 0..9 { + assert!(res[i] == XX_MONT[i]); + } + } + + #[test] + fn montgomery_square_max() { + let res = X.montgomery_square(); + for i in 0..9 { + assert!(res[i] == XX_MONT[i]); + } + } + + #[test] + fn mul() { + let res = Scalar29::mul(&X, &Y); + for i in 0..9 { + assert!(res[i] == XY[i]); + } + } + + #[test] + fn montgomery_mul() { + let res = Scalar29::montgomery_mul(&X, &Y); + for i in 0..9 { + assert!(res[i] == XY_MONT[i]); + } + } + + #[test] + fn add() { + let res = Scalar29::add(&A, &B); + let zero = Scalar29::zero(); + for i in 0..9 { + assert!(res[i] == zero[i]); + } + } + + #[test] + fn sub() { + let res = Scalar29::sub(&A, &B); + for i in 0..9 { + assert!(res[i] == AB[i]); + } + } + + #[test] + fn from_bytes_wide() { + let bignum = [255u8; 64]; // 2^512 - 1 + let reduced = Scalar29::from_bytes_wide(&bignum); + for i in 0..9 { + assert!(reduced[i] == C[i]); + } + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/constants.rs new file mode 100644 index 0000000..6cbc0b5 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/constants.rs @@ -0,0 +1,7759 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. + +use backend::serial::curve_models::AffineNielsPoint; +use super::field::FieldElement51; +use super::scalar::Scalar52; +use edwards::{EdwardsBasepointTable, EdwardsPoint}; +use window::{LookupTable, NafLookupTable8}; + +/// The value of minus one, equal to `-&FieldElement::one()` +pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([ + 2251799813685228, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247 +]); + +/// Edwards `d` value, equal to `-121665/121666 mod p`. +pub(crate) const EDWARDS_D: FieldElement51 = FieldElement51([ + 929955233495203, + 466365720129213, + 1662059464998953, + 2033849074728123, + 1442794654840575, +]); + +/// Edwards `2*d` value, equal to `2*(-121665/121666) mod p`. +pub(crate) const EDWARDS_D2: FieldElement51 = FieldElement51([ + 1859910466990425, + 932731440258426, + 1072319116312658, + 1815898335770999, + 633789495995903, +]); + +/// One minus edwards `d` value squared, equal to `(1 - (-121665/121666) mod p) pow 2` +pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement51 = FieldElement51([ + 1136626929484150, + 1998550399581263, + 496427632559748, + 118527312129759, + 45110755273534 +]); + +/// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2` +pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement51 = FieldElement51([ + 1507062230895904, + 1572317787530805, + 683053064812840, + 317374165784489, + 1572899562415810 +]); + +/// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const SQRT_AD_MINUS_ONE: FieldElement51 = FieldElement51([ + 2241493124984347, + 425987919032274, + 2207028919301688, + 1220490630685848, + 974799131293748, +]); + +/// `= 1/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const INVSQRT_A_MINUS_D: FieldElement51 = FieldElement51([ + 278908739862762, + 821645201101625, + 8113234426968, + 1777959178193151, + 2118520810568447, +]); + +/// Precomputed value of one of the square roots of -1 (mod p) +pub(crate) const SQRT_M1: FieldElement51 = FieldElement51([ + 1718705420411056, + 234908883556509, + 2233514472574048, + 2117202627021982, + 765476049583133, +]); + +/// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) +pub(crate) const APLUS2_OVER_FOUR: FieldElement51 = FieldElement51([121666, 0, 0, 0, 0]); + +/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation +/// for Curve25519 in its Montgomery form. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A: FieldElement51 = FieldElement51([486662, 0, 0, 0, 0]); + +/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A_NEG: FieldElement51 = FieldElement51([ + 2251799813198567, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, +]); + +/// `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493 +pub(crate) const L: Scalar52 = Scalar52([ + 0x0002631a5cf5d3ed, + 0x000dea2f79cd6581, + 0x000000000014def9, + 0x0000000000000000, + 0x0000100000000000, +]); + +/// `L` * `LFACTOR` = -1 (mod 2^52) +pub(crate) const LFACTOR: u64 = 0x51da312547e1b; + +/// `R` = R % L where R = 2^260 +pub(crate) const R: Scalar52 = Scalar52([ + 0x000f48bd6721e6ed, + 0x0003bab5ac67e45a, + 0x000fffffeb35e51b, + 0x000fffffffffffff, + 0x00000fffffffffff, +]); + +/// `RR` = (R^2) % L where R = 2^260 +pub(crate) const RR: Scalar52 = Scalar52([ + 0x0009d265e952d13b, + 0x000d63c715bea69f, + 0x0005be65cb687604, + 0x0003dceec73d217f, + 0x000009411b7c309a, +]); + +/// The Ed25519 basepoint, as an `EdwardsPoint`. +/// +/// This is called `_POINT` to distinguish it from +/// `ED25519_BASEPOINT_TABLE`, which should be used for scalar +/// multiplication (it's much faster). +pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { + X: FieldElement51([ + 1738742601995546, + 1146398526822698, + 2070867633025821, + 562264141797630, + 587772402128613, + ]), + Y: FieldElement51([ + 1801439850948184, + 1351079888211148, + 450359962737049, + 900719925474099, + 1801439850948198, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([ + 1841354044333475, + 16398895984059, + 755974180946558, + 900171276175154, + 1821297809914039, + ]), +}; + +/// The 8-torsion subgroup \\(\mathcal E [8]\\). +/// +/// In the case of Curve25519, it is cyclic; the \\(i\\)-th element of +/// the array is \\([i]P\\), where \\(P\\) is a point of order \\(8\\) +/// generating \\(\mathcal E[8]\\). +/// +/// Thus \\(\mathcal E[4]\\) is the points indexed by `0,2,4,6`, and +/// \\(\mathcal E[2]\\) is the points indexed by `0,4`. +pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN; + +/// Inner item used to hide limb constants from cargo doc output. +#[doc(hidden)] +pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ + EdwardsPoint { + X: FieldElement51([0, 0, 0, 0, 0]), + Y: FieldElement51([1, 0, 0, 0, 0]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51([ + 358744748052810, + 1691584618240980, + 977650209285361, + 1429865912637724, + 560044844278676, + ]), + Y: FieldElement51([ + 84926274344903, + 473620666599931, + 365590438845504, + 1028470286882429, + 2146499180330972, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([ + 1448326834587521, + 1857896831960481, + 1093722731865333, + 1677408490711241, + 1915505153018406, + ]), + }, + EdwardsPoint { + X: FieldElement51([ + 533094393274173, + 2016890930128738, + 18285341111199, + 134597186663265, + 1486323764102114, + ]), + Y: FieldElement51([0, 0, 0, 0, 0]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51([ + 358744748052810, + 1691584618240980, + 977650209285361, + 1429865912637724, + 560044844278676, + ]), + Y: FieldElement51([ + 2166873539340326, + 1778179147085316, + 1886209374839743, + 1223329526802818, + 105300633354275, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([ + 803472979097708, + 393902981724766, + 1158077081819914, + 574391322974006, + 336294660666841, + ]), + }, + EdwardsPoint { + X: FieldElement51([0, 0, 0, 0, 0]), + Y: FieldElement51([ + 2251799813685228, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51([ + 1893055065632419, + 560215195444267, + 1274149604399886, + 821933901047523, + 1691754969406571, + ]), + Y: FieldElement51([ + 2166873539340326, + 1778179147085316, + 1886209374839743, + 1223329526802818, + 105300633354275, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([ + 1448326834587521, + 1857896831960481, + 1093722731865333, + 1677408490711241, + 1915505153018406, + ]), + }, + EdwardsPoint { + X: FieldElement51([ + 1718705420411056, + 234908883556509, + 2233514472574048, + 2117202627021982, + 765476049583133, + ]), + Y: FieldElement51([0, 0, 0, 0, 0]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51([ + 1893055065632419, + 560215195444267, + 1274149604399886, + 821933901047523, + 1691754969406571, + ]), + Y: FieldElement51([ + 84926274344903, + 473620666599931, + 365590438845504, + 1028470286882429, + 2146499180330972, + ]), + Z: FieldElement51([1, 0, 0, 0, 0]), + T: FieldElement51([ + 803472979097708, + 393902981724766, + 1158077081819914, + 574391322974006, + 336294660666841, + ]), + }, +]; + +/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). +pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; + +/// Inner constant, used to avoid filling the docs with precomputed points. +#[doc(hidden)] +pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = + EdwardsBasepointTable([ + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3540182452943730, + 2497478415033846, + 2521227595762870, + 1462984067271729, + 2389212253076811, + ]), + y_minus_x: FieldElement51([ + 62697248952638, + 204681361388450, + 631292143396476, + 338455783676468, + 1213667448819585, + ]), + xy2d: FieldElement51([ + 301289933810280, + 1259582250014073, + 1422107436869536, + 796239922652654, + 1953934009299142, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3632771708514775, + 790832306631235, + 2067202295274102, + 1995808275510000, + 1566530869037010, + ]), + y_minus_x: FieldElement51([ + 463307831301544, + 432984605774163, + 1610641361907204, + 750899048855000, + 1894842303421586, + ]), + xy2d: FieldElement51([ + 748439484463711, + 1033211726465151, + 1396005112841647, + 1611506220286469, + 1972177495910992, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1601611775252272, + 1720807796594148, + 1132070835939856, + 3512254832574799, + 2147779492816910, + ]), + y_minus_x: FieldElement51([ + 316559037616741, + 2177824224946892, + 1459442586438991, + 1461528397712656, + 751590696113597, + ]), + xy2d: FieldElement51([ + 1850748884277385, + 1200145853858453, + 1068094770532492, + 672251375690438, + 1586055907191707, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 934282339813791, + 1846903124198670, + 1172395437954843, + 1007037127761661, + 1830588347719256, + ]), + y_minus_x: FieldElement51([ + 1694390458783935, + 1735906047636159, + 705069562067493, + 648033061693059, + 696214010414170, + ]), + xy2d: FieldElement51([ + 1121406372216585, + 192876649532226, + 190294192191717, + 1994165897297032, + 2245000007398739, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 769950342298400, + 2384754244604994, + 3095885746880802, + 3225892188161580, + 2977876099231263, + ]), + y_minus_x: FieldElement51([ + 425251763115706, + 608463272472562, + 442562545713235, + 837766094556764, + 374555092627893, + ]), + xy2d: FieldElement51([ + 1086255230780037, + 274979815921559, + 1960002765731872, + 929474102396301, + 1190409889297339, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1388594989461809, + 316767091099457, + 2646098655878230, + 1230079486801004, + 1440737038838979, + ]), + y_minus_x: FieldElement51([ + 7380825640100, + 146210432690483, + 304903576448906, + 1198869323871120, + 997689833219095, + ]), + xy2d: FieldElement51([ + 1181317918772081, + 114573476638901, + 262805072233344, + 265712217171332, + 294181933805782, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2916800678241215, + 2065379846933858, + 2622030924071124, + 2602788184473875, + 1233371373142984, + ]), + y_minus_x: FieldElement51([ + 2019367628972465, + 676711900706637, + 110710997811333, + 1108646842542025, + 517791959672113, + ]), + xy2d: FieldElement51([ + 965130719900578, + 247011430587952, + 526356006571389, + 91986625355052, + 2157223321444601, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4320419353804412, + 4218074731744053, + 957728544705548, + 729906502578991, + 2411634706750414, + ]), + y_minus_x: FieldElement51([ + 2073601412052185, + 31021124762708, + 264500969797082, + 248034690651703, + 1030252227928288, + ]), + xy2d: FieldElement51([ + 551790716293402, + 1989538725166328, + 801169423371717, + 2052451893578887, + 678432056995012, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1368953770187805, + 3042147450398169, + 2689308289352409, + 2142576377050579, + 1932081720066286, + ]), + y_minus_x: FieldElement51([ + 953638594433374, + 1092333936795051, + 1419774766716690, + 805677984380077, + 859228993502513, + ]), + xy2d: FieldElement51([ + 1200766035879111, + 20142053207432, + 1465634435977050, + 1645256912097844, + 295121984874596, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1735718747031538, + 1248237894295956, + 1204753118328107, + 976066523550493, + 2317743583219840, + ]), + y_minus_x: FieldElement51([ + 1060098822528990, + 1586825862073490, + 212301317240126, + 1975302711403555, + 666724059764335, + ]), + xy2d: FieldElement51([ + 1091990273418756, + 1572899409348578, + 80968014455247, + 306009358661350, + 1520450739132526, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3732317023121341, + 1511153322193951, + 3496143672676420, + 2556587964178488, + 2620936670181690, + ]), + y_minus_x: FieldElement51([ + 2151330273626164, + 762045184746182, + 1688074332551515, + 823046109005759, + 907602769079491, + ]), + xy2d: FieldElement51([ + 2047386910586836, + 168470092900250, + 1552838872594810, + 340951180073789, + 360819374702533, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1982622644432037, + 2014393600336956, + 2380709022489462, + 3869592437614438, + 2357094095599062, + ]), + y_minus_x: FieldElement51([ + 980234343912898, + 1712256739246056, + 588935272190264, + 204298813091998, + 841798321043288, + ]), + xy2d: FieldElement51([ + 197561292938973, + 454817274782871, + 1963754960082318, + 2113372252160468, + 971377527342673, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2416499262514576, + 2254927265442919, + 3451304785234000, + 1766155447043651, + 1899238924683527, + ]), + y_minus_x: FieldElement51([ + 732262946680281, + 1674412764227063, + 2182456405662809, + 1350894754474250, + 558458873295247, + ]), + xy2d: FieldElement51([ + 2103305098582922, + 1960809151316468, + 715134605001343, + 1454892949167181, + 40827143824949, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1239289043050193, + 1744654158124578, + 758702410031698, + 4048562808759936, + 2253402870349013, + ]), + y_minus_x: FieldElement51([ + 2232056027107988, + 987343914584615, + 2115594492994461, + 1819598072792159, + 1119305654014850, + ]), + xy2d: FieldElement51([ + 320153677847348, + 939613871605645, + 641883205761567, + 1930009789398224, + 329165806634126, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3232730304159378, + 1242488692177892, + 1251446316964684, + 1086618677993530, + 1961430968465772, + ]), + y_minus_x: FieldElement51([ + 276821765317453, + 1536835591188030, + 1305212741412361, + 61473904210175, + 2051377036983058, + ]), + xy2d: FieldElement51([ + 833449923882501, + 1750270368490475, + 1123347002068295, + 185477424765687, + 278090826653186, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 794524995833413, + 1849907304548286, + 2305148486158393, + 1272368559505216, + 1147304168324779, + ]), + y_minus_x: FieldElement51([ + 1504846112759364, + 1203096289004681, + 562139421471418, + 274333017451844, + 1284344053775441, + ]), + xy2d: FieldElement51([ + 483048732424432, + 2116063063343382, + 30120189902313, + 292451576741007, + 1156379271702225, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3180171966714267, + 2147692869914563, + 1455665844462196, + 1986737809425946, + 2437006863943337, + ]), + y_minus_x: FieldElement51([ + 137732961814206, + 706670923917341, + 1387038086865771, + 1965643813686352, + 1384777115696347, + ]), + xy2d: FieldElement51([ + 481144981981577, + 2053319313589856, + 2065402289827512, + 617954271490316, + 1106602634668125, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2948097833334040, + 3145099472726142, + 1148636718636008, + 2278533891034865, + 2203955659340680, + ]), + y_minus_x: FieldElement51([ + 657390353372855, + 998499966885562, + 991893336905797, + 810470207106761, + 343139804608786, + ]), + xy2d: FieldElement51([ + 791736669492960, + 934767652997115, + 824656780392914, + 1759463253018643, + 361530362383518, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2022541353055578, + 4346500076272714, + 3802807888710933, + 2494585331103411, + 2947785218648809, + ]), + y_minus_x: FieldElement51([ + 1287487199965223, + 2215311941380308, + 1552928390931986, + 1664859529680196, + 1125004975265243, + ]), + xy2d: FieldElement51([ + 677434665154918, + 989582503122485, + 1817429540898386, + 1052904935475344, + 1143826298169798, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2619066141993637, + 2570231002607651, + 2947429167440602, + 2885885471266079, + 2276381426249673, + ]), + y_minus_x: FieldElement51([ + 773360688841258, + 1815381330538070, + 363773437667376, + 539629987070205, + 783280434248437, + ]), + xy2d: FieldElement51([ + 180820816194166, + 168937968377394, + 748416242794470, + 1227281252254508, + 1567587861004268, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2730575372268893, + 2062896624554806, + 2951191072970647, + 2609899222113120, + 1277310261461760, + ]), + y_minus_x: FieldElement51([ + 1984740906540026, + 1079164179400229, + 1056021349262661, + 1659958556483663, + 1088529069025527, + ]), + xy2d: FieldElement51([ + 580736401511151, + 1842931091388998, + 1177201471228238, + 2075460256527244, + 1301133425678027, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1515728832059163, + 1575261009617579, + 1510246567196186, + 2442877836294952, + 2368461529974388, + ]), + y_minus_x: FieldElement51([ + 1295295738269652, + 1714742313707026, + 545583042462581, + 2034411676262552, + 1513248090013606, + ]), + xy2d: FieldElement51([ + 230710545179830, + 30821514358353, + 760704303452229, + 390668103790604, + 573437871383156, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3421179921230875, + 2514967047430861, + 4274701112739695, + 3071700566936367, + 4275698278559832, + ]), + y_minus_x: FieldElement51([ + 2102254323485823, + 1570832666216754, + 34696906544624, + 1993213739807337, + 70638552271463, + ]), + xy2d: FieldElement51([ + 894132856735058, + 548675863558441, + 845349339503395, + 1942269668326667, + 1615682209874691, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3539470031223082, + 1222355136884919, + 1846481788678694, + 1150426571265110, + 1613523400722047, + ]), + y_minus_x: FieldElement51([ + 793388516527298, + 1315457083650035, + 1972286999342417, + 1901825953052455, + 338269477222410, + ]), + xy2d: FieldElement51([ + 550201530671806, + 778605267108140, + 2063911101902983, + 115500557286349, + 2041641272971022, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 717255318455100, + 519313764361315, + 2080406977303708, + 541981206705521, + 774328150311600, + ]), + y_minus_x: FieldElement51([ + 261715221532238, + 1795354330069993, + 1496878026850283, + 499739720521052, + 389031152673770, + ]), + xy2d: FieldElement51([ + 1997217696294013, + 1717306351628065, + 1684313917746180, + 1644426076011410, + 1857378133465451, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3727234538477877, + 2328731709971226, + 3368528843456914, + 2002544139318041, + 2977347647489186, + ]), + y_minus_x: FieldElement51([ + 2022306639183567, + 726296063571875, + 315345054448644, + 1058733329149221, + 1448201136060677, + ]), + xy2d: FieldElement51([ + 1710065158525665, + 1895094923036397, + 123988286168546, + 1145519900776355, + 1607510767693874, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2813405189107769, + 1071733543815036, + 2383296312486238, + 1946868434569998, + 3079937947649451, + ]), + y_minus_x: FieldElement51([ + 1548495173745801, + 442310529226540, + 998072547000384, + 553054358385281, + 644824326376171, + ]), + xy2d: FieldElement51([ + 1445526537029440, + 2225519789662536, + 914628859347385, + 1064754194555068, + 1660295614401091, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3451490036797185, + 2275827949507588, + 2318438102929588, + 2309425969971222, + 2816893781664854, + ]), + y_minus_x: FieldElement51([ + 876926774220824, + 554618976488214, + 1012056309841565, + 839961821554611, + 1414499340307677, + ]), + xy2d: FieldElement51([ + 703047626104145, + 1266841406201770, + 165556500219173, + 486991595001879, + 1011325891650656, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1622861044480487, + 1156394801573634, + 4120932379100752, + 2578903799462977, + 2095342781472283, + ]), + y_minus_x: FieldElement51([ + 334886927423922, + 489511099221528, + 129160865966726, + 1720809113143481, + 619700195649254, + ]), + xy2d: FieldElement51([ + 1646545795166119, + 1758370782583567, + 714746174550637, + 1472693650165135, + 898994790308209, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2585203586724508, + 2547572356138185, + 1693106465353609, + 912330357530760, + 2723035471635610, + ]), + y_minus_x: FieldElement51([ + 1811196219982022, + 1068969825533602, + 289602974833439, + 1988956043611592, + 863562343398367, + ]), + xy2d: FieldElement51([ + 906282429780072, + 2108672665779781, + 432396390473936, + 150625823801893, + 1708930497638539, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 925664675702309, + 2273216662253932, + 4083236455546587, + 601157008940112, + 2623617868729744, + ]), + y_minus_x: FieldElement51([ + 1479786007267725, + 1738881859066675, + 68646196476567, + 2146507056100328, + 1247662817535471, + ]), + xy2d: FieldElement51([ + 52035296774456, + 939969390708103, + 312023458773250, + 59873523517659, + 1231345905848899, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2895154920100990, + 2541986621181021, + 2013561737429022, + 2571447883196794, + 2645536492181409, + ]), + y_minus_x: FieldElement51([ + 129358342392716, + 1932811617704777, + 1176749390799681, + 398040349861790, + 1170779668090425, + ]), + xy2d: FieldElement51([ + 2051980782668029, + 121859921510665, + 2048329875753063, + 1235229850149665, + 519062146124755, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3859970785658325, + 2667608874045675, + 1350468408164765, + 2038620059057678, + 3278704299674360, + ]), + y_minus_x: FieldElement51([ + 1837656083115103, + 1510134048812070, + 906263674192061, + 1821064197805734, + 565375124676301, + ]), + xy2d: FieldElement51([ + 578027192365650, + 2034800251375322, + 2128954087207123, + 478816193810521, + 2196171989962750, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1633188840273120, + 3104586986058956, + 1548762607215795, + 1266275218902681, + 3359018017010381, + ]), + y_minus_x: FieldElement51([ + 462189358480054, + 1784816734159228, + 1611334301651368, + 1303938263943540, + 707589560319424, + ]), + xy2d: FieldElement51([ + 1038829280972848, + 38176604650029, + 753193246598573, + 1136076426528122, + 595709990562434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3660251634545082, + 2194984964010832, + 2198361797561729, + 1061962440055713, + 1645147963442934, + ]), + y_minus_x: FieldElement51([ + 4701053362120, + 1647641066302348, + 1047553002242085, + 1923635013395977, + 206970314902065, + ]), + xy2d: FieldElement51([ + 1750479161778571, + 1362553355169293, + 1891721260220598, + 966109370862782, + 1024913988299801, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2464498862816952, + 1117950018299774, + 1873945661751056, + 3655602735669306, + 2382695896337945, + ]), + y_minus_x: FieldElement51([ + 636808533673210, + 1262201711667560, + 390951380330599, + 1663420692697294, + 561951321757406, + ]), + xy2d: FieldElement51([ + 520731594438141, + 1446301499955692, + 273753264629267, + 1565101517999256, + 1019411827004672, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3178327305714638, + 3443653291096626, + 734233225181170, + 2435838701226518, + 4042225960010590, + ]), + y_minus_x: FieldElement51([ + 1464651961852572, + 1483737295721717, + 1519450561335517, + 1161429831763785, + 405914998179977, + ]), + xy2d: FieldElement51([ + 996126634382301, + 796204125879525, + 127517800546509, + 344155944689303, + 615279846169038, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2990523894660505, + 2188666632415295, + 1961313708559162, + 1506545807547587, + 3403101452654988, + ]), + y_minus_x: FieldElement51([ + 622917337413835, + 1218989177089035, + 1284857712846592, + 970502061709359, + 351025208117090, + ]), + xy2d: FieldElement51([ + 2067814584765580, + 1677855129927492, + 2086109782475197, + 235286517313238, + 1416314046739645, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2838644076315587, + 2559244195637442, + 458399356043425, + 2853867838192310, + 3280348017100490, + ]), + y_minus_x: FieldElement51([ + 678489922928203, + 2016657584724032, + 90977383049628, + 1026831907234582, + 615271492942522, + ]), + xy2d: FieldElement51([ + 301225714012278, + 1094837270268560, + 1202288391010439, + 644352775178361, + 1647055902137983, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1210746697896459, + 1416608304244708, + 2938287290903104, + 3496931005119382, + 3303038150540984, + ]), + y_minus_x: FieldElement51([ + 1135604073198207, + 1683322080485474, + 769147804376683, + 2086688130589414, + 900445683120379, + ]), + xy2d: FieldElement51([ + 1971518477615628, + 401909519527336, + 448627091057375, + 1409486868273821, + 1214789035034363, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1364039144731711, + 1897497433586190, + 2203097701135459, + 2397261210496499, + 1349844460790698, + ]), + y_minus_x: FieldElement51([ + 1045230323257973, + 818206601145807, + 630513189076103, + 1672046528998132, + 807204017562437, + ]), + xy2d: FieldElement51([ + 439961968385997, + 386362664488986, + 1382706320807688, + 309894000125359, + 2207801346498567, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3480804500082836, + 3172443782216110, + 2375775707596425, + 2933223806901024, + 1400559197080972, + ]), + y_minus_x: FieldElement51([ + 2003766096898049, + 170074059235165, + 1141124258967971, + 1485419893480973, + 1573762821028725, + ]), + xy2d: FieldElement51([ + 729905708611432, + 1270323270673202, + 123353058984288, + 426460209632942, + 2195574535456672, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1271140255321216, + 2044363183174497, + 2303925201319937, + 3696920060379952, + 3194341800024331, + ]), + y_minus_x: FieldElement51([ + 1761608437466135, + 583360847526804, + 1586706389685493, + 2157056599579261, + 1170692369685772, + ]), + xy2d: FieldElement51([ + 871476219910823, + 1878769545097794, + 2241832391238412, + 548957640601001, + 690047440233174, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2548994545820755, + 1366347803776819, + 3552985325930849, + 561849853336293, + 1533554921345731, + ]), + y_minus_x: FieldElement51([ + 999628998628371, + 1132836708493400, + 2084741674517453, + 469343353015612, + 678782988708035, + ]), + xy2d: FieldElement51([ + 2189427607417022, + 699801937082607, + 412764402319267, + 1478091893643349, + 2244675696854460, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3964091869651792, + 2456213404310121, + 3657538451018088, + 2660781114515010, + 3112882032961968, + ]), + y_minus_x: FieldElement51([ + 508561155940631, + 966928475686665, + 2236717801150132, + 424543858577297, + 2089272956986143, + ]), + xy2d: FieldElement51([ + 221245220129925, + 1156020201681217, + 491145634799213, + 542422431960839, + 828100817819207, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2405556784925632, + 1299874139923976, + 2644898978945750, + 1058234455773021, + 996989038681183, + ]), + y_minus_x: FieldElement51([ + 559086812798481, + 573177704212711, + 1629737083816402, + 1399819713462595, + 1646954378266038, + ]), + xy2d: FieldElement51([ + 1887963056288059, + 228507035730124, + 1468368348640282, + 930557653420194, + 613513962454686, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1224529808187534, + 1577022856702685, + 2206946542980843, + 625883007765001, + 2531730607197406, + ]), + y_minus_x: FieldElement51([ + 1076287717051609, + 1114455570543035, + 187297059715481, + 250446884292121, + 1885187512550540, + ]), + xy2d: FieldElement51([ + 902497362940219, + 76749815795675, + 1657927525633846, + 1420238379745202, + 1340321636548352, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1129576631190765, + 3533793823712575, + 996844254743017, + 2509676177174497, + 3402650555740265, + ]), + y_minus_x: FieldElement51([ + 628740660038789, + 1943038498527841, + 467786347793886, + 1093341428303375, + 235413859513003, + ]), + xy2d: FieldElement51([ + 237425418909360, + 469614029179605, + 1512389769174935, + 1241726368345357, + 441602891065214, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3988217766743784, + 726531315520507, + 1833335034432527, + 1629442561574747, + 2876218732971333, + ]), + y_minus_x: FieldElement51([ + 1960754663920689, + 497040957888962, + 1909832851283095, + 1271432136996826, + 2219780368020940, + ]), + xy2d: FieldElement51([ + 1537037379417136, + 1358865369268262, + 2130838645654099, + 828733687040705, + 1999987652890901, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 629042105241795, + 1098854999137608, + 887281544569320, + 3674901833560025, + 2259711072636808, + ]), + y_minus_x: FieldElement51([ + 1811562332665373, + 1501882019007673, + 2213763501088999, + 359573079719636, + 36370565049116, + ]), + xy2d: FieldElement51([ + 218907117361280, + 1209298913016966, + 1944312619096112, + 1130690631451061, + 1342327389191701, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1369976867854685, + 1396479602419169, + 4017456468084104, + 2203659200586298, + 3250127649802489, + ]), + y_minus_x: FieldElement51([ + 2230701885562825, + 1348173180338974, + 2172856128624598, + 1426538746123771, + 444193481326151, + ]), + xy2d: FieldElement51([ + 784210426627951, + 918204562375674, + 1284546780452985, + 1324534636134684, + 1872449409642708, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2571438643225542, + 2848082470493653, + 2037902696412607, + 1557219121643918, + 341938082688094, + ]), + y_minus_x: FieldElement51([ + 1901860206695915, + 2004489122065736, + 1625847061568236, + 973529743399879, + 2075287685312905, + ]), + xy2d: FieldElement51([ + 1371853944110545, + 1042332820512553, + 1949855697918254, + 1791195775521505, + 37487364849293, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 687200189577836, + 1082536651125675, + 2896024754556794, + 2592723009743198, + 2595381160432643, + ]), + y_minus_x: FieldElement51([ + 2082717129583892, + 27829425539422, + 145655066671970, + 1690527209845512, + 1865260509673478, + ]), + xy2d: FieldElement51([ + 1059729620568824, + 2163709103470266, + 1440302280256872, + 1769143160546397, + 869830310425069, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3861316033464273, + 777277757338816, + 2101121130363987, + 550762194946473, + 1905542338659364, + ]), + y_minus_x: FieldElement51([ + 2024821921041576, + 426948675450149, + 595133284085473, + 471860860885970, + 600321679413000, + ]), + xy2d: FieldElement51([ + 598474602406721, + 1468128276358244, + 1191923149557635, + 1501376424093216, + 1281662691293476, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1721138489890688, + 1264336102277790, + 2684864359106535, + 1359988423149465, + 3813671107094695, + ]), + y_minus_x: FieldElement51([ + 719520245587143, + 393380711632345, + 132350400863381, + 1543271270810729, + 1819543295798660, + ]), + xy2d: FieldElement51([ + 396397949784152, + 1811354474471839, + 1362679985304303, + 2117033964846756, + 498041172552279, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1812471844975748, + 1856491995543149, + 126579494584102, + 3288044672967868, + 1975108050082549, + ]), + y_minus_x: FieldElement51([ + 650623932407995, + 1137551288410575, + 2125223403615539, + 1725658013221271, + 2134892965117796, + ]), + xy2d: FieldElement51([ + 522584000310195, + 1241762481390450, + 1743702789495384, + 2227404127826575, + 1686746002148897, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 427904865186293, + 1703211129693455, + 1585368107547509, + 3688784302429584, + 3012988348299225, + ]), + y_minus_x: FieldElement51([ + 318101947455002, + 248138407995851, + 1481904195303927, + 309278454311197, + 1258516760217879, + ]), + xy2d: FieldElement51([ + 1275068538599310, + 513726919533379, + 349926553492294, + 688428871968420, + 1702400196000666, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3313663849950481, + 3213411074010628, + 2573659446386085, + 3297400443644764, + 1985130202504037, + ]), + y_minus_x: FieldElement51([ + 1558816436882417, + 1962896332636523, + 1337709822062152, + 1501413830776938, + 294436165831932, + ]), + xy2d: FieldElement51([ + 818359826554971, + 1862173000996177, + 626821592884859, + 573655738872376, + 1749691246745455, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1988022651432119, + 3333911312271288, + 1834020786104820, + 3706626690108935, + 692929915223121, + ]), + y_minus_x: FieldElement51([ + 2146513703733331, + 584788900394667, + 464965657279958, + 2183973639356127, + 238371159456790, + ]), + xy2d: FieldElement51([ + 1129007025494441, + 2197883144413266, + 265142755578169, + 971864464758890, + 1983715884903702, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1291366624493056, + 2633256531874362, + 1711482489312443, + 1815233647702022, + 3144079596677715, + ]), + y_minus_x: FieldElement51([ + 444548969917454, + 1452286453853356, + 2113731441506810, + 645188273895859, + 810317625309512, + ]), + xy2d: FieldElement51([ + 2242724082797924, + 1373354730327868, + 1006520110883049, + 2147330369940688, + 1151816104883620, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3997520014069025, + 4163522956860564, + 2056329390702073, + 2607026987995097, + 3131032608056347, + ]), + y_minus_x: FieldElement51([ + 163723479936298, + 115424889803150, + 1156016391581227, + 1894942220753364, + 1970549419986329, + ]), + xy2d: FieldElement51([ + 681981452362484, + 267208874112496, + 1374683991933094, + 638600984916117, + 646178654558546, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2265178468539480, + 2358037120714814, + 1944412051589650, + 4093776581610705, + 2482502633520820, + ]), + y_minus_x: FieldElement51([ + 260683893467075, + 854060306077237, + 913639551980112, + 4704576840123, + 280254810808712, + ]), + xy2d: FieldElement51([ + 715374893080287, + 1173334812210491, + 1806524662079626, + 1894596008000979, + 398905715033393, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2751826223412909, + 3848231101880618, + 1420380351989369, + 3237011375206737, + 392444930785632, + ]), + y_minus_x: FieldElement51([ + 2096421546958141, + 1922523000950363, + 789831022876840, + 427295144688779, + 320923973161730, + ]), + xy2d: FieldElement51([ + 1927770723575450, + 1485792977512719, + 1850996108474547, + 551696031508956, + 2126047405475647, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2112099158080129, + 2994370617594963, + 2258284371762679, + 1951119898618915, + 2344890196388664, + ]), + y_minus_x: FieldElement51([ + 383905201636970, + 859946997631870, + 855623867637644, + 1017125780577795, + 794250831877809, + ]), + xy2d: FieldElement51([ + 77571826285752, + 999304298101753, + 487841111777762, + 1038031143212339, + 339066367948762, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2926794589205781, + 2517835660016036, + 826951213393477, + 1405007746162285, + 1781791018620876, + ]), + y_minus_x: FieldElement51([ + 1001412661522686, + 348196197067298, + 1666614366723946, + 888424995032760, + 580747687801357, + ]), + xy2d: FieldElement51([ + 1939560076207777, + 1409892634407635, + 552574736069277, + 383854338280405, + 190706709864139, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2177087163428741, + 1439255351721944, + 3459870654068041, + 2230616362004768, + 1396886392021913, + ]), + y_minus_x: FieldElement51([ + 676962063230039, + 1880275537148808, + 2046721011602706, + 888463247083003, + 1318301552024067, + ]), + xy2d: FieldElement51([ + 1466980508178206, + 617045217998949, + 652303580573628, + 757303753529064, + 207583137376902, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3762856566592150, + 2357202940576524, + 2745234706458093, + 1091943425335975, + 1802717338077427, + ]), + y_minus_x: FieldElement51([ + 1853982405405128, + 1878664056251147, + 1528011020803992, + 1019626468153565, + 1128438412189035, + ]), + xy2d: FieldElement51([ + 1963939888391106, + 293456433791664, + 697897559513649, + 985882796904380, + 796244541237972, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2668570812315008, + 2641455366112301, + 1314476859406755, + 1749382513022778, + 3413705412424739, + ]), + y_minus_x: FieldElement51([ + 1428358296490651, + 1027115282420478, + 304840698058337, + 441410174026628, + 1819358356278573, + ]), + xy2d: FieldElement51([ + 204943430200135, + 1554861433819175, + 216426658514651, + 264149070665950, + 2047097371738319, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1934415182909015, + 1393285083565062, + 2768209145458208, + 3409490548679139, + 2372839480279515, + ]), + y_minus_x: FieldElement51([ + 662035583584445, + 286736105093098, + 1131773000510616, + 818494214211439, + 472943792054479, + ]), + xy2d: FieldElement51([ + 665784778135882, + 1893179629898606, + 808313193813106, + 276797254706413, + 1563426179676396, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 945205108984213, + 2778077376644543, + 1324180513733565, + 1666970227868664, + 2405347422974421, + ]), + y_minus_x: FieldElement51([ + 2031433403516252, + 203996615228162, + 170487168837083, + 981513604791390, + 843573964916831, + ]), + xy2d: FieldElement51([ + 1476570093962618, + 838514669399805, + 1857930577281364, + 2017007352225784, + 317085545220047, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1461557121912823, + 1600674043318359, + 2157134900399597, + 1670641601940616, + 2379565397488531, + ]), + y_minus_x: FieldElement51([ + 1293543509393474, + 2143624609202546, + 1058361566797508, + 214097127393994, + 946888515472729, + ]), + xy2d: FieldElement51([ + 357067959932916, + 1290876214345711, + 521245575443703, + 1494975468601005, + 800942377643885, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2817916472785262, + 820247422481739, + 994464017954148, + 2578957425371613, + 2344391131796991, + ]), + y_minus_x: FieldElement51([ + 617256647603209, + 1652107761099439, + 1857213046645471, + 1085597175214970, + 817432759830522, + ]), + xy2d: FieldElement51([ + 771808161440705, + 1323510426395069, + 680497615846440, + 851580615547985, + 1320806384849017, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1219260086131896, + 2898968820282063, + 2331400938444953, + 2161724213426747, + 2656661710745446, + ]), + y_minus_x: FieldElement51([ + 1327968293887866, + 1335500852943256, + 1401587164534264, + 558137311952440, + 1551360549268902, + ]), + xy2d: FieldElement51([ + 417621685193956, + 1429953819744454, + 396157358457099, + 1940470778873255, + 214000046234152, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1268047918491954, + 2172375426948536, + 1533916099229249, + 1761293575457130, + 3842422480712013, + ]), + y_minus_x: FieldElement51([ + 1627072914981959, + 2211603081280073, + 1912369601616504, + 1191770436221309, + 2187309757525860, + ]), + xy2d: FieldElement51([ + 1149147819689533, + 378692712667677, + 828475842424202, + 2218619146419342, + 70688125792186, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3551539230764990, + 3690416477138006, + 3788528892189659, + 2053896748919837, + 3260220846276494, + ]), + y_minus_x: FieldElement51([ + 2040723824657366, + 399555637875075, + 632543375452995, + 872649937008051, + 1235394727030233, + ]), + xy2d: FieldElement51([ + 2211311599327900, + 2139787259888175, + 938706616835350, + 12609661139114, + 2081897930719789, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1324994503390431, + 2588782144267879, + 1183998925654176, + 3343454479598522, + 2300527487656566, + ]), + y_minus_x: FieldElement51([ + 1845522914617879, + 1222198248335542, + 150841072760134, + 1927029069940982, + 1189913404498011, + ]), + xy2d: FieldElement51([ + 1079559557592645, + 2215338383666441, + 1903569501302605, + 49033973033940, + 305703433934152, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2346453219102138, + 3637921163538246, + 3313930291577009, + 2288353761164521, + 3085469462634093, + ]), + y_minus_x: FieldElement51([ + 1432015813136298, + 440364795295369, + 1395647062821501, + 1976874522764578, + 934452372723352, + ]), + xy2d: FieldElement51([ + 1296625309219774, + 2068273464883862, + 1858621048097805, + 1492281814208508, + 2235868981918946, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1490330266465551, + 1858795661361448, + 3688040948655011, + 2546373032584894, + 3459939824714180, + ]), + y_minus_x: FieldElement51([ + 1282462923712748, + 741885683986255, + 2027754642827561, + 518989529541027, + 1826610009555945, + ]), + xy2d: FieldElement51([ + 1525827120027511, + 723686461809551, + 1597702369236987, + 244802101764964, + 1502833890372311, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2365421849929742, + 3485539881431101, + 2925909765963743, + 2114345180342964, + 2418564326541511, + ]), + y_minus_x: FieldElement51([ + 2041668749310338, + 2184405322203901, + 1633400637611036, + 2110682505536899, + 2048144390084644, + ]), + xy2d: FieldElement51([ + 503058759232932, + 760293024620937, + 2027152777219493, + 666858468148475, + 1539184379870952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1916168475367211, + 3167426246226591, + 883217071712574, + 363427871374304, + 1976029821251593, + ]), + y_minus_x: FieldElement51([ + 678039535434506, + 570587290189340, + 1605302676614120, + 2147762562875701, + 1706063797091704, + ]), + xy2d: FieldElement51([ + 1439489648586438, + 2194580753290951, + 832380563557396, + 561521973970522, + 584497280718389, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2439789269177838, + 681223515948274, + 1933493571072456, + 1872921007304880, + 2739962177820919, + ]), + y_minus_x: FieldElement51([ + 1413466089534451, + 410844090765630, + 1397263346404072, + 408227143123410, + 1594561803147811, + ]), + xy2d: FieldElement51([ + 2102170800973153, + 719462588665004, + 1479649438510153, + 1097529543970028, + 1302363283777685, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3193865531532443, + 3321113493038208, + 2007341951411050, + 2322773230131539, + 1419433790163705, + ]), + y_minus_x: FieldElement51([ + 1146565545556377, + 1661971299445212, + 406681704748893, + 564452436406089, + 1109109865829139, + ]), + xy2d: FieldElement51([ + 2214421081775077, + 1165671861210569, + 1890453018796184, + 3556249878661, + 442116172656317, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3005630360306059, + 1666955059895018, + 1530775289309243, + 3371786842789394, + 2164156153857579, + ]), + y_minus_x: FieldElement51([ + 615171919212796, + 1523849404854568, + 854560460547503, + 2067097370290715, + 1765325848586042, + ]), + xy2d: FieldElement51([ + 1094538949313667, + 1796592198908825, + 870221004284388, + 2025558921863561, + 1699010892802384, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1951351290725195, + 1916457206844795, + 2449824998123274, + 1909076887557594, + 1938542290318919, + ]), + y_minus_x: FieldElement51([ + 1014323197538413, + 869150639940606, + 1756009942696599, + 1334952557375672, + 1544945379082874, + ]), + xy2d: FieldElement51([ + 764055910920305, + 1603590757375439, + 146805246592357, + 1843313433854297, + 954279890114939, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 80113526615731, + 764536758732259, + 3306939158785481, + 2721052465444637, + 2869697326116762, + ]), + y_minus_x: FieldElement51([ + 74497112547268, + 740094153192149, + 1745254631717581, + 727713886503130, + 1283034364416928, + ]), + xy2d: FieldElement51([ + 525892105991110, + 1723776830270342, + 1476444848991936, + 573789489857760, + 133864092632978, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2794411533877810, + 1986812262899320, + 1162535242465837, + 2733298779828712, + 2796400347268869, + ]), + y_minus_x: FieldElement51([ + 64123227344372, + 1239927720647794, + 1360722983445904, + 222610813654661, + 62429487187991, + ]), + xy2d: FieldElement51([ + 1793193323953132, + 91096687857833, + 70945970938921, + 2158587638946380, + 1537042406482111, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1895854577604590, + 3646695522634664, + 1728548428495943, + 3392664713925397, + 2815445147288308, + ]), + y_minus_x: FieldElement51([ + 141358280486863, + 91435889572504, + 1087208572552643, + 1829599652522921, + 1193307020643647, + ]), + xy2d: FieldElement51([ + 1611230858525381, + 950720175540785, + 499589887488610, + 2001656988495019, + 88977313255908, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3440880315164906, + 2184348804772596, + 3292618539427567, + 2018318290311833, + 1712060030915354, + ]), + y_minus_x: FieldElement51([ + 873966876953756, + 1090638350350440, + 1708559325189137, + 672344594801910, + 1320437969700239, + ]), + xy2d: FieldElement51([ + 1508590048271766, + 1131769479776094, + 101550868699323, + 428297785557897, + 561791648661744, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3008217384184691, + 2489682092917849, + 2136263418594015, + 1701968045454886, + 2955512998822720, + ]), + y_minus_x: FieldElement51([ + 1781187809325462, + 1697624151492346, + 1381393690939988, + 175194132284669, + 1483054666415238, + ]), + xy2d: FieldElement51([ + 2175517777364616, + 708781536456029, + 955668231122942, + 1967557500069555, + 2021208005604118, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3366935780292116, + 2476017186636029, + 915967306279221, + 593866251291540, + 2813546907893254, + ]), + y_minus_x: FieldElement51([ + 1443163092879439, + 391875531646162, + 2180847134654632, + 464538543018753, + 1594098196837178, + ]), + xy2d: FieldElement51([ + 850858855888869, + 319436476624586, + 327807784938441, + 740785849558761, + 17128415486016, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2132756334090048, + 2788047633840893, + 2300706964962114, + 2860273011285942, + 3513489358708031, + ]), + y_minus_x: FieldElement51([ + 1525176236978354, + 974205476721062, + 293436255662638, + 148269621098039, + 137961998433963, + ]), + xy2d: FieldElement51([ + 1121075518299410, + 2071745529082111, + 1265567917414828, + 1648196578317805, + 496232102750820, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2374121042985030, + 3274721891178932, + 2001275453369483, + 2017441881607947, + 3245005694463250, + ]), + y_minus_x: FieldElement51([ + 654925550560074, + 1168810995576858, + 575655959430926, + 905758704861388, + 496774564663534, + ]), + xy2d: FieldElement51([ + 1954109525779738, + 2117022646152485, + 338102630417180, + 1194140505732026, + 107881734943492, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1714785840001267, + 4288299832366837, + 1876380234251965, + 2056717182974196, + 1645855254384642, + ]), + y_minus_x: FieldElement51([ + 106431476499341, + 62482972120563, + 1513446655109411, + 807258751769522, + 538491469114, + ]), + xy2d: FieldElement51([ + 2002850762893643, + 1243624520538135, + 1486040410574605, + 2184752338181213, + 378495998083531, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 922510868424903, + 1089502620807680, + 402544072617374, + 1131446598479839, + 1290278588136533, + ]), + y_minus_x: FieldElement51([ + 1867998812076769, + 715425053580701, + 39968586461416, + 2173068014586163, + 653822651801304, + ]), + xy2d: FieldElement51([ + 162892278589453, + 182585796682149, + 75093073137630, + 497037941226502, + 133871727117371, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4166396390264918, + 1608999621851577, + 1987629837704609, + 1519655314857977, + 1819193753409464, + ]), + y_minus_x: FieldElement51([ + 1949315551096831, + 1069003344994464, + 1939165033499916, + 1548227205730856, + 1933767655861407, + ]), + xy2d: FieldElement51([ + 1730519386931635, + 1393284965610134, + 1597143735726030, + 416032382447158, + 1429665248828629, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 360275475604546, + 2799635544748326, + 2467160717872776, + 2848446553564254, + 2584509464110332, + ]), + y_minus_x: FieldElement51([ + 47602113726801, + 1522314509708010, + 437706261372925, + 814035330438027, + 335930650933545, + ]), + xy2d: FieldElement51([ + 1291597595523886, + 1058020588994081, + 402837842324045, + 1363323695882781, + 2105763393033193, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2361321796251793, + 3967057562270386, + 1112231216891515, + 2046641005101484, + 2386048970842261, + ]), + y_minus_x: FieldElement51([ + 2156991030936798, + 2227544497153325, + 1869050094431622, + 754875860479115, + 1754242344267058, + ]), + xy2d: FieldElement51([ + 1846089562873800, + 98894784984326, + 1412430299204844, + 171351226625762, + 1100604760929008, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2335972195815721, + 2751510784385293, + 425749630620777, + 1762872794206857, + 2864642415813208, + ]), + y_minus_x: FieldElement51([ + 868309334532756, + 1703010512741873, + 1952690008738057, + 4325269926064, + 2071083554962116, + ]), + xy2d: FieldElement51([ + 523094549451158, + 401938899487815, + 1407690589076010, + 2022387426254453, + 158660516411257, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 612867287630009, + 2700012425789062, + 2823428891104443, + 1466796750919375, + 1728478129663858, + ]), + y_minus_x: FieldElement51([ + 1723848973783452, + 2208822520534681, + 1718748322776940, + 1974268454121942, + 1194212502258141, + ]), + xy2d: FieldElement51([ + 1254114807944608, + 977770684047110, + 2010756238954993, + 1783628927194099, + 1525962994408256, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2484263871921055, + 1948628555342433, + 1835348780427694, + 1031609499437291, + 2316271920603621, + ]), + y_minus_x: FieldElement51([ + 767338676040683, + 754089548318405, + 1523192045639075, + 435746025122062, + 512692508440385, + ]), + xy2d: FieldElement51([ + 1255955808701983, + 1700487367990941, + 1166401238800299, + 1175121994891534, + 1190934801395380, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2600943821853521, + 1337012557669161, + 1475912332999108, + 3573418268585706, + 2299411105589567, + ]), + y_minus_x: FieldElement51([ + 877519947135419, + 2172838026132651, + 272304391224129, + 1655143327559984, + 886229406429814, + ]), + xy2d: FieldElement51([ + 375806028254706, + 214463229793940, + 572906353144089, + 572168269875638, + 697556386112979, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1168827102357825, + 823864273033637, + 4323338565789945, + 788062026895923, + 2851378154428610, + ]), + y_minus_x: FieldElement51([ + 1948116082078088, + 2054898304487796, + 2204939184983900, + 210526805152138, + 786593586607626, + ]), + xy2d: FieldElement51([ + 1915320147894736, + 156481169009469, + 655050471180417, + 592917090415421, + 2165897438660879, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1726336468579724, + 1119932070398949, + 1929199510967666, + 2285718602008207, + 1836837863503149, + ]), + y_minus_x: FieldElement51([ + 829996854845988, + 217061778005138, + 1686565909803640, + 1346948817219846, + 1723823550730181, + ]), + xy2d: FieldElement51([ + 384301494966394, + 687038900403062, + 2211195391021739, + 254684538421383, + 1245698430589680, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1247567493562669, + 4229981908141095, + 2435671288478202, + 806570235643434, + 2540261331753164, + ]), + y_minus_x: FieldElement51([ + 1449077384734201, + 38285445457996, + 2136537659177832, + 2146493000841573, + 725161151123125, + ]), + xy2d: FieldElement51([ + 1201928866368855, + 800415690605445, + 1703146756828343, + 997278587541744, + 1858284414104014, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2608268623334125, + 3034173730618399, + 1718002439402869, + 3644022065904502, + 663171266061950, + ]), + y_minus_x: FieldElement51([ + 759628738230460, + 1012693474275852, + 353780233086498, + 246080061387552, + 2030378857679162, + ]), + xy2d: FieldElement51([ + 2040672435071076, + 888593182036908, + 1298443657189359, + 1804780278521327, + 354070726137060, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1894938527423184, + 3715012855162525, + 2726210319182898, + 2499094776718546, + 877975941029127, + ]), + y_minus_x: FieldElement51([ + 207937160991127, + 12966911039119, + 820997788283092, + 1010440472205286, + 1701372890140810, + ]), + xy2d: FieldElement51([ + 218882774543183, + 533427444716285, + 1233243976733245, + 435054256891319, + 1509568989549904, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4140638349397055, + 3303977572025869, + 3465353617009382, + 2420981822812579, + 2715174081801119, + ]), + y_minus_x: FieldElement51([ + 299137589460312, + 1594371588983567, + 868058494039073, + 257771590636681, + 1805012993142921, + ]), + xy2d: FieldElement51([ + 1806842755664364, + 2098896946025095, + 1356630998422878, + 1458279806348064, + 347755825962072, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1402334161391744, + 3811883484731547, + 1008585416617746, + 1147797150908892, + 1420416683642459, + ]), + y_minus_x: FieldElement51([ + 665506704253369, + 273770475169863, + 799236974202630, + 848328990077558, + 1811448782807931, + ]), + xy2d: FieldElement51([ + 1468412523962641, + 771866649897997, + 1931766110147832, + 799561180078482, + 524837559150077, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2223212657821831, + 2882216061048914, + 2144451165500327, + 3068710944633039, + 3276150872095279, + ]), + y_minus_x: FieldElement51([ + 1266603897524861, + 156378408858100, + 1275649024228779, + 447738405888420, + 253186462063095, + ]), + xy2d: FieldElement51([ + 2022215964509735, + 136144366993649, + 1800716593296582, + 1193970603800203, + 871675847064218, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1862751661970309, + 851596246739884, + 1519315554814041, + 3794598280232697, + 3669775149586767, + ]), + y_minus_x: FieldElement51([ + 1228168094547481, + 334133883362894, + 587567568420081, + 433612590281181, + 603390400373205, + ]), + xy2d: FieldElement51([ + 121893973206505, + 1843345804916664, + 1703118377384911, + 497810164760654, + 101150811654673, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2710146069631716, + 2542709749304591, + 1452768413850678, + 2802722688939463, + 1537286854336537, + ]), + y_minus_x: FieldElement51([ + 584322311184395, + 380661238802118, + 114839394528060, + 655082270500073, + 2111856026034852, + ]), + xy2d: FieldElement51([ + 996965581008991, + 2148998626477022, + 1012273164934654, + 1073876063914522, + 1688031788934939, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3175286832534829, + 2085106799623354, + 2779882615305384, + 1606206360876187, + 2987706905397772, + ]), + y_minus_x: FieldElement51([ + 1697697887804317, + 1335343703828273, + 831288615207040, + 949416685250051, + 288760277392022, + ]), + xy2d: FieldElement51([ + 1419122478109648, + 1325574567803701, + 602393874111094, + 2107893372601700, + 1314159682671307, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2201150872731785, + 2180241023425241, + 2349463270108411, + 1633405770247823, + 3100744856129234, + ]), + y_minus_x: FieldElement51([ + 1173339555550611, + 818605084277583, + 47521504364289, + 924108720564965, + 735423405754506, + ]), + xy2d: FieldElement51([ + 830104860549448, + 1886653193241086, + 1600929509383773, + 1475051275443631, + 286679780900937, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3828911108518224, + 3282698983453994, + 2396700729978777, + 4216472406664814, + 2820189914640497, + ]), + y_minus_x: FieldElement51([ + 278388655910247, + 487143369099838, + 927762205508727, + 181017540174210, + 1616886700741287, + ]), + xy2d: FieldElement51([ + 1191033906638969, + 940823957346562, + 1606870843663445, + 861684761499847, + 658674867251089, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1875032594195527, + 1427106132796197, + 2976536204647406, + 3153660325729987, + 2887068310954007, + ]), + y_minus_x: FieldElement51([ + 622869792298357, + 1903919278950367, + 1922588621661629, + 1520574711600434, + 1087100760174640, + ]), + xy2d: FieldElement51([ + 25465949416618, + 1693639527318811, + 1526153382657203, + 125943137857169, + 145276964043999, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2466539671654587, + 920212862967914, + 4191701364657517, + 3463662605460468, + 2336897329405367, + ]), + y_minus_x: FieldElement51([ + 2006245852772938, + 734762734836159, + 254642929763427, + 1406213292755966, + 239303749517686, + ]), + xy2d: FieldElement51([ + 1619678837192149, + 1919424032779215, + 1357391272956794, + 1525634040073113, + 1310226789796241, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3292563523447371, + 1704449869235351, + 2857062884141577, + 1998838089036354, + 1312142911487502, + ]), + y_minus_x: FieldElement51([ + 1996723311435669, + 1844342766567060, + 985455700466044, + 1165924681400960, + 311508689870129, + ]), + xy2d: FieldElement51([ + 43173156290518, + 2202883069785309, + 1137787467085917, + 1733636061944606, + 1394992037553852, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 670078326344559, + 2807454838744604, + 2723759199967685, + 2141455487356408, + 849015953823125, + ]), + y_minus_x: FieldElement51([ + 2197214573372804, + 794254097241315, + 1030190060513737, + 267632515541902, + 2040478049202624, + ]), + xy2d: FieldElement51([ + 1812516004670529, + 1609256702920783, + 1706897079364493, + 258549904773295, + 996051247540686, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1540374301420565, + 1764656898914615, + 1810104162020396, + 3175608592848336, + 2916189887881826, + ]), + y_minus_x: FieldElement51([ + 1323460699404750, + 1262690757880991, + 871777133477900, + 1060078894988977, + 1712236889662886, + ]), + xy2d: FieldElement51([ + 1696163952057966, + 1391710137550823, + 608793846867416, + 1034391509472039, + 1780770894075012, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1367603834210822, + 4383788460268472, + 890353773628143, + 1908908219165595, + 2522636708938139, + ]), + y_minus_x: FieldElement51([ + 597536315471731, + 40375058742586, + 1942256403956049, + 1185484645495932, + 312666282024145, + ]), + xy2d: FieldElement51([ + 1919411405316294, + 1234508526402192, + 1066863051997083, + 1008444703737597, + 1348810787701552, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2102881477513865, + 3822074379630609, + 1573617900503707, + 2270462449417831, + 2232324307922097, + ]), + y_minus_x: FieldElement51([ + 1853931367696942, + 8107973870707, + 350214504129299, + 775206934582587, + 1752317649166792, + ]), + xy2d: FieldElement51([ + 1417148368003523, + 721357181628282, + 505725498207811, + 373232277872983, + 261634707184480, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2186733281493248, + 2250694917008620, + 1014829812957440, + 2731797975137637, + 2335366007561721, + ]), + y_minus_x: FieldElement51([ + 1268116367301224, + 560157088142809, + 802626839600444, + 2210189936605713, + 1129993785579988, + ]), + xy2d: FieldElement51([ + 615183387352312, + 917611676109240, + 878893615973325, + 978940963313282, + 938686890583575, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 522024729211672, + 3296859129001056, + 1892245413707789, + 1907891107684253, + 2059998109500714, + ]), + y_minus_x: FieldElement51([ + 1799679152208884, + 912132775900387, + 25967768040979, + 432130448590461, + 274568990261996, + ]), + xy2d: FieldElement51([ + 98698809797682, + 2144627600856209, + 1907959298569602, + 811491302610148, + 1262481774981493, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1791451399743152, + 1713538728337276, + 2370149810942738, + 1882306388849953, + 158235232210248, + ]), + y_minus_x: FieldElement51([ + 1217809823321928, + 2173947284933160, + 1986927836272325, + 1388114931125539, + 12686131160169, + ]), + xy2d: FieldElement51([ + 1650875518872272, + 1136263858253897, + 1732115601395988, + 734312880662190, + 1252904681142109, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2624786269799113, + 2777230729143418, + 2116279931702134, + 2753222527273063, + 1907002872974924, + ]), + y_minus_x: FieldElement51([ + 803147181835288, + 868941437997146, + 316299302989663, + 943495589630550, + 571224287904572, + ]), + xy2d: FieldElement51([ + 227742695588364, + 1776969298667369, + 628602552821802, + 457210915378118, + 2041906378111140, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 815000523470260, + 3164885502413555, + 3303859931956420, + 1345536665214222, + 541623413135555, + ]), + y_minus_x: FieldElement51([ + 1580216071604333, + 1877997504342444, + 857147161260913, + 703522726778478, + 2182763974211603, + ]), + xy2d: FieldElement51([ + 1870080310923419, + 71988220958492, + 1783225432016732, + 615915287105016, + 1035570475990230, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2982787564515398, + 857613889540279, + 1083813157271766, + 1002817255970169, + 1719228484436074, + ]), + y_minus_x: FieldElement51([ + 377616581647602, + 1581980403078513, + 804044118130621, + 2034382823044191, + 643844048472185, + ]), + xy2d: FieldElement51([ + 176957326463017, + 1573744060478586, + 528642225008045, + 1816109618372371, + 1515140189765006, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1888911448245718, + 3638910709296328, + 4176303607751676, + 1731539523700948, + 2230378382645454, + ]), + y_minus_x: FieldElement51([ + 443392177002051, + 233793396845137, + 2199506622312416, + 1011858706515937, + 974676837063129, + ]), + xy2d: FieldElement51([ + 1846351103143623, + 1949984838808427, + 671247021915253, + 1946756846184401, + 1929296930380217, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 849646212451983, + 1410198775302919, + 2325567699868943, + 1641663456615811, + 3014056086137659, + ]), + y_minus_x: FieldElement51([ + 692017667358279, + 723305578826727, + 1638042139863265, + 748219305990306, + 334589200523901, + ]), + xy2d: FieldElement51([ + 22893968530686, + 2235758574399251, + 1661465835630252, + 925707319443452, + 1203475116966621, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3053098849470395, + 3985092410411378, + 1664508947088595, + 2719548934677170, + 3899298398220870, + ]), + y_minus_x: FieldElement51([ + 903105258014366, + 427141894933047, + 561187017169777, + 1884330244401954, + 1914145708422219, + ]), + xy2d: FieldElement51([ + 1344191060517578, + 1960935031767890, + 1518838929955259, + 1781502350597190, + 1564784025565682, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2925523165433334, + 1979969272514922, + 3427087126180756, + 1187589090978665, + 1881897672213940, + ]), + y_minus_x: FieldElement51([ + 1917185587363432, + 1098342571752737, + 5935801044414, + 2000527662351839, + 1538640296181569, + ]), + xy2d: FieldElement51([ + 2495540013192, + 678856913479236, + 224998292422872, + 219635787698590, + 1972465269000940, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 271413961212179, + 3604851875156899, + 2596511104968730, + 2014925838520661, + 2006221033113941, + ]), + y_minus_x: FieldElement51([ + 194583029968109, + 514316781467765, + 829677956235672, + 1676415686873082, + 810104584395840, + ]), + xy2d: FieldElement51([ + 1980510813313589, + 1948645276483975, + 152063780665900, + 129968026417582, + 256984195613935, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1860190562533083, + 1936576191345085, + 2712900106391212, + 1811043097042829, + 3209286562992083, + ]), + y_minus_x: FieldElement51([ + 796664815624365, + 1543160838872951, + 1500897791837765, + 1667315977988401, + 599303877030711, + ]), + xy2d: FieldElement51([ + 1151480509533204, + 2136010406720455, + 738796060240027, + 319298003765044, + 1150614464349587, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1731069268103131, + 2987442261301335, + 1364750481334267, + 2669032653668119, + 3178908082812908, + ]), + y_minus_x: FieldElement51([ + 1017222050227968, + 1987716148359, + 2234319589635701, + 621282683093392, + 2132553131763026, + ]), + xy2d: FieldElement51([ + 1567828528453324, + 1017807205202360, + 565295260895298, + 829541698429100, + 307243822276582, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 249079270936229, + 1501514259790706, + 3199709537890096, + 944551802437486, + 2804458577667728, + ]), + y_minus_x: FieldElement51([ + 2089966982947227, + 1854140343916181, + 2151980759220007, + 2139781292261749, + 158070445864917, + ]), + xy2d: FieldElement51([ + 1338766321464554, + 1906702607371284, + 1519569445519894, + 115384726262267, + 1393058953390992, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3616421371950629, + 3764188048593604, + 1926731583198685, + 2041482526432505, + 3172200936019022, + ]), + y_minus_x: FieldElement51([ + 1884844597333588, + 601480070269079, + 620203503079537, + 1079527400117915, + 1202076693132015, + ]), + xy2d: FieldElement51([ + 840922919763324, + 727955812569642, + 1303406629750194, + 522898432152867, + 294161410441865, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2605560604520539, + 1598361541848742, + 3374705511887547, + 4174333403844152, + 2670907514351827, + ]), + y_minus_x: FieldElement51([ + 359856369838236, + 180914355488683, + 861726472646627, + 218807937262986, + 575626773232501, + ]), + xy2d: FieldElement51([ + 755467689082474, + 909202735047934, + 730078068932500, + 936309075711518, + 2007798262842972, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1609384177904054, + 2614544999293875, + 1335318541768200, + 3052765584121496, + 2799677792952659, + ]), + y_minus_x: FieldElement51([ + 984339177776787, + 815727786505884, + 1645154585713747, + 1659074964378553, + 1686601651984156, + ]), + xy2d: FieldElement51([ + 1697863093781930, + 599794399429786, + 1104556219769607, + 830560774794755, + 12812858601017, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1168737550514982, + 897832437380552, + 463140296333799, + 2554364413707795, + 2008360505135500, + ]), + y_minus_x: FieldElement51([ + 1856930662813910, + 678090852002597, + 1920179140755167, + 1259527833759868, + 55540971895511, + ]), + xy2d: FieldElement51([ + 1158643631044921, + 476554103621892, + 178447851439725, + 1305025542653569, + 103433927680625, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2176793111709008, + 3828525530035639, + 2009350167273522, + 2012390194631546, + 2125297410909580, + ]), + y_minus_x: FieldElement51([ + 825403285195098, + 2144208587560784, + 1925552004644643, + 1915177840006985, + 1015952128947864, + ]), + xy2d: FieldElement51([ + 1807108316634472, + 1534392066433717, + 347342975407218, + 1153820745616376, + 7375003497471, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3234860815484973, + 2683011703586488, + 2201903782961092, + 3069193724749589, + 2214616493042166, + ]), + y_minus_x: FieldElement51([ + 228567918409756, + 865093958780220, + 358083886450556, + 159617889659320, + 1360637926292598, + ]), + xy2d: FieldElement51([ + 234147501399755, + 2229469128637390, + 2175289352258889, + 1397401514549353, + 1885288963089922, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3363562226636810, + 2504649386192636, + 3300514047508588, + 2397910909286693, + 1237505378776769, + ]), + y_minus_x: FieldElement51([ + 1113790697840279, + 1051167139966244, + 1045930658550944, + 2011366241542643, + 1686166824620755, + ]), + xy2d: FieldElement51([ + 1054097349305049, + 1872495070333352, + 182121071220717, + 1064378906787311, + 100273572924182, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3558210666856834, + 1627717417672446, + 2302783034773665, + 1109249951172249, + 3122001602766640, + ]), + y_minus_x: FieldElement51([ + 104233794644221, + 1548919791188248, + 2224541913267306, + 2054909377116478, + 1043803389015153, + ]), + xy2d: FieldElement51([ + 216762189468802, + 707284285441622, + 190678557969733, + 973969342604308, + 1403009538434867, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3530824104723725, + 2596576648903557, + 2525521909702446, + 4086000250496689, + 634517197663803, + ]), + y_minus_x: FieldElement51([ + 343805853118335, + 1302216857414201, + 566872543223541, + 2051138939539004, + 321428858384280, + ]), + xy2d: FieldElement51([ + 470067171324852, + 1618629234173951, + 2000092177515639, + 7307679772789, + 1117521120249968, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2529951391976704, + 1810282338562946, + 1771599529530998, + 3635459223356879, + 2937173228157088, + ]), + y_minus_x: FieldElement51([ + 577009397403102, + 1791440261786291, + 2177643735971638, + 174546149911960, + 1412505077782326, + ]), + xy2d: FieldElement51([ + 893719721537457, + 1201282458018197, + 1522349501711173, + 58011597740583, + 1130406465887139, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 412607348255434, + 1280455764199780, + 2233277987330768, + 2265979894086913, + 2583384512102412, + ]), + y_minus_x: FieldElement51([ + 262483770854550, + 990511055108216, + 526885552771698, + 571664396646158, + 354086190278723, + ]), + xy2d: FieldElement51([ + 1820352417585487, + 24495617171480, + 1547899057533253, + 10041836186225, + 480457105094042, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2023310314989233, + 2889705151211129, + 2106474638900686, + 2809620524769320, + 1687858215057825, + ]), + y_minus_x: FieldElement51([ + 1144168702609745, + 604444390410187, + 1544541121756138, + 1925315550126027, + 626401428894002, + ]), + xy2d: FieldElement51([ + 1922168257351784, + 2018674099908659, + 1776454117494445, + 956539191509034, + 36031129147635, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2796444352433270, + 1039872944430373, + 3128550222815858, + 2962457525011798, + 3468752501170219, + ]), + y_minus_x: FieldElement51([ + 58242421545916, + 2035812695641843, + 2118491866122923, + 1191684463816273, + 46921517454099, + ]), + xy2d: FieldElement51([ + 272268252444639, + 1374166457774292, + 2230115177009552, + 1053149803909880, + 1354288411641016, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1857910905368338, + 1754729879288912, + 3137745277795125, + 1516096106802165, + 1602902393369811, + ]), + y_minus_x: FieldElement51([ + 1193437069800958, + 901107149704790, + 999672920611411, + 477584824802207, + 364239578697845, + ]), + xy2d: FieldElement51([ + 886299989548838, + 1538292895758047, + 1590564179491896, + 1944527126709657, + 837344427345298, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3006358179063534, + 1712186480903617, + 3955456640022779, + 3002110732175033, + 2770795853936147, + ]), + y_minus_x: FieldElement51([ + 1309847803895382, + 1462151862813074, + 211370866671570, + 1544595152703681, + 1027691798954090, + ]), + xy2d: FieldElement51([ + 803217563745370, + 1884799722343599, + 1357706345069218, + 2244955901722095, + 730869460037413, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2941099284981214, + 1831210565161070, + 3626987155270686, + 3358084791231418, + 1893781834054268, + ]), + y_minus_x: FieldElement51([ + 696351368613042, + 1494385251239250, + 738037133616932, + 636385507851544, + 927483222611406, + ]), + xy2d: FieldElement51([ + 1949114198209333, + 1104419699537997, + 783495707664463, + 1747473107602770, + 2002634765788641, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1607325776830197, + 2782683755100581, + 1451089452727894, + 3833490970768671, + 496100432831153, + ]), + y_minus_x: FieldElement51([ + 1068900648804224, + 2006891997072550, + 1134049269345549, + 1638760646180091, + 2055396084625778, + ]), + xy2d: FieldElement51([ + 2222475519314561, + 1870703901472013, + 1884051508440561, + 1344072275216753, + 1318025677799069, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 155711679280637, + 681100400509288, + 389811735211209, + 2135723811340709, + 2660533024889373, + ]), + y_minus_x: FieldElement51([ + 7813206966729, + 194444201427550, + 2071405409526507, + 1065605076176312, + 1645486789731291, + ]), + xy2d: FieldElement51([ + 16625790644959, + 1647648827778410, + 1579910185572704, + 436452271048548, + 121070048451050, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3289062842237779, + 2820185594063076, + 2549752917829677, + 3810384325616458, + 2238221839292470, + ]), + y_minus_x: FieldElement51([ + 190565267697443, + 672855706028058, + 338796554369226, + 337687268493904, + 853246848691734, + ]), + xy2d: FieldElement51([ + 1763863028400139, + 766498079432444, + 1321118624818005, + 69494294452268, + 858786744165651, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3543856582248253, + 1456632109855637, + 3352431060735432, + 1386133165675320, + 3484698163879000, + ]), + y_minus_x: FieldElement51([ + 366253102478259, + 525676242508811, + 1449610995265438, + 1183300845322183, + 185960306491545, + ]), + xy2d: FieldElement51([ + 28315355815982, + 460422265558930, + 1799675876678724, + 1969256312504498, + 1051823843138725, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2408714813047231, + 3857948219405196, + 1665208410108429, + 2569443092377519, + 1383783705665319, + ]), + y_minus_x: FieldElement51([ + 54684536365732, + 2210010038536222, + 1194984798155308, + 535239027773705, + 1516355079301361, + ]), + xy2d: FieldElement51([ + 1484387703771650, + 198537510937949, + 2186282186359116, + 617687444857508, + 647477376402122, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2147715541830533, + 2751832352131065, + 2898179830570073, + 2604027669016369, + 1488268620408051, + ]), + y_minus_x: FieldElement51([ + 159386186465542, + 1877626593362941, + 618737197060512, + 1026674284330807, + 1158121760792685, + ]), + xy2d: FieldElement51([ + 1744544377739822, + 1964054180355661, + 1685781755873170, + 2169740670377448, + 1286112621104591, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2333777063470241, + 3919742931398333, + 3920783633320113, + 1605016835177614, + 1353960708075544, + ]), + y_minus_x: FieldElement51([ + 1602253788689063, + 439542044889886, + 2220348297664483, + 657877410752869, + 157451572512238, + ]), + xy2d: FieldElement51([ + 1029287186166717, + 65860128430192, + 525298368814832, + 1491902500801986, + 1461064796385400, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2660016802414475, + 2121095722306988, + 913562102267595, + 1879708920318308, + 2492861262121979, + ]), + y_minus_x: FieldElement51([ + 1185483484383269, + 1356339572588553, + 584932367316448, + 102132779946470, + 1792922621116791, + ]), + xy2d: FieldElement51([ + 1966196870701923, + 2230044620318636, + 1425982460745905, + 261167817826569, + 46517743394330, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2358877405280588, + 3136759755857592, + 2279106683482647, + 2224911448949389, + 3216151871930471, + ]), + y_minus_x: FieldElement51([ + 1730194207717538, + 431790042319772, + 1831515233279467, + 1372080552768581, + 1074513929381760, + ]), + xy2d: FieldElement51([ + 1450880638731607, + 1019861580989005, + 1229729455116861, + 1174945729836143, + 826083146840706, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1899935429242705, + 1602068751520477, + 940583196550370, + 2334230882739107, + 1540863155745695, + ]), + y_minus_x: FieldElement51([ + 2136688454840028, + 2099509000964294, + 1690800495246475, + 1217643678575476, + 828720645084218, + ]), + xy2d: FieldElement51([ + 765548025667841, + 462473984016099, + 998061409979798, + 546353034089527, + 2212508972466858, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2298375097456408, + 3144370785258318, + 1281983193144089, + 1491520128287375, + 75847005908304, + ]), + y_minus_x: FieldElement51([ + 1801436127943107, + 1734436817907890, + 1268728090345068, + 167003097070711, + 2233597765834956, + ]), + xy2d: FieldElement51([ + 1997562060465113, + 1048700225534011, + 7615603985628, + 1855310849546841, + 2242557647635213, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1161017320376250, + 2744424393854291, + 2169815802355236, + 3228296595417790, + 1770879511019628, + ]), + y_minus_x: FieldElement51([ + 1357044908364776, + 729130645262438, + 1762469072918979, + 1365633616878458, + 181282906404941, + ]), + xy2d: FieldElement51([ + 1080413443139865, + 1155205815510486, + 1848782073549786, + 622566975152580, + 124965574467971, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1184526762066993, + 247622751762817, + 2943928830891604, + 3071818503097743, + 2188697339828084, + ]), + y_minus_x: FieldElement51([ + 2020536369003019, + 202261491735136, + 1053169669150884, + 2056531979272544, + 778165514694311, + ]), + xy2d: FieldElement51([ + 237404399610207, + 1308324858405118, + 1229680749538400, + 720131409105291, + 1958958863624906, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2767383321724075, + 2269456792542436, + 1717918437373988, + 1568052070792483, + 2298775616809171, + ]), + y_minus_x: FieldElement51([ + 281527309158085, + 36970532401524, + 866906920877543, + 2222282602952734, + 1289598729589882, + ]), + xy2d: FieldElement51([ + 1278207464902042, + 494742455008756, + 1262082121427081, + 1577236621659884, + 1888786707293291, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 353042527954210, + 1830056151907359, + 1111731275799225, + 2426760769524072, + 404312815582674, + ]), + y_minus_x: FieldElement51([ + 2064251142068628, + 1666421603389706, + 1419271365315441, + 468767774902855, + 191535130366583, + ]), + xy2d: FieldElement51([ + 1716987058588002, + 1859366439773457, + 1767194234188234, + 64476199777924, + 1117233614485261, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3236091949205521, + 2386938060636506, + 2220652137473166, + 1722843421165029, + 2442282371698157, + ]), + y_minus_x: FieldElement51([ + 298845952651262, + 1166086588952562, + 1179896526238434, + 1347812759398693, + 1412945390096208, + ]), + xy2d: FieldElement51([ + 1143239552672925, + 906436640714209, + 2177000572812152, + 2075299936108548, + 325186347798433, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2972824668060020, + 2936287674948563, + 3625238557779406, + 2193186935276994, + 1387043709851261, + ]), + y_minus_x: FieldElement51([ + 418098668140962, + 715065997721283, + 1471916138376055, + 2168570337288357, + 937812682637044, + ]), + xy2d: FieldElement51([ + 1043584187226485, + 2143395746619356, + 2209558562919611, + 482427979307092, + 847556718384018, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1248731221520740, + 1465200936117687, + 2792603306395388, + 2304778448366139, + 2513234303861356, + ]), + y_minus_x: FieldElement51([ + 1057329623869501, + 620334067429122, + 461700859268034, + 2012481616501857, + 297268569108938, + ]), + xy2d: FieldElement51([ + 1055352180870759, + 1553151421852298, + 1510903185371259, + 1470458349428097, + 1226259419062731, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3744788603986897, + 3042126439258578, + 3441906842094992, + 3641194565844440, + 3872208010289441, + ]), + y_minus_x: FieldElement51([ + 47000654413729, + 1004754424173864, + 1868044813557703, + 173236934059409, + 588771199737015, + ]), + xy2d: FieldElement51([ + 30498470091663, + 1082245510489825, + 576771653181956, + 806509986132686, + 1317634017056939, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2672107869436803, + 3745154677001249, + 2417006535213335, + 4136645508605033, + 2065456951573058, + ]), + y_minus_x: FieldElement51([ + 1115636332012334, + 1854340990964155, + 83792697369514, + 1972177451994021, + 457455116057587, + ]), + xy2d: FieldElement51([ + 1698968457310898, + 1435137169051090, + 1083661677032510, + 938363267483709, + 340103887207182, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1995325341336555, + 911500251774648, + 2415810569088940, + 855378419194761, + 3825401211214090, + ]), + y_minus_x: FieldElement51([ + 241719380661528, + 310028521317150, + 1215881323380194, + 1408214976493624, + 2141142156467363, + ]), + xy2d: FieldElement51([ + 1315157046163473, + 727368447885818, + 1363466668108618, + 1668921439990361, + 1398483384337907, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2326829491984875, + 3267188020145720, + 1849729037055211, + 4191614430138232, + 2696204044080201, + ]), + y_minus_x: FieldElement51([ + 2053597130993710, + 2024431685856332, + 2233550957004860, + 2012407275509545, + 872546993104440, + ]), + xy2d: FieldElement51([ + 1217269667678610, + 599909351968693, + 1390077048548598, + 1471879360694802, + 739586172317596, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3970118453066023, + 1560510726633957, + 3156262694845170, + 1418028351780051, + 2346204163137185, + ]), + y_minus_x: FieldElement51([ + 2132502667405250, + 214379346175414, + 1502748313768060, + 1960071701057800, + 1353971822643138, + ]), + xy2d: FieldElement51([ + 319394212043702, + 2127459436033571, + 717646691535162, + 663366796076914, + 318459064945314, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2657789238608841, + 1960452633787082, + 2919148848086913, + 3744474074452359, + 1451061489880786, + ]), + y_minus_x: FieldElement51([ + 947085906234007, + 323284730494107, + 1485778563977200, + 728576821512394, + 901584347702286, + ]), + xy2d: FieldElement51([ + 1575783124125742, + 2126210792434375, + 1569430791264065, + 1402582372904727, + 1891780248341114, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3090232019245924, + 4249503325136911, + 3270591693593114, + 1662001808174330, + 2330127946643001, + ]), + y_minus_x: FieldElement51([ + 739152638255629, + 2074935399403557, + 505483666745895, + 1611883356514088, + 628654635394878, + ]), + xy2d: FieldElement51([ + 1822054032121349, + 643057948186973, + 7306757352712, + 577249257962099, + 284735863382083, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3618358370049178, + 1448606567552085, + 3730680834630016, + 2417602993041145, + 1115718458123497, + ]), + y_minus_x: FieldElement51([ + 204146226972102, + 1630511199034723, + 2215235214174763, + 174665910283542, + 956127674017216, + ]), + xy2d: FieldElement51([ + 1562934578796716, + 1070893489712745, + 11324610642270, + 958989751581897, + 2172552325473805, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1770564423056008, + 2987323445349813, + 1326060113795288, + 1509650369341127, + 2317692235267932, + ]), + y_minus_x: FieldElement51([ + 623682558650637, + 1337866509471512, + 990313350206649, + 1314236615762469, + 1164772974270275, + ]), + xy2d: FieldElement51([ + 223256821462517, + 723690150104139, + 1000261663630601, + 933280913953265, + 254872671543046, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1969087237026022, + 2876595539132372, + 1335555107635968, + 2069986355593023, + 3963899963027150, + ]), + y_minus_x: FieldElement51([ + 1236103475266979, + 1837885883267218, + 1026072585230455, + 1025865513954973, + 1801964901432134, + ]), + xy2d: FieldElement51([ + 1115241013365517, + 1712251818829143, + 2148864332502771, + 2096001471438138, + 2235017246626125, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3551068012286861, + 2047148477845620, + 2165648650132450, + 1612539282026145, + 2765997725314138, + ]), + y_minus_x: FieldElement51([ + 118352772338543, + 1067608711804704, + 1434796676193498, + 1683240170548391, + 230866769907437, + ]), + xy2d: FieldElement51([ + 1850689576796636, + 1601590730430274, + 1139674615958142, + 1954384401440257, + 76039205311, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1723387471374172, + 3249101280723658, + 2785727448808904, + 2272728458379212, + 1756575222802512, + ]), + y_minus_x: FieldElement51([ + 2146711623855116, + 503278928021499, + 625853062251406, + 1109121378393107, + 1033853809911861, + ]), + xy2d: FieldElement51([ + 571005965509422, + 2005213373292546, + 1016697270349626, + 56607856974274, + 914438579435146, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1346698876211176, + 2076651707527589, + 3336561384795453, + 2517134292513653, + 1068954492309670, + ]), + y_minus_x: FieldElement51([ + 1769967932677654, + 1695893319756416, + 1151863389675920, + 1781042784397689, + 400287774418285, + ]), + xy2d: FieldElement51([ + 1851867764003121, + 403841933237558, + 820549523771987, + 761292590207581, + 1743735048551143, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 410915148140008, + 2107072311871739, + 3256167275561751, + 2351484709082008, + 1180818713503223, + ]), + y_minus_x: FieldElement51([ + 285945406881439, + 648174397347453, + 1098403762631981, + 1366547441102991, + 1505876883139217, + ]), + xy2d: FieldElement51([ + 672095903120153, + 1675918957959872, + 636236529315028, + 1569297300327696, + 2164144194785875, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1902708175321798, + 3287143344600686, + 1178560808893262, + 2552895497743394, + 1280977479761117, + ]), + y_minus_x: FieldElement51([ + 1615357281742403, + 404257611616381, + 2160201349780978, + 1160947379188955, + 1578038619549541, + ]), + xy2d: FieldElement51([ + 2013087639791217, + 822734930507457, + 1785668418619014, + 1668650702946164, + 389450875221715, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2705718263383616, + 2358206633614248, + 2072540975937134, + 308588860670238, + 1304394580755385, + ]), + y_minus_x: FieldElement51([ + 1295082798350326, + 2091844511495996, + 1851348972587817, + 3375039684596, + 789440738712837, + ]), + xy2d: FieldElement51([ + 2083069137186154, + 848523102004566, + 993982213589257, + 1405313299916317, + 1532824818698468, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3747761112537659, + 1397203457344778, + 4026750030752190, + 2391102557240943, + 2318403398028034, + ]), + y_minus_x: FieldElement51([ + 1782411379088302, + 1096724939964781, + 27593390721418, + 542241850291353, + 1540337798439873, + ]), + xy2d: FieldElement51([ + 693543956581437, + 171507720360750, + 1557908942697227, + 1074697073443438, + 1104093109037196, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 345288228393400, + 3351443383432420, + 2386681722088990, + 1740551994106739, + 2500011992985018, + ]), + y_minus_x: FieldElement51([ + 231429562203065, + 1526290236421172, + 2021375064026423, + 1520954495658041, + 806337791525116, + ]), + xy2d: FieldElement51([ + 1079623667189886, + 872403650198613, + 766894200588288, + 2163700860774109, + 2023464507911816, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 854645372543796, + 1936406001954827, + 2403260476226501, + 3077125552956802, + 1554306377287555, + ]), + y_minus_x: FieldElement51([ + 1497138821904622, + 1044820250515590, + 1742593886423484, + 1237204112746837, + 849047450816987, + ]), + xy2d: FieldElement51([ + 667962773375330, + 1897271816877105, + 1399712621683474, + 1143302161683099, + 2081798441209593, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2378947665252234, + 1936114012888109, + 1704424366552046, + 3108474694401560, + 2968403435020606, + ]), + y_minus_x: FieldElement51([ + 1072409664800960, + 2146937497077528, + 1508780108920651, + 935767602384853, + 1112800433544068, + ]), + xy2d: FieldElement51([ + 333549023751292, + 280219272863308, + 2104176666454852, + 1036466864875785, + 536135186520207, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2625466093568366, + 2398257055215356, + 2555916080813104, + 2667888562832962, + 3510376944868638, + ]), + y_minus_x: FieldElement51([ + 1186115062588401, + 2251609796968486, + 1098944457878953, + 1153112761201374, + 1791625503417267, + ]), + xy2d: FieldElement51([ + 1870078460219737, + 2129630962183380, + 852283639691142, + 292865602592851, + 401904317342226, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1361070124828016, + 815664541425524, + 3278598711049919, + 1951790935390646, + 2807674705520038, + ]), + y_minus_x: FieldElement51([ + 1546301003424277, + 459094500062839, + 1097668518375311, + 1780297770129643, + 720763293687608, + ]), + xy2d: FieldElement51([ + 1212405311403990, + 1536693382542438, + 61028431067459, + 1863929423417129, + 1223219538638038, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1294303766540260, + 3435357279640341, + 3134071170918340, + 2315654383110622, + 2213283684565086, + ]), + y_minus_x: FieldElement51([ + 339050984211414, + 601386726509773, + 413735232134068, + 966191255137228, + 1839475899458159, + ]), + xy2d: FieldElement51([ + 235605972169408, + 2174055643032978, + 1538335001838863, + 1281866796917192, + 1815940222628465, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1632352921721536, + 1833328609514701, + 2092779091951987, + 4175756015558474, + 2210068022482918, + ]), + y_minus_x: FieldElement51([ + 35271216625062, + 1712350667021807, + 983664255668860, + 98571260373038, + 1232645608559836, + ]), + xy2d: FieldElement51([ + 1998172393429622, + 1798947921427073, + 784387737563581, + 1589352214827263, + 1589861734168180, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1733739258725305, + 2283515530744786, + 2453769758904107, + 3243892858242237, + 1194308773174555, + ]), + y_minus_x: FieldElement51([ + 846415389605137, + 746163495539180, + 829658752826080, + 592067705956946, + 957242537821393, + ]), + xy2d: FieldElement51([ + 1758148849754419, + 619249044817679, + 168089007997045, + 1371497636330523, + 1867101418880350, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2578433797894864, + 2513559319756263, + 1700682323676192, + 1577907266349064, + 3469447477068264, + ]), + y_minus_x: FieldElement51([ + 1714182387328607, + 1477856482074168, + 574895689942184, + 2159118410227270, + 1555532449716575, + ]), + xy2d: FieldElement51([ + 853828206885131, + 998498946036955, + 1835887550391235, + 207627336608048, + 258363815956050, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2392941288336925, + 3488528558590503, + 2894901233585134, + 1646615130509172, + 1208239602291765, + ]), + y_minus_x: FieldElement51([ + 1501663228068911, + 1354879465566912, + 1444432675498247, + 897812463852601, + 855062598754348, + ]), + xy2d: FieldElement51([ + 714380763546606, + 1032824444965790, + 1774073483745338, + 1063840874947367, + 1738680636537158, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1640635546696233, + 2884968766877360, + 2212651044092395, + 2282390772269100, + 2620315074574625, + ]), + y_minus_x: FieldElement51([ + 1171650314802029, + 1567085444565577, + 1453660792008405, + 757914533009261, + 1619511342778196, + ]), + xy2d: FieldElement51([ + 420958967093237, + 971103481109486, + 2169549185607107, + 1301191633558497, + 1661514101014240, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3158923465503550, + 1332556122804145, + 4075855067109735, + 3619414031128206, + 1982558335973171, + ]), + y_minus_x: FieldElement51([ + 1121533090144639, + 1021251337022187, + 110469995947421, + 1511059774758394, + 2110035908131662, + ]), + xy2d: FieldElement51([ + 303213233384524, + 2061932261128138, + 352862124777736, + 40828818670255, + 249879468482660, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 856559257852200, + 2760317478634258, + 3629993581580163, + 3975258940632376, + 1962275756614520, + ]), + y_minus_x: FieldElement51([ + 1445691340537320, + 40614383122127, + 402104303144865, + 485134269878232, + 1659439323587426, + ]), + xy2d: FieldElement51([ + 20057458979482, + 1183363722525800, + 2140003847237215, + 2053873950687614, + 2112017736174909, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2228654250927986, + 3735391177100515, + 1368661293910955, + 3328311098862539, + 526650682059607, + ]), + y_minus_x: FieldElement51([ + 709481497028540, + 531682216165724, + 316963769431931, + 1814315888453765, + 258560242424104, + ]), + xy2d: FieldElement51([ + 1053447823660455, + 1955135194248683, + 1010900954918985, + 1182614026976701, + 1240051576966610, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1957943897155478, + 1788667368028035, + 2389492723714354, + 2252839333292309, + 3078204576998275, + ]), + y_minus_x: FieldElement51([ + 1848942433095597, + 1582009882530495, + 1849292741020143, + 1068498323302788, + 2001402229799484, + ]), + xy2d: FieldElement51([ + 1528282417624269, + 2142492439828191, + 2179662545816034, + 362568973150328, + 1591374675250271, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2411826493119617, + 2484141002903963, + 2149181472355544, + 598041771119831, + 2435658815595421, + ]), + y_minus_x: FieldElement51([ + 2013278155187349, + 662660471354454, + 793981225706267, + 411706605985744, + 804490933124791, + ]), + xy2d: FieldElement51([ + 2051892037280204, + 488391251096321, + 2230187337030708, + 930221970662692, + 679002758255210, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1530723630438670, + 875873929577927, + 2593359947955236, + 2701702933216000, + 1055551308214178, + ]), + y_minus_x: FieldElement51([ + 1461835919309432, + 1955256480136428, + 180866187813063, + 1551979252664528, + 557743861963950, + ]), + xy2d: FieldElement51([ + 359179641731115, + 1324915145732949, + 902828372691474, + 294254275669987, + 1887036027752957, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4295071423139571, + 2038225437857463, + 1317528426475850, + 1398989128982787, + 2027639881006861, + ]), + y_minus_x: FieldElement51([ + 2072902725256516, + 312132452743412, + 309930885642209, + 996244312618453, + 1590501300352303, + ]), + xy2d: FieldElement51([ + 1397254305160710, + 695734355138021, + 2233992044438756, + 1776180593969996, + 1085588199351115, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2692366865016258, + 2506694600041928, + 2745669038615469, + 1556322069683365, + 3819256354004466, + ]), + y_minus_x: FieldElement51([ + 1950722461391320, + 1907845598854797, + 1822757481635527, + 2121567704750244, + 73811931471221, + ]), + xy2d: FieldElement51([ + 387139307395758, + 2058036430315676, + 1220915649965325, + 1794832055328951, + 1230009312169328, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1765973779329498, + 2911143873132225, + 2271621715291913, + 3553728154996461, + 3368065817761132, + ]), + y_minus_x: FieldElement51([ + 1127572801181483, + 1224743760571696, + 1276219889847274, + 1529738721702581, + 1589819666871853, + ]), + xy2d: FieldElement51([ + 2181229378964934, + 2190885205260020, + 1511536077659137, + 1246504208580490, + 668883326494241, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2689666469258543, + 2920826224880015, + 2333696811665585, + 523874406393177, + 2496851874620484, + ]), + y_minus_x: FieldElement51([ + 1975438052228868, + 1071801519999806, + 594652299224319, + 1877697652668809, + 1489635366987285, + ]), + xy2d: FieldElement51([ + 958592545673770, + 233048016518599, + 851568750216589, + 567703851596087, + 1740300006094761, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2014540178270324, + 192672779514432, + 2465676996326778, + 2194819933853410, + 1716422829364835, + ]), + y_minus_x: FieldElement51([ + 1540769606609725, + 2148289943846077, + 1597804156127445, + 1230603716683868, + 815423458809453, + ]), + xy2d: FieldElement51([ + 1738560251245018, + 1779576754536888, + 1783765347671392, + 1880170990446751, + 1088225159617541, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2911103727614740, + 1956447718227572, + 1830568515922666, + 3092868863429656, + 1669607124206367, + ]), + y_minus_x: FieldElement51([ + 1143465490433355, + 1532194726196059, + 1093276745494697, + 481041706116088, + 2121405433561163, + ]), + xy2d: FieldElement51([ + 1686424298744462, + 1451806974487153, + 266296068846582, + 1834686947542675, + 1720762336132256, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3141016840074207, + 3295090436969907, + 3107924901237156, + 1669272323124635, + 1603340330827879, + ]), + y_minus_x: FieldElement51([ + 1206396181488998, + 333158148435054, + 1402633492821422, + 1120091191722026, + 1945474114550509, + ]), + xy2d: FieldElement51([ + 766720088232571, + 1512222781191002, + 1189719893490790, + 2091302129467914, + 2141418006894941, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2671463460991841, + 1998875112167986, + 3678399683938955, + 3406728169064757, + 2738338345823434, + ]), + y_minus_x: FieldElement51([ + 938160078005954, + 1421776319053174, + 1941643234741774, + 180002183320818, + 1414380336750546, + ]), + xy2d: FieldElement51([ + 398001940109652, + 1577721237663248, + 1012748649830402, + 1540516006905144, + 1011684812884559, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1653276489969611, + 2257881638852872, + 1921777941170835, + 1604139841794531, + 3113010867325889, + ]), + y_minus_x: FieldElement51([ + 996661541407379, + 1455877387952927, + 744312806857277, + 139213896196746, + 1000282908547789, + ]), + xy2d: FieldElement51([ + 1450817495603008, + 1476865707053229, + 1030490562252053, + 620966950353376, + 1744760161539058, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2811528223687828, + 2288856475326432, + 2038622963352005, + 1637244893271723, + 3278365165924196, + ]), + y_minus_x: FieldElement51([ + 962165956135846, + 1116599660248791, + 182090178006815, + 1455605467021751, + 196053588803284, + ]), + xy2d: FieldElement51([ + 796863823080135, + 1897365583584155, + 420466939481601, + 2165972651724672, + 932177357788289, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 877047233620613, + 1375632631944375, + 2895573425567369, + 2911822552533124, + 2271153746017078, + ]), + y_minus_x: FieldElement51([ + 2216943882299338, + 394841323190322, + 2222656898319671, + 558186553950529, + 1077236877025190, + ]), + xy2d: FieldElement51([ + 801118384953213, + 1914330175515892, + 574541023311511, + 1471123787903705, + 1526158900256288, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3201417702772463, + 2207116611267330, + 3164719852826535, + 2752958352884036, + 2314162374456719, + ]), + y_minus_x: FieldElement51([ + 1474518386765335, + 1760793622169197, + 1157399790472736, + 1622864308058898, + 165428294422792, + ]), + xy2d: FieldElement51([ + 1961673048027128, + 102619413083113, + 1051982726768458, + 1603657989805485, + 1941613251499678, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1401939116319247, + 2587106153588320, + 2323846009771033, + 862423201496005, + 3102318568216632, + ]), + y_minus_x: FieldElement51([ + 1234706593321979, + 1083343891215917, + 898273974314935, + 1640859118399498, + 157578398571149, + ]), + xy2d: FieldElement51([ + 1143483057726416, + 1992614991758919, + 674268662140796, + 1773370048077526, + 674318359920189, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1835401379538542, + 173900035308392, + 818247630716732, + 4013900225838034, + 1021506399448290, + ]), + y_minus_x: FieldElement51([ + 1506632088156630, + 2127481795522179, + 513812919490255, + 140643715928370, + 442476620300318, + ]), + xy2d: FieldElement51([ + 2056683376856736, + 219094741662735, + 2193541883188309, + 1841182310235800, + 556477468664293, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3566819241596075, + 1049075855992602, + 4318372866671791, + 2518704280870781, + 2040482348591519, + ]), + y_minus_x: FieldElement51([ + 94096246544434, + 922482381166992, + 24517828745563, + 2139430508542503, + 2097139044231004, + ]), + xy2d: FieldElement51([ + 537697207950515, + 1399352016347350, + 1563663552106345, + 2148749520888918, + 549922092988516, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1747985413252415, + 680511052635695, + 1809559829982725, + 2846074064615302, + 2453472984431229, + ]), + y_minus_x: FieldElement51([ + 323583936109569, + 1973572998577657, + 1192219029966558, + 79354804385273, + 1374043025560347, + ]), + xy2d: FieldElement51([ + 213277331329947, + 416202017849623, + 1950535221091783, + 1313441578103244, + 2171386783823658, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2440888617915079, + 993969372859109, + 3147669935222235, + 3799101348983503, + 1477373024911349, + ]), + y_minus_x: FieldElement51([ + 1620578418245010, + 541035331188469, + 2235785724453865, + 2154865809088198, + 1974627268751826, + ]), + xy2d: FieldElement51([ + 1346805451740245, + 1350981335690626, + 942744349501813, + 2155094562545502, + 1012483751693409, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2107080134091762, + 1132567062788208, + 1824935377687210, + 769194804343737, + 1857941799971888, + ]), + y_minus_x: FieldElement51([ + 1074666112436467, + 249279386739593, + 1174337926625354, + 1559013532006480, + 1472287775519121, + ]), + xy2d: FieldElement51([ + 1872620123779532, + 1892932666768992, + 1921559078394978, + 1270573311796160, + 1438913646755037, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3089190001333428, + 3264053113908846, + 989780015893986, + 1351393287739814, + 2580427560230798, + ]), + y_minus_x: FieldElement51([ + 1028328827183114, + 1711043289969857, + 1350832470374933, + 1923164689604327, + 1495656368846911, + ]), + xy2d: FieldElement51([ + 1900828492104143, + 430212361082163, + 687437570852799, + 832514536673512, + 1685641495940794, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3094432661621646, + 605670026766215, + 290836444839585, + 2415010588577604, + 2213815011799644, + ]), + y_minus_x: FieldElement51([ + 1176336383453996, + 1725477294339771, + 12700622672454, + 678015708818208, + 162724078519879, + ]), + xy2d: FieldElement51([ + 1448049969043497, + 1789411762943521, + 385587766217753, + 90201620913498, + 832999441066823, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2767886146978542, + 2240508292484615, + 3603469341851756, + 3475055379001735, + 3002035638112385, + ]), + y_minus_x: FieldElement51([ + 1263624896582495, + 1102602401673328, + 526302183714372, + 2152015839128799, + 1483839308490010, + ]), + xy2d: FieldElement51([ + 442991718646863, + 1599275157036458, + 1925389027579192, + 899514691371390, + 350263251085160, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1689713572022124, + 2845654372939621, + 3229894858477217, + 1985127338729498, + 3927868934032873, + ]), + y_minus_x: FieldElement51([ + 1557207018622683, + 340631692799603, + 1477725909476187, + 614735951619419, + 2033237123746766, + ]), + xy2d: FieldElement51([ + 968764929340557, + 1225534776710944, + 662967304013036, + 1155521416178595, + 791142883466590, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1487081286167458, + 3244839255500182, + 1792378982844639, + 2950452258685122, + 2153908693179753, + ]), + y_minus_x: FieldElement51([ + 1123181311102823, + 685575944875442, + 507605465509927, + 1412590462117473, + 568017325228626, + ]), + xy2d: FieldElement51([ + 560258797465417, + 2193971151466401, + 1824086900849026, + 579056363542056, + 1690063960036441, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1918407319222397, + 2605567366745211, + 1930426334528098, + 1564816146005724, + 4113142195393344, + ]), + y_minus_x: FieldElement51([ + 2131325168777276, + 1176636658428908, + 1756922641512981, + 1390243617176012, + 1966325177038383, + ]), + xy2d: FieldElement51([ + 2063958120364491, + 2140267332393533, + 699896251574968, + 273268351312140, + 375580724713232, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2024297515263178, + 2668759143407935, + 3330814048702549, + 2423412039258430, + 1031677520051052, + ]), + y_minus_x: FieldElement51([ + 2033900009388450, + 1744902869870788, + 2190580087917640, + 1949474984254121, + 231049754293748, + ]), + xy2d: FieldElement51([ + 343868674606581, + 550155864008088, + 1450580864229630, + 481603765195050, + 896972360018042, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2151139328380127, + 2566545695770176, + 2311556639460451, + 1676664391494650, + 2048348075599360, + ]), + y_minus_x: FieldElement51([ + 1528930066340597, + 1605003907059576, + 1055061081337675, + 1458319101947665, + 1234195845213142, + ]), + xy2d: FieldElement51([ + 830430507734812, + 1780282976102377, + 1425386760709037, + 362399353095425, + 2168861579799910, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3407562046415562, + 980662895504005, + 2053766700883521, + 2742766027762854, + 2762205690726604, + ]), + y_minus_x: FieldElement51([ + 1683750316716132, + 652278688286128, + 1221798761193539, + 1897360681476669, + 319658166027343, + ]), + xy2d: FieldElement51([ + 618808732869972, + 72755186759744, + 2060379135624181, + 1730731526741822, + 48862757828238, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3714971784278753, + 3394840525452699, + 614590986558882, + 1409210575145591, + 1882816996436803, + ]), + y_minus_x: FieldElement51([ + 2230133264691131, + 563950955091024, + 2042915975426398, + 827314356293472, + 672028980152815, + ]), + xy2d: FieldElement51([ + 264204366029760, + 1654686424479449, + 2185050199932931, + 2207056159091748, + 506015669043634, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1784446333136550, + 1973746527984364, + 334856327359575, + 3408569589569858, + 3275749938360725, + ]), + y_minus_x: FieldElement51([ + 2065270940578383, + 31477096270353, + 306421879113491, + 181958643936686, + 1907105536686083, + ]), + xy2d: FieldElement51([ + 1496516440779464, + 1748485652986458, + 872778352227340, + 818358834654919, + 97932669284220, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2723435829455580, + 2924255216478824, + 1804995246884102, + 1842309243470804, + 3753662318666930, + ]), + y_minus_x: FieldElement51([ + 1013216974933691, + 538921919682598, + 1915776722521558, + 1742822441583877, + 1886550687916656, + ]), + xy2d: FieldElement51([ + 2094270000643336, + 303971879192276, + 40801275554748, + 649448917027930, + 1818544418535447, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2241737709499146, + 549397817447461, + 838180519319392, + 1725686958520781, + 3957438894582995, + ]), + y_minus_x: FieldElement51([ + 1216074541925116, + 50120933933509, + 1565829004133810, + 721728156134580, + 349206064666188, + ]), + xy2d: FieldElement51([ + 948617110470858, + 346222547451945, + 1126511960599975, + 1759386906004538, + 493053284802266, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1454933046815146, + 3126495827951610, + 1467170975468587, + 1432316382418897, + 2111710746366763, + ]), + y_minus_x: FieldElement51([ + 2105387117364450, + 1996463405126433, + 1303008614294500, + 851908115948209, + 1353742049788635, + ]), + xy2d: FieldElement51([ + 750300956351719, + 1487736556065813, + 15158817002104, + 1511998221598392, + 971739901354129, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1874648163531674, + 2124487685930551, + 1810030029384882, + 918400043048335, + 2838148440985898, + ]), + y_minus_x: FieldElement51([ + 1235084464747900, + 1166111146432082, + 1745394857881591, + 1405516473883040, + 4463504151617, + ]), + xy2d: FieldElement51([ + 1663810156463827, + 327797390285791, + 1341846161759410, + 1964121122800605, + 1747470312055380, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 660005247548214, + 2071860029952887, + 3610548013635355, + 911703252219106, + 3266179736709079, + ]), + y_minus_x: FieldElement51([ + 2206641276178231, + 1690587809721504, + 1600173622825126, + 2156096097634421, + 1106822408548216, + ]), + xy2d: FieldElement51([ + 1344788193552206, + 1949552134239140, + 1735915881729557, + 675891104100469, + 1834220014427292, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1920949492387945, + 2410685102072778, + 2322108077349280, + 2877838278583064, + 3719881539786256, + ]), + y_minus_x: FieldElement51([ + 622221042073383, + 1210146474039168, + 1742246422343683, + 1403839361379025, + 417189490895736, + ]), + xy2d: FieldElement51([ + 22727256592983, + 168471543384997, + 1324340989803650, + 1839310709638189, + 504999476432775, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3565040332441556, + 1721896294296941, + 2304063388272514, + 2065069734239231, + 3056710287109878, + ]), + y_minus_x: FieldElement51([ + 1337466662091884, + 1287645354669772, + 2018019646776184, + 652181229374245, + 898011753211715, + ]), + xy2d: FieldElement51([ + 1969792547910734, + 779969968247557, + 2011350094423418, + 1823964252907487, + 1058949448296945, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2459143550747250, + 1118176942430252, + 3010694408233412, + 806764629546265, + 1157700123092949, + ]), + y_minus_x: FieldElement51([ + 1273565321399022, + 1638509681964574, + 759235866488935, + 666015124346707, + 897983460943405, + ]), + xy2d: FieldElement51([ + 1717263794012298, + 1059601762860786, + 1837819172257618, + 1054130665797229, + 680893204263559, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2237039662793603, + 2249022333361206, + 2058613546633703, + 2401253908530527, + 2215176649164581, + ]), + y_minus_x: FieldElement51([ + 79472182719605, + 1851130257050174, + 1825744808933107, + 821667333481068, + 781795293511946, + ]), + xy2d: FieldElement51([ + 755822026485370, + 152464789723500, + 1178207602290608, + 410307889503239, + 156581253571278, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3669985309815545, + 2736319981413860, + 3898537095128197, + 3653287498355512, + 1349185550126960, + ]), + y_minus_x: FieldElement51([ + 1495380034400429, + 325049476417173, + 46346894893933, + 1553408840354856, + 828980101835683, + ]), + xy2d: FieldElement51([ + 1280337889310282, + 2070832742866672, + 1640940617225222, + 2098284908289951, + 450929509534434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2659503167684029, + 2378371955168899, + 2537839641198868, + 1999255076709337, + 2030511179441770, + ]), + y_minus_x: FieldElement51([ + 1254958221100483, + 1153235960999843, + 942907704968834, + 637105404087392, + 1149293270147267, + ]), + xy2d: FieldElement51([ + 894249020470196, + 400291701616810, + 406878712230981, + 1599128793487393, + 1145868722604026, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3749755063888563, + 2361916158338507, + 1128535642171975, + 1900106496009660, + 2381592531146157, + ]), + y_minus_x: FieldElement51([ + 452487513298665, + 1352120549024569, + 1173495883910956, + 1999111705922009, + 367328130454226, + ]), + xy2d: FieldElement51([ + 1717539401269642, + 1475188995688487, + 891921989653942, + 836824441505699, + 1885988485608364, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3493583935107776, + 2439136865632830, + 3370281625921440, + 2680547565621609, + 2282158712612572, + ]), + y_minus_x: FieldElement51([ + 2022432361201842, + 1088816090685051, + 1977843398539868, + 1854834215890724, + 564238862029357, + ]), + xy2d: FieldElement51([ + 938868489100585, + 1100285072929025, + 1017806255688848, + 1957262154788833, + 152787950560442, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3119119231364171, + 2872271776627789, + 2477832016990963, + 2593801257642876, + 1761675818237335, + ]), + y_minus_x: FieldElement51([ + 1295072362439987, + 931227904689414, + 1355731432641687, + 922235735834035, + 892227229410209, + ]), + xy2d: FieldElement51([ + 1680989767906154, + 535362787031440, + 2136691276706570, + 1942228485381244, + 1267350086882274, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2617818047455756, + 2684460443440843, + 2378209521329782, + 1973842949591661, + 2897427157127624, + ]), + y_minus_x: FieldElement51([ + 535509430575217, + 546885533737322, + 1524675609547799, + 2138095752851703, + 1260738089896827, + ]), + xy2d: FieldElement51([ + 1159906385590467, + 2198530004321610, + 714559485023225, + 81880727882151, + 1484020820037082, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1377485731340769, + 2046328105512000, + 1802058637158797, + 2313945950453421, + 1356993908853900, + ]), + y_minus_x: FieldElement51([ + 2013612215646735, + 1830770575920375, + 536135310219832, + 609272325580394, + 270684344495013, + ]), + xy2d: FieldElement51([ + 1237542585982777, + 2228682050256790, + 1385281931622824, + 593183794882890, + 493654978552689, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2299141301692989, + 1891414891220256, + 983894663308928, + 2427961581972066, + 3378060928864955, + ]), + y_minus_x: FieldElement51([ + 1694030170963455, + 502038567066200, + 1691160065225467, + 949628319562187, + 275110186693066, + ]), + xy2d: FieldElement51([ + 1124515748676336, + 1661673816593408, + 1499640319059718, + 1584929449166988, + 558148594103306, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1784525599998356, + 1619698033617383, + 2097300287550715, + 2510065271789004, + 1905684794832757, + ]), + y_minus_x: FieldElement51([ + 1288941072872766, + 931787902039402, + 190731008859042, + 2006859954667190, + 1005931482221702, + ]), + xy2d: FieldElement51([ + 1465551264822703, + 152905080555927, + 680334307368453, + 173227184634745, + 666407097159852, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2111017076203943, + 3630560299479595, + 1248583954016455, + 3604089008549670, + 1895180776543895, + ]), + y_minus_x: FieldElement51([ + 171348223915638, + 662766099800389, + 462338943760497, + 466917763340314, + 656911292869115, + ]), + xy2d: FieldElement51([ + 488623681976577, + 866497561541722, + 1708105560937768, + 1673781214218839, + 1506146329818807, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2412225278142205, + 950394373239688, + 2682296937026182, + 711676555398831, + 320964687779005, + ]), + y_minus_x: FieldElement51([ + 988979367990485, + 1359729327576302, + 1301834257246029, + 294141160829308, + 29348272277475, + ]), + xy2d: FieldElement51([ + 1434382743317910, + 100082049942065, + 221102347892623, + 186982837860588, + 1305765053501834, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2205916462268190, + 2751663643476068, + 961960554686615, + 2409862576442233, + 1841471168298304, + ]), + y_minus_x: FieldElement51([ + 1191737341426592, + 1847042034978363, + 1382213545049056, + 1039952395710448, + 788812858896859, + ]), + xy2d: FieldElement51([ + 1346965964571152, + 1291881610839830, + 2142916164336056, + 786821641205979, + 1571709146321039, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 787164375951248, + 2454669019058437, + 3608390234717387, + 1431233331032509, + 786341368775957, + ]), + y_minus_x: FieldElement51([ + 492448143532951, + 304105152670757, + 1761767168301056, + 233782684697790, + 1981295323106089, + ]), + xy2d: FieldElement51([ + 665807507761866, + 1343384868355425, + 895831046139653, + 439338948736892, + 1986828765695105, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3007896024559801, + 1721699973539148, + 2510565115413133, + 1390588532210644, + 1212530909934781, + ]), + y_minus_x: FieldElement51([ + 852891097972275, + 1816988871354562, + 1543772755726524, + 1174710635522444, + 202129090724628, + ]), + xy2d: FieldElement51([ + 1205281565824323, + 22430498399418, + 992947814485516, + 1392458699738672, + 688441466734558, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3302427242100220, + 1955849529137134, + 2171162376368357, + 2343545681983462, + 447733118757825, + ]), + y_minus_x: FieldElement51([ + 1287181461435438, + 622722465530711, + 880952150571872, + 741035693459198, + 311565274989772, + ]), + xy2d: FieldElement51([ + 1003649078149734, + 545233927396469, + 1849786171789880, + 1318943684880434, + 280345687170552, + ]), + }, + ]), + ]); + +/// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = + NafLookupTable8([ + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3540182452943730, + 2497478415033846, + 2521227595762870, + 1462984067271729, + 2389212253076811, + ]), + y_minus_x: FieldElement51([ + 62697248952638, + 204681361388450, + 631292143396476, + 338455783676468, + 1213667448819585, + ]), + xy2d: FieldElement51([ + 301289933810280, + 1259582250014073, + 1422107436869536, + 796239922652654, + 1953934009299142, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1601611775252272, + 1720807796594148, + 1132070835939856, + 3512254832574799, + 2147779492816910, + ]), + y_minus_x: FieldElement51([ + 316559037616741, + 2177824224946892, + 1459442586438991, + 1461528397712656, + 751590696113597, + ]), + xy2d: FieldElement51([ + 1850748884277385, + 1200145853858453, + 1068094770532492, + 672251375690438, + 1586055907191707, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 769950342298400, + 2384754244604994, + 3095885746880802, + 3225892188161580, + 2977876099231263, + ]), + y_minus_x: FieldElement51([ + 425251763115706, + 608463272472562, + 442562545713235, + 837766094556764, + 374555092627893, + ]), + xy2d: FieldElement51([ + 1086255230780037, + 274979815921559, + 1960002765731872, + 929474102396301, + 1190409889297339, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2916800678241215, + 2065379846933858, + 2622030924071124, + 2602788184473875, + 1233371373142984, + ]), + y_minus_x: FieldElement51([ + 2019367628972465, + 676711900706637, + 110710997811333, + 1108646842542025, + 517791959672113, + ]), + xy2d: FieldElement51([ + 965130719900578, + 247011430587952, + 526356006571389, + 91986625355052, + 2157223321444601, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1802695059464988, + 1664899123557221, + 2845359304426105, + 2160434469266658, + 3179370264440279, + ]), + y_minus_x: FieldElement51([ + 1725674970513508, + 1933645953859181, + 1542344539275782, + 1767788773573747, + 1297447965928905, + ]), + xy2d: FieldElement51([ + 1381809363726107, + 1430341051343062, + 2061843536018959, + 1551778050872521, + 2036394857967624, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4222693909998302, + 2779866139518454, + 1619374932191226, + 2207306624415883, + 1169170329061080, + ]), + y_minus_x: FieldElement51([ + 2070390218572616, + 1458919061857835, + 624171843017421, + 1055332792707765, + 433987520732508, + ]), + xy2d: FieldElement51([ + 893653801273833, + 1168026499324677, + 1242553501121234, + 1306366254304474, + 1086752658510815, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2465253816303469, + 3191571337672685, + 1159882208056013, + 2569188183312765, + 621213314200686, + ]), + y_minus_x: FieldElement51([ + 1971678598905747, + 338026507889165, + 762398079972271, + 655096486107477, + 42299032696322, + ]), + xy2d: FieldElement51([ + 177130678690680, + 1754759263300204, + 1864311296286618, + 1180675631479880, + 1292726903152791, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1913163449625248, + 2712579013977241, + 2193883288642313, + 1008900146920800, + 1721983679009502, + ]), + y_minus_x: FieldElement51([ + 1070401523076875, + 1272492007800961, + 1910153608563310, + 2075579521696771, + 1191169788841221, + ]), + xy2d: FieldElement51([ + 692896803108118, + 500174642072499, + 2068223309439677, + 1162190621851337, + 1426986007309901, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1819621230288238, + 2735700366193240, + 1755134670739586, + 3080648199451191, + 4172807995775876, + ]), + y_minus_x: FieldElement51([ + 992069868904071, + 799011518185730, + 1777586403832768, + 1134820506145684, + 1999461475558530, + ]), + xy2d: FieldElement51([ + 425204543703124, + 2040469794090382, + 1651690622153809, + 1500530168597569, + 1253908377065966, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2105824306960939, + 1387520302709358, + 3633176580451016, + 2211816663841753, + 1629085891776489, + ]), + y_minus_x: FieldElement51([ + 1485201376284999, + 1022406647424656, + 504181009209019, + 962621520820995, + 590876713147230, + ]), + xy2d: FieldElement51([ + 265873406365287, + 1192742653492898, + 88553098803050, + 525037770869640, + 1266933811251234, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3552316659826612, + 1254279525791875, + 1609927932077699, + 3578654071679972, + 3750681296069893, + ]), + y_minus_x: FieldElement51([ + 37186803519861, + 1404297334376301, + 578519728836650, + 1740727951192592, + 2095534282477028, + ]), + xy2d: FieldElement51([ + 833234263154399, + 2023862470013762, + 1854137933982069, + 853924318090959, + 1589812702805850, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3679150557957763, + 1319179453661745, + 497496853611112, + 2665464286942351, + 1208137952365560, + ]), + y_minus_x: FieldElement51([ + 1654513078530905, + 907489875842908, + 126098711296368, + 1726320004173677, + 28269495058173, + ]), + xy2d: FieldElement51([ + 114436686957443, + 532739313025996, + 115428841215897, + 2191499400074366, + 370280402676434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1111146849833253, + 2016430049079759, + 1860522747477948, + 3537164738290194, + 4137142824844184, + ]), + y_minus_x: FieldElement51([ + 429069864577128, + 975327637149449, + 237881983565075, + 1654761232378630, + 2122527599091807, + ]), + xy2d: FieldElement51([ + 2093793463548278, + 754827233241879, + 1420389751719629, + 1829952782588138, + 2011865756773717, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 676293365438898, + 2850296017886344, + 1205350322490195, + 2763699392265669, + 2133931188538142, + ]), + y_minus_x: FieldElement51([ + 48340340349120, + 1299261101494832, + 1137329686775218, + 1534848106674340, + 1351662218216799, + ]), + xy2d: FieldElement51([ + 1904520614137939, + 1590301001714014, + 215781420985270, + 2043534301034629, + 1970888949300424, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2365217962409710, + 2061307169694064, + 1887478590157603, + 2169639621284316, + 2373810867477200, + ]), + y_minus_x: FieldElement51([ + 1020052624656948, + 1260412094216707, + 366721640607121, + 585331442306596, + 345876457758061, + ]), + xy2d: FieldElement51([ + 975390299880933, + 1066555195234642, + 12651997758352, + 1184252205433068, + 1058378155074223, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1431537716602643, + 2024827957433813, + 3746434518400495, + 1087794891033550, + 2156817571680455, + ]), + y_minus_x: FieldElement51([ + 929288033346881, + 255179964546973, + 711057989588035, + 208899572612840, + 185348357387383, + ]), + xy2d: FieldElement51([ + 823689746424808, + 47266130989546, + 209403309368097, + 1100966895202707, + 710792075292719, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2311213117823762, + 3296668540922318, + 2004276520649823, + 1861500579441125, + 3148029033359833, + ]), + y_minus_x: FieldElement51([ + 1563693677475261, + 1843782073741194, + 1950700654453170, + 911540858113949, + 2085151496302359, + ]), + xy2d: FieldElement51([ + 1427880892005482, + 106216431121745, + 42608394782284, + 1217295886989793, + 1514235272796882, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3544335535746750, + 2367994491347456, + 2567261456502612, + 1854058085060971, + 2263545563461076, + ]), + y_minus_x: FieldElement51([ + 787426011300053, + 2105981035769060, + 1130476291127206, + 1748659348100075, + 53470983013756, + ]), + xy2d: FieldElement51([ + 553548273865386, + 5927805718390, + 65184587381926, + 633576679686953, + 576048559439973, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 993787326657446, + 3868807161609258, + 1615796046728943, + 2514644292681953, + 2059021068660907, + ]), + y_minus_x: FieldElement51([ + 251010270518880, + 1681684095763484, + 1521949356387564, + 431593457045116, + 1855308922422910, + ]), + xy2d: FieldElement51([ + 618490909691959, + 1257497595618257, + 202952467594088, + 35577762721238, + 1494883566841973, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1673474571932262, + 2409784519770613, + 2636095316260487, + 2761112584601925, + 3333713288149876, + ]), + y_minus_x: FieldElement51([ + 1600640202645197, + 1019569075331823, + 1041916487915822, + 1680448171313267, + 2126903137527901, + ]), + xy2d: FieldElement51([ + 894964745143659, + 106116880092678, + 1009869382959477, + 317866368542032, + 1986983122763912, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1765281781276487, + 2863247187455184, + 2589075472439062, + 1386435905543054, + 2182338478845320, + ]), + y_minus_x: FieldElement51([ + 1144730936996693, + 2213315231278180, + 1489676672185125, + 665039429138074, + 1131283313040268, + ]), + xy2d: FieldElement51([ + 2004734176670602, + 1738311085075235, + 418866995976618, + 1050782508034394, + 577747313404652, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2185209688340293, + 1309276076461009, + 2514740038571278, + 3994889904012999, + 3018098826231021, + ]), + y_minus_x: FieldElement51([ + 1405936970888515, + 1754621155316654, + 1211862168554999, + 1813045702919083, + 997853418197172, + ]), + xy2d: FieldElement51([ + 82037622045021, + 1646398333621944, + 613095452763466, + 1312329542583705, + 81014679202721, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2389287991277873, + 403851022333257, + 1597473361477193, + 2953351602509212, + 2135174663049062, + ]), + y_minus_x: FieldElement51([ + 1826548187201150, + 302299893734126, + 1475477168615781, + 842617616347376, + 1438600873676130, + ]), + xy2d: FieldElement51([ + 663049852468609, + 1649295727846569, + 1048009692742781, + 628866177992421, + 1914360327429204, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1795645928096646, + 306878154408959, + 2924901319092394, + 2801261341654799, + 1653782432983523, + ]), + y_minus_x: FieldElement51([ + 2077597317438627, + 212642017882064, + 674844477518888, + 875487498687554, + 2060550250171182, + ]), + xy2d: FieldElement51([ + 1420448018683809, + 1032663994771382, + 1341927003385267, + 1340360916546159, + 1988547473895228, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1082660122598844, + 2545055705583789, + 3888919679589007, + 1670283344995811, + 3403239134794618, + ]), + y_minus_x: FieldElement51([ + 90430593339788, + 1838338032241275, + 571293238480915, + 1639938867416883, + 257378872001111, + ]), + xy2d: FieldElement51([ + 1528535658865034, + 1516636853043960, + 787000569996728, + 1464531394704506, + 1684822625133795, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 811329918113934, + 2783463529007378, + 1769095754634835, + 2970819621866866, + 881037178164325, + ]), + y_minus_x: FieldElement51([ + 1784566501964517, + 433890943689325, + 1186055625589419, + 1496077405487512, + 1731807117886548, + ]), + xy2d: FieldElement51([ + 424909811816304, + 1355993963741797, + 409606483251841, + 455665350637068, + 1617009023642808, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2478728492077816, + 2780289048655501, + 2328687177473769, + 4107341333582032, + 1316147724308250, + ]), + y_minus_x: FieldElement51([ + 1617420574301156, + 1741273341070467, + 667135503486508, + 2100436564640123, + 1032223920000865, + ]), + xy2d: FieldElement51([ + 1753947659404033, + 247279202390193, + 1819288880178945, + 737334285670249, + 1037873664856104, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1762568490530034, + 673742465299012, + 2054571050635888, + 2040165159255111, + 3040123733327257, + ]), + y_minus_x: FieldElement51([ + 1627187989987422, + 1686331580821752, + 1309895873498183, + 719718719104086, + 300063199808722, + ]), + xy2d: FieldElement51([ + 238176707016164, + 1440454788877048, + 203336037573144, + 1437789888677072, + 101522256664211, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1895216760098480, + 1934324337975022, + 3677350688973167, + 2536415965456176, + 714678003308640, + ]), + y_minus_x: FieldElement51([ + 508185358728815, + 1691320535341855, + 2168887448239256, + 1035124393070661, + 1936603999698584, + ]), + xy2d: FieldElement51([ + 390562831571647, + 1390223890708972, + 1383183990676371, + 435998174196410, + 1882086414390730, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3747620842612921, + 2081794785291195, + 3284594056262745, + 2090090346797895, + 2581692978935809, + ]), + y_minus_x: FieldElement51([ + 244144781251265, + 1290834426417077, + 1888701171101942, + 1233922456644870, + 241117402207491, + ]), + xy2d: FieldElement51([ + 1266169390045455, + 1148042013187970, + 878921907853942, + 1815738019658093, + 908920199341621, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2521768507305118, + 953557056811112, + 2015863732865770, + 1358382511861315, + 2835421647899992, + ]), + y_minus_x: FieldElement51([ + 2239837206240498, + 330928973149665, + 422268062913642, + 1481280019493032, + 619879520439841, + ]), + xy2d: FieldElement51([ + 1360166735366017, + 1770556573948510, + 1395061284191031, + 1814003148068126, + 522781147076884, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2611794802645686, + 707234844948070, + 1314059396506491, + 2919250341703934, + 2161831667832785, + ]), + y_minus_x: FieldElement51([ + 934831784182383, + 433734253968318, + 1660867106725771, + 1968393082772831, + 873946300968490, + ]), + xy2d: FieldElement51([ + 26306827827554, + 430884999378685, + 1504310424376419, + 1761358720837522, + 542195685418530, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1762131062631725, + 3123952634417535, + 3619918390837537, + 2909990877347294, + 1411594230004385, + ]), + y_minus_x: FieldElement51([ + 538272372224622, + 1425714779586199, + 588313661410172, + 1497062084392578, + 1602174047128512, + ]), + xy2d: FieldElement51([ + 907490361939255, + 1963620338391363, + 626927432296975, + 1250748516081414, + 959901171882527, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1335066153744413, + 2887804660779657, + 2653073855954038, + 2765226981667422, + 938831784476763, + ]), + y_minus_x: FieldElement51([ + 296699434737224, + 2047543711075683, + 2076451038937139, + 227783599906901, + 1602062110967627, + ]), + xy2d: FieldElement51([ + 1574834773194203, + 1384279952062839, + 393652417255803, + 2166968242848859, + 1552890441390820, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1619646774410947, + 1576090644023562, + 3035228391320965, + 1735328519940543, + 2355324535937066, + ]), + y_minus_x: FieldElement51([ + 1024074573633446, + 957088456885874, + 1690425531356997, + 2102187380180052, + 1082544623222033, + ]), + xy2d: FieldElement51([ + 1871906170635853, + 1719383891167200, + 1584032250247862, + 823764804192117, + 2244048510084261, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 642147846489775, + 3334304977145699, + 305205716788147, + 2589176626729533, + 2224680511484174, + ]), + y_minus_x: FieldElement51([ + 1734162377166545, + 260713621840346, + 157174591942595, + 952544272517991, + 222818702471733, + ]), + xy2d: FieldElement51([ + 1213115494182947, + 286778704335711, + 2130189536016490, + 308349182281342, + 1217623948685491, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3360052266973635, + 1843486583624091, + 1561693837124349, + 1084041964025479, + 1866270922024009, + ]), + y_minus_x: FieldElement51([ + 460705465481210, + 1968151453817859, + 497005926994844, + 625618055866751, + 2176893440866887, + ]), + xy2d: FieldElement51([ + 1655800250476757, + 2036588542300609, + 666447448675243, + 1615721995750683, + 1508669225186765, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2245948203759141, + 1058306669699396, + 1452898014240582, + 3961024141962768, + 1633235287338608, + ]), + y_minus_x: FieldElement51([ + 986647273684279, + 1507266907811370, + 1260572633649005, + 2071672342077446, + 695976026010857, + ]), + xy2d: FieldElement51([ + 1312356620823495, + 1635278548098567, + 901946076841033, + 585120475533168, + 1240667113237384, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2313723935779695, + 1506054666773895, + 996040223525031, + 636592914999692, + 1497801917020297, + ]), + y_minus_x: FieldElement51([ + 292042016419794, + 1158932298133044, + 2062611870323738, + 1946058478962569, + 1749165808126286, + ]), + xy2d: FieldElement51([ + 654683942212830, + 1526897351349087, + 2006818439922838, + 2194919327350361, + 1451960776874416, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3015041017808905, + 2951823141773809, + 2584865668253675, + 2508192032998563, + 2582137700042019, + ]), + y_minus_x: FieldElement51([ + 1628123495344283, + 2072923641214546, + 1647225812023982, + 855655925244679, + 1758126430071140, + ]), + xy2d: FieldElement51([ + 1615895096489599, + 275295258643784, + 937665541219916, + 1313496726746346, + 1186468946422626, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1603070202850694, + 2072127623773242, + 1692648737212158, + 2493373404187852, + 1248948672117105, + ]), + y_minus_x: FieldElement51([ + 11167836031898, + 596565174397990, + 2196351068723859, + 314744641791907, + 1102014997250781, + ]), + xy2d: FieldElement51([ + 1409047922401191, + 69960384467966, + 688103515547600, + 1309746102488044, + 150292892873778, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1986083055103168, + 691715819340300, + 1361811659746933, + 3459052030333434, + 1063594696046061, + ]), + y_minus_x: FieldElement51([ + 1201987338414749, + 2198784582460616, + 1203335513981498, + 489243077045066, + 2205278143582433, + ]), + xy2d: FieldElement51([ + 2034744376624534, + 2077387101466387, + 148448542974969, + 1502697574577258, + 473186584705655, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 472016956315960, + 720786972252993, + 2840633661190043, + 3150798753357827, + 2816563335499153, + ]), + y_minus_x: FieldElement51([ + 253464247569755, + 168314237403057, + 511780806170295, + 1058862316549135, + 1646858476817137, + ]), + xy2d: FieldElement51([ + 595092995922219, + 1491311840717691, + 291581784452778, + 1569186646367854, + 1031385061400544, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3483137021572755, + 1526955102024322, + 2778006642704458, + 457549634924205, + 1097420237736736, + ]), + y_minus_x: FieldElement51([ + 1246991699537710, + 81367319519439, + 530844036072196, + 163656863755855, + 1950742455979290, + ]), + xy2d: FieldElement51([ + 191532664076407, + 539378506082089, + 1021612562876554, + 1026603384732632, + 1773368780410653, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 4144620731387879, + 590179521333342, + 4034023318016108, + 2255745030335426, + 2699746851701250, + ]), + y_minus_x: FieldElement51([ + 2206599697359952, + 553895797384417, + 181689161933786, + 1153123447919104, + 778568064152659, + ]), + xy2d: FieldElement51([ + 1706307000059211, + 1885601289314487, + 889758608505788, + 550131729999853, + 1006862664714268, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3210197754285058, + 2048500453422630, + 3403309827888207, + 927154428508963, + 4199813798872019, + ]), + y_minus_x: FieldElement51([ + 992058915374933, + 476120535358775, + 1973648780784340, + 2025282643598818, + 2182318983793230, + ]), + xy2d: FieldElement51([ + 1343440812005821, + 1316045839091795, + 1884951299078063, + 1765919609219175, + 2197567554627988, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3129247779382818, + 4415026969054274, + 1900265885969643, + 1528796215447059, + 2172730393748688, + ]), + y_minus_x: FieldElement51([ + 1773355092297603, + 64654329538271, + 1332124041660957, + 748492100858001, + 895500006200535, + ]), + xy2d: FieldElement51([ + 2000840647851980, + 546565968824914, + 420633283457524, + 195470736374507, + 1958689297569520, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 743138980705446, + 3411117504637167, + 2591389959690621, + 2380042066577202, + 3022267940115114, + ]), + y_minus_x: FieldElement51([ + 165947002229363, + 115186103724967, + 1068573292121517, + 1842565776920938, + 1969395681111987, + ]), + xy2d: FieldElement51([ + 553322266190633, + 234265665613185, + 484544650202821, + 1238773526575826, + 2017991917953668, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2581954631514051, + 1245093644265357, + 3537016673825374, + 1834216551713857, + 923978372152807, + ]), + y_minus_x: FieldElement51([ + 1855378315339552, + 890045579230758, + 1764718173975590, + 197904186055854, + 1718129022310327, + ]), + xy2d: FieldElement51([ + 1278162928734862, + 1894118254109862, + 987503995465517, + 177406744098996, + 781538103127693, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1996603431230215, + 1191888797552937, + 1207440075928499, + 2765853449051137, + 2525314961343288, + ]), + y_minus_x: FieldElement51([ + 808903879370889, + 990820108751280, + 1084429472258867, + 1078562781312589, + 254514692695625, + ]), + xy2d: FieldElement51([ + 615855140068469, + 586046731175395, + 693470779212674, + 1964537100203868, + 1350330550265229, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3344544372023708, + 720386671449874, + 2480841360702110, + 2036034126860286, + 2015744690201389, + ]), + y_minus_x: FieldElement51([ + 1337446193390478, + 1984110761311871, + 746489405020285, + 407347127604128, + 1740475330360596, + ]), + xy2d: FieldElement51([ + 140840424783613, + 1063284623568331, + 1136446106453878, + 372042229029799, + 442607248430694, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2330781679120937, + 376801425148230, + 2032603686676107, + 1488926293635130, + 1317278311532959, + ]), + y_minus_x: FieldElement51([ + 1290116731380016, + 2166899563471713, + 831997001838078, + 870954980505220, + 2108537278055823, + ]), + xy2d: FieldElement51([ + 1912719171026343, + 846194720551034, + 2043988124740726, + 993234269653961, + 421229796383281, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2651184584992902, + 2775702557638963, + 2539786009779572, + 2575974880015305, + 2122619079836732, + ]), + y_minus_x: FieldElement51([ + 1154054290132562, + 931753998725577, + 1647742001778052, + 865765466488226, + 1083816107290025, + ]), + xy2d: FieldElement51([ + 986341121095108, + 1522330369638573, + 1990880546211047, + 501525962272123, + 198539304862139, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1496414019192687, + 3991034436173951, + 3380311659062196, + 2854747485359158, + 3346958036643152, + ]), + y_minus_x: FieldElement51([ + 805612068303425, + 1891790027761335, + 1587008567571549, + 722120737390201, + 378156757163816, + ]), + xy2d: FieldElement51([ + 1588994517921951, + 977362751042302, + 1329302387067714, + 2069348224564088, + 1586007159625211, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2490539421551682, + 1985699850375015, + 2331762317128172, + 4145097393776678, + 2521049460190674, + ]), + y_minus_x: FieldElement51([ + 615817553313996, + 2245962768078178, + 482564324326173, + 2101336843140780, + 1240914880829407, + ]), + xy2d: FieldElement51([ + 1438242482238189, + 874267817785463, + 1620810389770625, + 866155221338671, + 1040426546798301, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 2403083624110300, + 2548561409802975, + 2492699136535911, + 2358289519456539, + 3203964320363148, + ]), + y_minus_x: FieldElement51([ + 1913986535403097, + 1977163223054199, + 1972905914623196, + 1650122133472502, + 1905849310819035, + ]), + xy2d: FieldElement51([ + 858174816360838, + 614595356564037, + 1099584959044836, + 636998087084906, + 1070393269058348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3666695924830668, + 3585640662737501, + 2372994528684236, + 2628565977288995, + 3482812783469694, + ]), + y_minus_x: FieldElement51([ + 1994161359147952, + 2198039369802658, + 62790022842537, + 1522306785848169, + 951223194802833, + ]), + xy2d: FieldElement51([ + 852296621440717, + 431889737774209, + 370755457746189, + 437604073958073, + 627857326892757, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1794955764684156, + 2586904290013612, + 1322647643615887, + 856117964085888, + 2652432778663153, + ]), + y_minus_x: FieldElement51([ + 933592377399646, + 78031722952813, + 926049890685253, + 1471649501316246, + 33789909190376, + ]), + xy2d: FieldElement51([ + 1479319468832059, + 203906207621608, + 659828362330083, + 44358398435755, + 1273573524210803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1592342143350813, + 3227219208247713, + 2345240352078765, + 2577750109932929, + 2933512841197243, + ]), + y_minus_x: FieldElement51([ + 2184946892642995, + 1517382324576002, + 1557940277419806, + 2170635134813213, + 747314658627002, + ]), + xy2d: FieldElement51([ + 1823193620577742, + 1135817878516419, + 1731253819308581, + 1031652967267804, + 2123506616999453, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1346190246005805, + 2052692552023851, + 1718128041785940, + 2491557332978474, + 3474370880388305, + ]), + y_minus_x: FieldElement51([ + 424776012994573, + 281050757243423, + 626466040846420, + 990194703866532, + 38571969885982, + ]), + xy2d: FieldElement51([ + 192408346595466, + 1054889725292349, + 584097975693004, + 1447909807397749, + 2134645004369136, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3169895788615063, + 3503097743181446, + 601598510029975, + 1422812237223371, + 2121009661378329, + ]), + y_minus_x: FieldElement51([ + 1603348391996783, + 2066143816131699, + 1789627290363958, + 2145705961178118, + 1985578641438222, + ]), + xy2d: FieldElement51([ + 352633958653380, + 856927627345554, + 793925083122702, + 93551575767286, + 1222010153634215, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1756866499986349, + 911731956999969, + 2707505543214075, + 4006920335263786, + 822501008147910, + ]), + y_minus_x: FieldElement51([ + 1094036422864347, + 1897208881572508, + 1503607738246960, + 1901060196071406, + 294068411105729, + ]), + xy2d: FieldElement51([ + 587776484399576, + 1116861711228807, + 343398777436088, + 936544065763093, + 1643746750211060, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 3477749685790410, + 267997399528836, + 2953780922004404, + 3252368924080907, + 3787792887348381, + ]), + y_minus_x: FieldElement51([ + 2042368155872443, + 41662387210459, + 1676313264498480, + 1333968523426810, + 1765708383352310, + ]), + xy2d: FieldElement51([ + 1453394896690938, + 1585795827439909, + 1469309456804303, + 1294645324464404, + 2042954198665899, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51([ + 1810069207599881, + 1358344669503239, + 1989371257548167, + 2316270051121225, + 3019675451276507, + ]), + y_minus_x: FieldElement51([ + 1866114438287676, + 1663420339568364, + 1437691317033088, + 538298302628038, + 1212711449614363, + ]), + xy2d: FieldElement51([ + 1769235035677897, + 1562012115317882, + 31277513664750, + 536198657928416, + 1976134212537183, + ]), + }, + ]); diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/field.rs new file mode 100644 index 0000000..a73d4b5 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/field.rs @@ -0,0 +1,564 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\), using \\(64\\)-bit +//! limbs with \\(128\\)-bit products. + +use core::fmt::Debug; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Sub, SubAssign}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use zeroize::Zeroize; + +/// A `FieldElement51` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// In the 64-bit implementation, a `FieldElement` is represented in +/// radix \\(2\^{51}\\) as five `u64`s; the coefficients are allowed to +/// grow up to \\(2\^{54}\\) between reductions modulo \\(p\\). +/// +/// # Note +/// +/// The `curve25519_dalek::field` module provides a type alias +/// `curve25519_dalek::field::FieldElement` to either `FieldElement51` +/// or `FieldElement2625`. +/// +/// The backend-specific type `FieldElement51` should not be used +/// outside of the `curve25519_dalek::field` module. +#[derive(Copy, Clone)] +pub struct FieldElement51(pub (crate) [u64; 5]); + +impl Debug for FieldElement51 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "FieldElement51({:?})", &self.0[..]) + } +} + +impl Zeroize for FieldElement51 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl<'b> AddAssign<&'b FieldElement51> for FieldElement51 { + fn add_assign(&mut self, _rhs: &'b FieldElement51) { + for i in 0..5 { + self.0[i] += _rhs.0[i]; + } + } +} + +impl<'a, 'b> Add<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn add(self, _rhs: &'b FieldElement51) -> FieldElement51 { + let mut output = *self; + output += _rhs; + output + } +} + +impl<'b> SubAssign<&'b FieldElement51> for FieldElement51 { + fn sub_assign(&mut self, _rhs: &'b FieldElement51) { + let result = (self as &FieldElement51) - _rhs; + self.0 = result.0; + } +} + +impl<'a, 'b> Sub<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn sub(self, _rhs: &'b FieldElement51) -> FieldElement51 { + // To avoid underflow, first add a multiple of p. + // Choose 16*p = p << 4 to be larger than 54-bit _rhs. + // + // If we could statically track the bitlengths of the limbs + // of every FieldElement51, we could choose a multiple of p + // just bigger than _rhs and avoid having to do a reduction. + // + // Since we don't yet have type-level integers to do this, we + // have to add an explicit reduction call here. + FieldElement51::reduce([ + (self.0[0] + 36028797018963664u64) - _rhs.0[0], + (self.0[1] + 36028797018963952u64) - _rhs.0[1], + (self.0[2] + 36028797018963952u64) - _rhs.0[2], + (self.0[3] + 36028797018963952u64) - _rhs.0[3], + (self.0[4] + 36028797018963952u64) - _rhs.0[4], + ]) + } +} + +impl<'b> MulAssign<&'b FieldElement51> for FieldElement51 { + fn mul_assign(&mut self, _rhs: &'b FieldElement51) { + let result = (self as &FieldElement51) * _rhs; + self.0 = result.0; + } +} + +impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { + type Output = FieldElement51; + fn mul(self, _rhs: &'b FieldElement51) -> FieldElement51 { + /// Helper function to multiply two 64-bit integers with 128 + /// bits of output. + #[inline(always)] + fn m(x: u64, y: u64) -> u128 { (x as u128) * (y as u128) } + + // Alias self, _rhs for more readable formulas + let a: &[u64; 5] = &self.0; + let b: &[u64; 5] = &_rhs.0; + + // Precondition: assume input limbs a[i], b[i] are bounded as + // + // a[i], b[i] < 2^(51 + b) + // + // where b is a real parameter measuring the "bit excess" of the limbs. + + // 64-bit precomputations to avoid 128-bit multiplications. + // + // This fits into a u64 whenever 51 + b + lg(19) < 64. + // + // Since 51 + b + lg(19) < 51 + 4.25 + b + // = 55.25 + b, + // this fits if b < 8.75. + let b1_19 = b[1] * 19; + let b2_19 = b[2] * 19; + let b3_19 = b[3] * 19; + let b4_19 = b[4] * 19; + + // Multiply to get 128-bit coefficients of output + let c0: u128 = m(a[0],b[0]) + m(a[4],b1_19) + m(a[3],b2_19) + m(a[2],b3_19) + m(a[1],b4_19); + let mut c1: u128 = m(a[1],b[0]) + m(a[0],b[1]) + m(a[4],b2_19) + m(a[3],b3_19) + m(a[2],b4_19); + let mut c2: u128 = m(a[2],b[0]) + m(a[1],b[1]) + m(a[0],b[2]) + m(a[4],b3_19) + m(a[3],b4_19); + let mut c3: u128 = m(a[3],b[0]) + m(a[2],b[1]) + m(a[1],b[2]) + m(a[0],b[3]) + m(a[4],b4_19); + let mut c4: u128 = m(a[4],b[0]) + m(a[3],b[1]) + m(a[2],b[2]) + m(a[1],b[3]) + m(a[0],b[4]); + + // How big are the c[i]? We have + // + // c[i] < 2^(102 + 2*b) * (1+i + (4-i)*19) + // < 2^(102 + lg(1 + 4*19) + 2*b) + // < 2^(108.27 + 2*b) + // + // The carry (c[i] >> 51) fits into a u64 when + // 108.27 + 2*b - 51 < 64 + // 2*b < 6.73 + // b < 3.365. + // + // So we require b < 3 to ensure this fits. + debug_assert!(a[0] < (1 << 54)); debug_assert!(b[0] < (1 << 54)); + debug_assert!(a[1] < (1 << 54)); debug_assert!(b[1] < (1 << 54)); + debug_assert!(a[2] < (1 << 54)); debug_assert!(b[2] < (1 << 54)); + debug_assert!(a[3] < (1 << 54)); debug_assert!(b[3] < (1 << 54)); + debug_assert!(a[4] < (1 << 54)); debug_assert!(b[4] < (1 << 54)); + + // Casting to u64 and back tells the compiler that the carry is + // bounded by 2^64, so that the addition is a u128 + u64 rather + // than u128 + u128. + + const LOW_51_BIT_MASK: u64 = (1u64 << 51) - 1; + let mut out = [0u64; 5]; + + c1 += ((c0 >> 51) as u64) as u128; + out[0] = (c0 as u64) & LOW_51_BIT_MASK; + + c2 += ((c1 >> 51) as u64) as u128; + out[1] = (c1 as u64) & LOW_51_BIT_MASK; + + c3 += ((c2 >> 51) as u64) as u128; + out[2] = (c2 as u64) & LOW_51_BIT_MASK; + + c4 += ((c3 >> 51) as u64) as u128; + out[3] = (c3 as u64) & LOW_51_BIT_MASK; + + let carry: u64 = (c4 >> 51) as u64; + out[4] = (c4 as u64) & LOW_51_BIT_MASK; + + // To see that this does not overflow, we need out[0] + carry * 19 < 2^64. + // + // c4 < a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0 + (carry from c3) + // < 5*(2^(51 + b) * 2^(51 + b)) + (carry from c3) + // < 2^(102 + 2*b + lg(5)) + 2^64. + // + // When b < 3 we get + // + // c4 < 2^110.33 so that carry < 2^59.33 + // + // so that + // + // out[0] + carry * 19 < 2^51 + 19 * 2^59.33 < 2^63.58 + // + // and there is no overflow. + out[0] = out[0] + carry * 19; + + // Now out[1] < 2^51 + 2^(64 -51) = 2^51 + 2^13 < 2^(51 + epsilon). + out[1] += out[0] >> 51; + out[0] &= LOW_51_BIT_MASK; + + // Now out[i] < 2^(51 + epsilon) for all i. + FieldElement51(out) + } +} + +impl<'a> Neg for &'a FieldElement51 { + type Output = FieldElement51; + fn neg(self) -> FieldElement51 { + let mut output = *self; + output.negate(); + output + } +} + +impl ConditionallySelectable for FieldElement51 { + fn conditional_select( + a: &FieldElement51, + b: &FieldElement51, + choice: Choice, + ) -> FieldElement51 { + FieldElement51([ + u64::conditional_select(&a.0[0], &b.0[0], choice), + u64::conditional_select(&a.0[1], &b.0[1], choice), + u64::conditional_select(&a.0[2], &b.0[2], choice), + u64::conditional_select(&a.0[3], &b.0[3], choice), + u64::conditional_select(&a.0[4], &b.0[4], choice), + ]) + } + + fn conditional_swap(a: &mut FieldElement51, b: &mut FieldElement51, choice: Choice) { + u64::conditional_swap(&mut a.0[0], &mut b.0[0], choice); + u64::conditional_swap(&mut a.0[1], &mut b.0[1], choice); + u64::conditional_swap(&mut a.0[2], &mut b.0[2], choice); + u64::conditional_swap(&mut a.0[3], &mut b.0[3], choice); + u64::conditional_swap(&mut a.0[4], &mut b.0[4], choice); + } + + fn conditional_assign(&mut self, other: &FieldElement51, choice: Choice) { + self.0[0].conditional_assign(&other.0[0], choice); + self.0[1].conditional_assign(&other.0[1], choice); + self.0[2].conditional_assign(&other.0[2], choice); + self.0[3].conditional_assign(&other.0[3], choice); + self.0[4].conditional_assign(&other.0[4], choice); + } +} + +impl FieldElement51 { + /// Invert the sign of this field element + pub fn negate(&mut self) { + // See commentary in the Sub impl + let neg = FieldElement51::reduce([ + 36028797018963664u64 - self.0[0], + 36028797018963952u64 - self.0[1], + 36028797018963952u64 - self.0[2], + 36028797018963952u64 - self.0[3], + 36028797018963952u64 - self.0[4], + ]); + self.0 = neg.0; + } + + /// Construct zero. + pub fn zero() -> FieldElement51 { + FieldElement51([ 0, 0, 0, 0, 0 ]) + } + + /// Construct one. + pub fn one() -> FieldElement51 { + FieldElement51([ 1, 0, 0, 0, 0 ]) + } + + /// Construct -1. + pub fn minus_one() -> FieldElement51 { + FieldElement51([2251799813685228, 2251799813685247, 2251799813685247, 2251799813685247, 2251799813685247]) + } + + /// Given 64-bit input limbs, reduce to enforce the bound 2^(51 + epsilon). + #[inline(always)] + fn reduce(mut limbs: [u64; 5]) -> FieldElement51 { + const LOW_51_BIT_MASK: u64 = (1u64 << 51) - 1; + + // Since the input limbs are bounded by 2^64, the biggest + // carry-out is bounded by 2^13. + // + // The biggest carry-in is c4 * 19, resulting in + // + // 2^51 + 19*2^13 < 2^51.0000000001 + // + // Because we don't need to canonicalize, only to reduce the + // limb sizes, it's OK to do a "weak reduction", where we + // compute the carry-outs in parallel. + + let c0 = limbs[0] >> 51; + let c1 = limbs[1] >> 51; + let c2 = limbs[2] >> 51; + let c3 = limbs[3] >> 51; + let c4 = limbs[4] >> 51; + + limbs[0] &= LOW_51_BIT_MASK; + limbs[1] &= LOW_51_BIT_MASK; + limbs[2] &= LOW_51_BIT_MASK; + limbs[3] &= LOW_51_BIT_MASK; + limbs[4] &= LOW_51_BIT_MASK; + + limbs[0] += c4 * 19; + limbs[1] += c0; + limbs[2] += c1; + limbs[3] += c2; + limbs[4] += c3; + + FieldElement51(limbs) + } + + /// Load a `FieldElement51` from the low 255 bits of a 256-bit + /// input. + /// + /// # Warning + /// + /// This function does not check that the input used the canonical + /// representative. It masks the high bit, but it will happily + /// decode 2^255 - 18 to 1. Applications that require a canonical + /// encoding of every field element should decode, re-encode to + /// the canonical encoding, and check that the input was + /// canonical. + /// + pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement51 { + let load8 = |input: &[u8]| -> u64 { + (input[0] as u64) + | ((input[1] as u64) << 8) + | ((input[2] as u64) << 16) + | ((input[3] as u64) << 24) + | ((input[4] as u64) << 32) + | ((input[5] as u64) << 40) + | ((input[6] as u64) << 48) + | ((input[7] as u64) << 56) + }; + + let low_51_bit_mask = (1u64 << 51) - 1; + FieldElement51( + // load bits [ 0, 64), no shift + [ load8(&bytes[ 0..]) & low_51_bit_mask + // load bits [ 48,112), shift to [ 51,112) + , (load8(&bytes[ 6..]) >> 3) & low_51_bit_mask + // load bits [ 96,160), shift to [102,160) + , (load8(&bytes[12..]) >> 6) & low_51_bit_mask + // load bits [152,216), shift to [153,216) + , (load8(&bytes[19..]) >> 1) & low_51_bit_mask + // load bits [192,256), shift to [204,112) + , (load8(&bytes[24..]) >> 12) & low_51_bit_mask + ]) + } + + /// Serialize this `FieldElement51` to a 32-byte array. The + /// encoding is canonical. + pub fn to_bytes(&self) -> [u8; 32] { + // Let h = limbs[0] + limbs[1]*2^51 + ... + limbs[4]*2^204. + // + // Write h = pq + r with 0 <= r < p. + // + // We want to compute r = h mod p. + // + // If h < 2*p = 2^256 - 38, + // then q = 0 or 1, + // + // with q = 0 when h < p + // and q = 1 when h >= p. + // + // Notice that h >= p <==> h + 19 >= p + 19 <==> h + 19 >= 2^255. + // Therefore q can be computed as the carry bit of h + 19. + + // First, reduce the limbs to ensure h < 2*p. + let mut limbs = FieldElement51::reduce(self.0).0; + + let mut q = (limbs[0] + 19) >> 51; + q = (limbs[1] + q) >> 51; + q = (limbs[2] + q) >> 51; + q = (limbs[3] + q) >> 51; + q = (limbs[4] + q) >> 51; + + // Now we can compute r as r = h - pq = r - (2^255-19)q = r + 19q - 2^255q + + limbs[0] += 19*q; + + // Now carry the result to compute r + 19q ... + let low_51_bit_mask = (1u64 << 51) - 1; + limbs[1] += limbs[0] >> 51; + limbs[0] = limbs[0] & low_51_bit_mask; + limbs[2] += limbs[1] >> 51; + limbs[1] = limbs[1] & low_51_bit_mask; + limbs[3] += limbs[2] >> 51; + limbs[2] = limbs[2] & low_51_bit_mask; + limbs[4] += limbs[3] >> 51; + limbs[3] = limbs[3] & low_51_bit_mask; + // ... but instead of carrying (limbs[4] >> 51) = 2^255q + // into another limb, discard it, subtracting the value + limbs[4] = limbs[4] & low_51_bit_mask; + + // Now arrange the bits of the limbs. + let mut s = [0u8;32]; + s[ 0] = limbs[0] as u8; + s[ 1] = (limbs[0] >> 8) as u8; + s[ 2] = (limbs[0] >> 16) as u8; + s[ 3] = (limbs[0] >> 24) as u8; + s[ 4] = (limbs[0] >> 32) as u8; + s[ 5] = (limbs[0] >> 40) as u8; + s[ 6] = ((limbs[0] >> 48) | (limbs[1] << 3)) as u8; + s[ 7] = (limbs[1] >> 5) as u8; + s[ 8] = (limbs[1] >> 13) as u8; + s[ 9] = (limbs[1] >> 21) as u8; + s[10] = (limbs[1] >> 29) as u8; + s[11] = (limbs[1] >> 37) as u8; + s[12] = ((limbs[1] >> 45) | (limbs[2] << 6)) as u8; + s[13] = (limbs[2] >> 2) as u8; + s[14] = (limbs[2] >> 10) as u8; + s[15] = (limbs[2] >> 18) as u8; + s[16] = (limbs[2] >> 26) as u8; + s[17] = (limbs[2] >> 34) as u8; + s[18] = (limbs[2] >> 42) as u8; + s[19] = ((limbs[2] >> 50) | (limbs[3] << 1)) as u8; + s[20] = (limbs[3] >> 7) as u8; + s[21] = (limbs[3] >> 15) as u8; + s[22] = (limbs[3] >> 23) as u8; + s[23] = (limbs[3] >> 31) as u8; + s[24] = (limbs[3] >> 39) as u8; + s[25] = ((limbs[3] >> 47) | (limbs[4] << 4)) as u8; + s[26] = (limbs[4] >> 4) as u8; + s[27] = (limbs[4] >> 12) as u8; + s[28] = (limbs[4] >> 20) as u8; + s[29] = (limbs[4] >> 28) as u8; + s[30] = (limbs[4] >> 36) as u8; + s[31] = (limbs[4] >> 44) as u8; + + // High bit should be zero. + debug_assert!((s[31] & 0b1000_0000u8) == 0u8); + + s + } + + /// Given `k > 0`, return `self^(2^k)`. + pub fn pow2k(&self, mut k: u32) -> FieldElement51 { + + debug_assert!( k > 0 ); + + /// Multiply two 64-bit integers with 128 bits of output. + #[inline(always)] + fn m(x: u64, y: u64) -> u128 { (x as u128) * (y as u128) } + + let mut a: [u64; 5] = self.0; + + loop { + // Precondition: assume input limbs a[i] are bounded as + // + // a[i] < 2^(51 + b) + // + // where b is a real parameter measuring the "bit excess" of the limbs. + + // Precomputation: 64-bit multiply by 19. + // + // This fits into a u64 whenever 51 + b + lg(19) < 64. + // + // Since 51 + b + lg(19) < 51 + 4.25 + b + // = 55.25 + b, + // this fits if b < 8.75. + let a3_19 = 19 * a[3]; + let a4_19 = 19 * a[4]; + + // Multiply to get 128-bit coefficients of output. + // + // The 128-bit multiplications by 2 turn into 1 slr + 1 slrd each, + // which doesn't seem any better or worse than doing them as precomputations + // on the 64-bit inputs. + let c0: u128 = m(a[0], a[0]) + 2*( m(a[1], a4_19) + m(a[2], a3_19) ); + let mut c1: u128 = m(a[3], a3_19) + 2*( m(a[0], a[1]) + m(a[2], a4_19) ); + let mut c2: u128 = m(a[1], a[1]) + 2*( m(a[0], a[2]) + m(a[4], a3_19) ); + let mut c3: u128 = m(a[4], a4_19) + 2*( m(a[0], a[3]) + m(a[1], a[2]) ); + let mut c4: u128 = m(a[2], a[2]) + 2*( m(a[0], a[4]) + m(a[1], a[3]) ); + + // Same bound as in multiply: + // c[i] < 2^(102 + 2*b) * (1+i + (4-i)*19) + // < 2^(102 + lg(1 + 4*19) + 2*b) + // < 2^(108.27 + 2*b) + // + // The carry (c[i] >> 51) fits into a u64 when + // 108.27 + 2*b - 51 < 64 + // 2*b < 6.73 + // b < 3.365. + // + // So we require b < 3 to ensure this fits. + debug_assert!(a[0] < (1 << 54)); + debug_assert!(a[1] < (1 << 54)); + debug_assert!(a[2] < (1 << 54)); + debug_assert!(a[3] < (1 << 54)); + debug_assert!(a[4] < (1 << 54)); + + const LOW_51_BIT_MASK: u64 = (1u64 << 51) - 1; + + // Casting to u64 and back tells the compiler that the carry is bounded by 2^64, so + // that the addition is a u128 + u64 rather than u128 + u128. + c1 += ((c0 >> 51) as u64) as u128; + a[0] = (c0 as u64) & LOW_51_BIT_MASK; + + c2 += ((c1 >> 51) as u64) as u128; + a[1] = (c1 as u64) & LOW_51_BIT_MASK; + + c3 += ((c2 >> 51) as u64) as u128; + a[2] = (c2 as u64) & LOW_51_BIT_MASK; + + c4 += ((c3 >> 51) as u64) as u128; + a[3] = (c3 as u64) & LOW_51_BIT_MASK; + + let carry: u64 = (c4 >> 51) as u64; + a[4] = (c4 as u64) & LOW_51_BIT_MASK; + + // To see that this does not overflow, we need a[0] + carry * 19 < 2^64. + // + // c4 < a2^2 + 2*a0*a4 + 2*a1*a3 + (carry from c3) + // < 2^(102 + 2*b + lg(5)) + 2^64. + // + // When b < 3 we get + // + // c4 < 2^110.33 so that carry < 2^59.33 + // + // so that + // + // a[0] + carry * 19 < 2^51 + 19 * 2^59.33 < 2^63.58 + // + // and there is no overflow. + a[0] = a[0] + carry * 19; + + // Now a[1] < 2^51 + 2^(64 -51) = 2^51 + 2^13 < 2^(51 + epsilon). + a[1] += a[0] >> 51; + a[0] &= LOW_51_BIT_MASK; + + // Now all a[i] < 2^(51 + epsilon) and a = self^(2^k). + + k = k - 1; + if k == 0 { + break; + } + } + + FieldElement51(a) + } + + /// Returns the square of this field element. + pub fn square(&self) -> FieldElement51 { + self.pow2k(1) + } + + /// Returns 2 times the square of this field element. + pub fn square2(&self) -> FieldElement51 { + let mut square = self.pow2k(1); + for i in 0..5 { + square.0[i] *= 2; + } + + square + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/mod.rs new file mode 100644 index 0000000..aa29eb6 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/mod.rs @@ -0,0 +1,27 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2018 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! The `u64` backend uses `u64`s and a `(u64, u64) -> u128` multiplier. +//! +//! On x86_64, the idiom `(x as u128) * (y as u128)` lowers to `MUL` +//! instructions taking 64-bit inputs and producing 128-bit outputs. On +//! other platforms, this implementation is not recommended. +//! +//! On Haswell and newer, the BMI2 extension provides `MULX`, and on +//! Broadwell and newer, the ADX extension provides `ADCX` and `ADOX` +//! (allowing the CPU to compute two carry chains in parallel). These +//! will be used if available. + +pub mod field; + +pub mod scalar; + +pub mod constants; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/scalar.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/scalar.rs new file mode 100644 index 0000000..cee69da --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/serial/u64/scalar.rs @@ -0,0 +1,450 @@ +//! Arithmetic mod \\(2\^{252} + 27742317777372353535851937790883648493\\) +//! with five \\(52\\)-bit unsigned limbs. +//! +//! \\(51\\)-bit limbs would cover the desired bit range (\\(253\\) +//! bits), but isn't large enough to reduce a \\(512\\)-bit number with +//! Montgomery multiplication, so \\(52\\) bits is used instead. To see +//! that this is safe for intermediate results, note that the largest +//! limb in a \\(5\times 5\\) product of \\(52\\)-bit limbs will be +//! +//! ```text +//! (0xfffffffffffff^2) * 5 = 0x4ffffffffffff60000000000005 (107 bits). +//! ``` + +use core::fmt::Debug; +use core::ops::{Index, IndexMut}; + +use zeroize::Zeroize; + +use constants; + +/// The `Scalar52` struct represents an element in +/// \\(\mathbb Z / \ell \mathbb Z\\) as 5 \\(52\\)-bit limbs. +#[derive(Copy,Clone)] +pub struct Scalar52(pub [u64; 5]); + +impl Debug for Scalar52 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "Scalar52: {:?}", &self.0[..]) + } +} + +impl Zeroize for Scalar52 { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl Index for Scalar52 { + type Output = u64; + fn index(&self, _index: usize) -> &u64 { + &(self.0[_index]) + } +} + +impl IndexMut for Scalar52 { + fn index_mut(&mut self, _index: usize) -> &mut u64 { + &mut (self.0[_index]) + } +} + +/// u64 * u64 = u128 multiply helper +#[inline(always)] +fn m(x: u64, y: u64) -> u128 { + (x as u128) * (y as u128) +} + +impl Scalar52 { + /// Return the zero scalar + pub fn zero() -> Scalar52 { + Scalar52([0,0,0,0,0]) + } + + /// Unpack a 32 byte / 256 bit scalar into 5 52-bit limbs. + pub fn from_bytes(bytes: &[u8; 32]) -> Scalar52 { + let mut words = [0u64; 4]; + for i in 0..4 { + for j in 0..8 { + words[i] |= (bytes[(i * 8) + j] as u64) << (j * 8); + } + } + + let mask = (1u64 << 52) - 1; + let top_mask = (1u64 << 48) - 1; + let mut s = Scalar52::zero(); + + s[ 0] = words[0] & mask; + s[ 1] = ((words[0] >> 52) | (words[1] << 12)) & mask; + s[ 2] = ((words[1] >> 40) | (words[2] << 24)) & mask; + s[ 3] = ((words[2] >> 28) | (words[3] << 36)) & mask; + s[ 4] = (words[3] >> 16) & top_mask; + + s + } + + /// Reduce a 64 byte / 512 bit scalar mod l + pub fn from_bytes_wide(bytes: &[u8; 64]) -> Scalar52 { + let mut words = [0u64; 8]; + for i in 0..8 { + for j in 0..8 { + words[i] |= (bytes[(i * 8) + j] as u64) << (j * 8); + } + } + + let mask = (1u64 << 52) - 1; + let mut lo = Scalar52::zero(); + let mut hi = Scalar52::zero(); + + lo[0] = words[ 0] & mask; + lo[1] = ((words[ 0] >> 52) | (words[ 1] << 12)) & mask; + lo[2] = ((words[ 1] >> 40) | (words[ 2] << 24)) & mask; + lo[3] = ((words[ 2] >> 28) | (words[ 3] << 36)) & mask; + lo[4] = ((words[ 3] >> 16) | (words[ 4] << 48)) & mask; + hi[0] = (words[ 4] >> 4) & mask; + hi[1] = ((words[ 4] >> 56) | (words[ 5] << 8)) & mask; + hi[2] = ((words[ 5] >> 44) | (words[ 6] << 20)) & mask; + hi[3] = ((words[ 6] >> 32) | (words[ 7] << 32)) & mask; + hi[4] = words[ 7] >> 20 ; + + lo = Scalar52::montgomery_mul(&lo, &constants::R); // (lo * R) / R = lo + hi = Scalar52::montgomery_mul(&hi, &constants::RR); // (hi * R^2) / R = hi * R + + Scalar52::add(&hi, &lo) + } + + /// Pack the limbs of this `Scalar52` into 32 bytes + pub fn to_bytes(&self) -> [u8; 32] { + let mut s = [0u8; 32]; + + s[0] = (self.0[ 0] >> 0) as u8; + s[1] = (self.0[ 0] >> 8) as u8; + s[2] = (self.0[ 0] >> 16) as u8; + s[3] = (self.0[ 0] >> 24) as u8; + s[4] = (self.0[ 0] >> 32) as u8; + s[5] = (self.0[ 0] >> 40) as u8; + s[6] = ((self.0[ 0] >> 48) | (self.0[ 1] << 4)) as u8; + s[7] = (self.0[ 1] >> 4) as u8; + s[8] = (self.0[ 1] >> 12) as u8; + s[9] = (self.0[ 1] >> 20) as u8; + s[10] = (self.0[ 1] >> 28) as u8; + s[11] = (self.0[ 1] >> 36) as u8; + s[12] = (self.0[ 1] >> 44) as u8; + s[13] = (self.0[ 2] >> 0) as u8; + s[14] = (self.0[ 2] >> 8) as u8; + s[15] = (self.0[ 2] >> 16) as u8; + s[16] = (self.0[ 2] >> 24) as u8; + s[17] = (self.0[ 2] >> 32) as u8; + s[18] = (self.0[ 2] >> 40) as u8; + s[19] = ((self.0[ 2] >> 48) | (self.0[ 3] << 4)) as u8; + s[20] = (self.0[ 3] >> 4) as u8; + s[21] = (self.0[ 3] >> 12) as u8; + s[22] = (self.0[ 3] >> 20) as u8; + s[23] = (self.0[ 3] >> 28) as u8; + s[24] = (self.0[ 3] >> 36) as u8; + s[25] = (self.0[ 3] >> 44) as u8; + s[26] = (self.0[ 4] >> 0) as u8; + s[27] = (self.0[ 4] >> 8) as u8; + s[28] = (self.0[ 4] >> 16) as u8; + s[29] = (self.0[ 4] >> 24) as u8; + s[30] = (self.0[ 4] >> 32) as u8; + s[31] = (self.0[ 4] >> 40) as u8; + + s + } + + /// Compute `a + b` (mod l) + pub fn add(a: &Scalar52, b: &Scalar52) -> Scalar52 { + let mut sum = Scalar52::zero(); + let mask = (1u64 << 52) - 1; + + // a + b + let mut carry: u64 = 0; + for i in 0..5 { + carry = a[i] + b[i] + (carry >> 52); + sum[i] = carry & mask; + } + + // subtract l if the sum is >= l + Scalar52::sub(&sum, &constants::L) + } + + /// Compute `a - b` (mod l) + pub fn sub(a: &Scalar52, b: &Scalar52) -> Scalar52 { + let mut difference = Scalar52::zero(); + let mask = (1u64 << 52) - 1; + + // a - b + let mut borrow: u64 = 0; + for i in 0..5 { + borrow = a[i].wrapping_sub(b[i] + (borrow >> 63)); + difference[i] = borrow & mask; + } + + // conditionally add l if the difference is negative + let underflow_mask = ((borrow >> 63) ^ 1).wrapping_sub(1); + let mut carry: u64 = 0; + for i in 0..5 { + carry = (carry >> 52) + difference[i] + (constants::L[i] & underflow_mask); + difference[i] = carry & mask; + } + + difference + } + + /// Compute `a * b` + #[inline(always)] + pub (crate) fn mul_internal(a: &Scalar52, b: &Scalar52) -> [u128; 9] { + let mut z = [0u128; 9]; + + z[0] = m(a[0],b[0]); + z[1] = m(a[0],b[1]) + m(a[1],b[0]); + z[2] = m(a[0],b[2]) + m(a[1],b[1]) + m(a[2],b[0]); + z[3] = m(a[0],b[3]) + m(a[1],b[2]) + m(a[2],b[1]) + m(a[3],b[0]); + z[4] = m(a[0],b[4]) + m(a[1],b[3]) + m(a[2],b[2]) + m(a[3],b[1]) + m(a[4],b[0]); + z[5] = m(a[1],b[4]) + m(a[2],b[3]) + m(a[3],b[2]) + m(a[4],b[1]); + z[6] = m(a[2],b[4]) + m(a[3],b[3]) + m(a[4],b[2]); + z[7] = m(a[3],b[4]) + m(a[4],b[3]); + z[8] = m(a[4],b[4]); + + z + } + + /// Compute `a^2` + #[inline(always)] + fn square_internal(a: &Scalar52) -> [u128; 9] { + let aa = [ + a[0]*2, + a[1]*2, + a[2]*2, + a[3]*2, + ]; + + [ + m( a[0],a[0]), + m(aa[0],a[1]), + m(aa[0],a[2]) + m( a[1],a[1]), + m(aa[0],a[3]) + m(aa[1],a[2]), + m(aa[0],a[4]) + m(aa[1],a[3]) + m( a[2],a[2]), + m(aa[1],a[4]) + m(aa[2],a[3]), + m(aa[2],a[4]) + m( a[3],a[3]), + m(aa[3],a[4]), + m(a[4],a[4]) + ] + } + + /// Compute `limbs/R` (mod l), where R is the Montgomery modulus 2^260 + #[inline(always)] + pub (crate) fn montgomery_reduce(limbs: &[u128; 9]) -> Scalar52 { + + #[inline(always)] + fn part1(sum: u128) -> (u128, u64) { + let p = (sum as u64).wrapping_mul(constants::LFACTOR) & ((1u64 << 52) - 1); + ((sum + m(p,constants::L[0])) >> 52, p) + } + + #[inline(always)] + fn part2(sum: u128) -> (u128, u64) { + let w = (sum as u64) & ((1u64 << 52) - 1); + (sum >> 52, w) + } + + // note: l[3] is zero, so its multiples can be skipped + let l = &constants::L; + + // the first half computes the Montgomery adjustment factor n, and begins adding n*l to make limbs divisible by R + let (carry, n0) = part1( limbs[0]); + let (carry, n1) = part1(carry + limbs[1] + m(n0,l[1])); + let (carry, n2) = part1(carry + limbs[2] + m(n0,l[2]) + m(n1,l[1])); + let (carry, n3) = part1(carry + limbs[3] + m(n1,l[2]) + m(n2,l[1])); + let (carry, n4) = part1(carry + limbs[4] + m(n0,l[4]) + m(n2,l[2]) + m(n3,l[1])); + + // limbs is divisible by R now, so we can divide by R by simply storing the upper half as the result + let (carry, r0) = part2(carry + limbs[5] + m(n1,l[4]) + m(n3,l[2]) + m(n4,l[1])); + let (carry, r1) = part2(carry + limbs[6] + m(n2,l[4]) + m(n4,l[2])); + let (carry, r2) = part2(carry + limbs[7] + m(n3,l[4]) ); + let (carry, r3) = part2(carry + limbs[8] + m(n4,l[4])); + let r4 = carry as u64; + + // result may be >= l, so attempt to subtract l + Scalar52::sub(&Scalar52([r0,r1,r2,r3,r4]), l) + } + + /// Compute `a * b` (mod l) + #[inline(never)] + pub fn mul(a: &Scalar52, b: &Scalar52) -> Scalar52 { + let ab = Scalar52::montgomery_reduce(&Scalar52::mul_internal(a, b)); + Scalar52::montgomery_reduce(&Scalar52::mul_internal(&ab, &constants::RR)) + } + + /// Compute `a^2` (mod l) + #[inline(never)] + #[allow(dead_code)] // XXX we don't expose square() via the Scalar API + pub fn square(&self) -> Scalar52 { + let aa = Scalar52::montgomery_reduce(&Scalar52::square_internal(self)); + Scalar52::montgomery_reduce(&Scalar52::mul_internal(&aa, &constants::RR)) + } + + /// Compute `(a * b) / R` (mod l), where R is the Montgomery modulus 2^260 + #[inline(never)] + pub fn montgomery_mul(a: &Scalar52, b: &Scalar52) -> Scalar52 { + Scalar52::montgomery_reduce(&Scalar52::mul_internal(a, b)) + } + + /// Compute `(a^2) / R` (mod l) in Montgomery form, where R is the Montgomery modulus 2^260 + #[inline(never)] + pub fn montgomery_square(&self) -> Scalar52 { + Scalar52::montgomery_reduce(&Scalar52::square_internal(self)) + } + + /// Puts a Scalar52 in to Montgomery form, i.e. computes `a*R (mod l)` + #[inline(never)] + pub fn to_montgomery(&self) -> Scalar52 { + Scalar52::montgomery_mul(self, &constants::RR) + } + + /// Takes a Scalar52 out of Montgomery form, i.e. computes `a/R (mod l)` + #[inline(never)] + pub fn from_montgomery(&self) -> Scalar52 { + let mut limbs = [0u128; 9]; + for i in 0..5 { + limbs[i] = self[i] as u128; + } + Scalar52::montgomery_reduce(&limbs) + } +} + + +#[cfg(test)] +mod test { + use super::*; + + /// Note: x is 2^253-1 which is slightly larger than the largest scalar produced by + /// this implementation (l-1), and should show there are no overflows for valid scalars + /// + /// x = 14474011154664524427946373126085988481658748083205070504932198000989141204991 + /// x = 7237005577332262213973186563042994240801631723825162898930247062703686954002 mod l + /// x = 3057150787695215392275360544382990118917283750546154083604586903220563173085*R mod l in Montgomery form + pub static X: Scalar52 = Scalar52( + [0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, + 0x00001fffffffffff]); + + /// x^2 = 3078544782642840487852506753550082162405942681916160040940637093560259278169 mod l + pub static XX: Scalar52 = Scalar52( + [0x0001668020217559, 0x000531640ffd0ec0, 0x00085fd6f9f38a31, 0x000c268f73bb1cf4, + 0x000006ce65046df0]); + + /// x^2 = 4413052134910308800482070043710297189082115023966588301924965890668401540959*R mod l in Montgomery form + pub static XX_MONT: Scalar52 = Scalar52( + [0x000c754eea569a5c, 0x00063b6ed36cb215, 0x0008ffa36bf25886, 0x000e9183614e7543, + 0x0000061db6c6f26f]); + + /// y = 6145104759870991071742105800796537629880401874866217824609283457819451087098 + pub static Y: Scalar52 = Scalar52( + [0x000b75071e1458fa, 0x000bf9d75e1ecdac, 0x000433d2baf0672b, 0x0005fffcc11fad13, + 0x00000d96018bb825]); + + /// x*y = 36752150652102274958925982391442301741 mod l + pub static XY: Scalar52 = Scalar52( + [0x000ee6d76ba7632d, 0x000ed50d71d84e02, 0x00000000001ba634, 0x0000000000000000, + 0x0000000000000000]); + + /// x*y = 658448296334113745583381664921721413881518248721417041768778176391714104386*R mod l in Montgomery form + pub static XY_MONT: Scalar52 = Scalar52( + [0x0006d52bf200cfd5, 0x00033fb1d7021570, 0x000f201bc07139d8, 0x0001267e3e49169e, + 0x000007b839c00268]); + + /// a = 2351415481556538453565687241199399922945659411799870114962672658845158063753 + pub static A: Scalar52 = Scalar52( + [0x0005236c07b3be89, 0x0001bc3d2a67c0c4, 0x000a4aa782aae3ee, 0x0006b3f6e4fec4c4, + 0x00000532da9fab8c]); + + /// b = 4885590095775723760407499321843594317911456947580037491039278279440296187236 + pub static B: Scalar52 = Scalar52( + [0x000d3fae55421564, 0x000c2df24f65a4bc, 0x0005b5587d69fb0b, 0x00094c091b013b3b, + 0x00000acd25605473]); + + /// a+b = 0 + /// a-b = 4702830963113076907131374482398799845891318823599740229925345317690316127506 + pub static AB: Scalar52 = Scalar52( + [0x000a46d80f677d12, 0x0003787a54cf8188, 0x0004954f0555c7dc, 0x000d67edc9fd8989, + 0x00000a65b53f5718]); + + // c = (2^512 - 1) % l = 1627715501170711445284395025044413883736156588369414752970002579683115011840 + pub static C: Scalar52 = Scalar52( + [0x000611e3449c0f00, 0x000a768859347a40, 0x0007f5be65d00e1b, 0x0009a3dceec73d21, + 0x00000399411b7c30]); + + #[test] + fn mul_max() { + let res = Scalar52::mul(&X, &X); + for i in 0..5 { + assert!(res[i] == XX[i]); + } + } + + #[test] + fn square_max() { + let res = X.square(); + for i in 0..5 { + assert!(res[i] == XX[i]); + } + } + + #[test] + fn montgomery_mul_max() { + let res = Scalar52::montgomery_mul(&X, &X); + for i in 0..5 { + assert!(res[i] == XX_MONT[i]); + } + } + + #[test] + fn montgomery_square_max() { + let res = X.montgomery_square(); + for i in 0..5 { + assert!(res[i] == XX_MONT[i]); + } + } + + #[test] + fn mul() { + let res = Scalar52::mul(&X, &Y); + for i in 0..5 { + assert!(res[i] == XY[i]); + } + } + + #[test] + fn montgomery_mul() { + let res = Scalar52::montgomery_mul(&X, &Y); + for i in 0..5 { + assert!(res[i] == XY_MONT[i]); + } + } + + #[test] + fn add() { + let res = Scalar52::add(&A, &B); + let zero = Scalar52::zero(); + for i in 0..5 { + assert!(res[i] == zero[i]); + } + } + + #[test] + fn sub() { + let res = Scalar52::sub(&A, &B); + for i in 0..5 { + assert!(res[i] == AB[i]); + } + } + + #[test] + fn from_bytes_wide() { + let bignum = [255u8; 64]; // 2^512 - 1 + let reduced = Scalar52::from_bytes_wide(&bignum); + for i in 0..5 { + assert!(reduced[i] == C[i]); + } + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/constants.rs new file mode 100644 index 0000000..122068e --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/constants.rs @@ -0,0 +1,3428 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! This module contains constants used by the AVX2 backend. + +use packed_simd::u32x8; + +use backend::vector::avx2::edwards::{CachedPoint, ExtendedPoint}; +use backend::vector::avx2::field::FieldElement2625x4; +use window::NafLookupTable8; + +/// The identity element as an `ExtendedPoint`. +pub(crate) static EXTENDEDPOINT_IDENTITY: ExtendedPoint = ExtendedPoint(FieldElement2625x4([ + u32x8::new(0, 1, 0, 0, 1, 0, 0, 0), + u32x8::splat(0), + u32x8::splat(0), + u32x8::splat(0), + u32x8::splat(0), +])); + +/// The identity element as a `CachedPoint`. +pub(crate) static CACHEDPOINT_IDENTITY: CachedPoint = CachedPoint(FieldElement2625x4([ + u32x8::new(121647, 121666, 0, 0, 243332, 67108845, 0, 33554431), + u32x8::new(67108864, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), +])); + +/// The low limbs of (2p, 2p, 2p, 2p), so that +/// ```ascii,no_run +/// (2p, 2p, 2p, 2p) = [P_TIMES_2_LO, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI] +/// ``` +pub(crate) static P_TIMES_2_LO: u32x8 = u32x8::new( + 67108845 << 1, + 67108845 << 1, + 33554431 << 1, + 33554431 << 1, + 67108845 << 1, + 67108845 << 1, + 33554431 << 1, + 33554431 << 1, +); + +/// The high limbs of (2p, 2p, 2p, 2p), so that +/// ```ascii,no_run +/// (2p, 2p, 2p, 2p) = [P_TIMES_2_LO, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI] +/// ``` +pub(crate) static P_TIMES_2_HI: u32x8 = u32x8::new( + 67108863 << 1, + 67108863 << 1, + 33554431 << 1, + 33554431 << 1, + 67108863 << 1, + 67108863 << 1, + 33554431 << 1, + 33554431 << 1, +); + +/// The low limbs of (16p, 16p, 16p, 16p), so that +/// ```ascii,no_run +/// (16p, 16p, 16p, 16p) = [P_TIMES_16_LO, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI] +/// ``` +pub(crate) static P_TIMES_16_LO: u32x8 = u32x8::new( + 67108845 << 4, + 67108845 << 4, + 33554431 << 4, + 33554431 << 4, + 67108845 << 4, + 67108845 << 4, + 33554431 << 4, + 33554431 << 4, +); + +/// The high limbs of (16p, 16p, 16p, 16p), so that +/// ```ascii,no_run +/// (16p, 16p, 16p, 16p) = [P_TIMES_16_LO, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI] +/// ``` +pub(crate) static P_TIMES_16_HI: u32x8 = u32x8::new( + 67108863 << 4, + 67108863 << 4, + 33554431 << 4, + 33554431 << 4, + 67108863 << 4, + 67108863 << 4, + 33554431 << 4, + 33554431 << 4, +); + +/// Odd multiples of the Ed25519 basepoint: +pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = NafLookupTable8([ + CachedPoint(FieldElement2625x4([ + u32x8::new( + 3571425, + 10045002, + 19036563, + 1096096, + 243332, + 65897020, + 0, + 28963681, + ), + u32x8::new( + 30896895, + 63055514, + 1614915, + 5095970, + 0, + 53791688, + 0, + 31258312, + ), + u32x8::new( + 13347627, + 40339464, + 2236269, + 11185503, + 0, + 22520087, + 0, + 8659512, + ), + u32x8::new( + 11125413, + 29139905, + 32037254, + 28360723, + 0, + 64556417, + 0, + 9635759, + ), + u32x8::new( + 33268144, + 47262491, + 4336918, + 15795740, + 0, + 22027545, + 0, + 4846528, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 47099681, + 31447946, + 29365447, + 24740513, + 42991046, + 18317844, + 16051644, + 21404226, + ), + u32x8::new( + 31708133, + 28909527, + 2366091, + 13703791, + 469246, + 54159622, + 2601402, + 32988002, + ), + u32x8::new( + 63432457, + 30251794, + 15163516, + 18491340, + 28144087, + 35605455, + 13682295, + 18474872, + ), + u32x8::new( + 12221607, + 4967598, + 26061980, + 26008006, + 20226147, + 9726961, + 17410, + 18051083, + ), + u32x8::new( + 60569645, + 62487085, + 11911242, + 21920922, + 4092105, + 38186967, + 22431483, + 31366585, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 18147205, + 62587998, + 2554617, + 536692, + 11924528, + 26674131, + 17645433, + 24341419, + ), + u32x8::new( + 11573357, + 27579485, + 31491870, + 29000885, + 10800976, + 51902791, + 28076395, + 20464029, + ), + u32x8::new( + 56031649, + 10856669, + 11791193, + 26769430, + 25306956, + 5922200, + 6630685, + 9385098, + ), + u32x8::new( + 31319348, + 23906711, + 16290213, + 32142166, + 61106354, + 17181823, + 3548308, + 12022566, + ), + u32x8::new( + 5904298, + 50218605, + 11826440, + 5492249, + 10379071, + 3472255, + 172742, + 31948344, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 10625852, + 15193821, + 22918394, + 23676410, + 53695416, + 54987793, + 10067515, + 11747680, + ), + u32x8::new( + 65013325, + 1309652, + 29616320, + 28922974, + 60360891, + 19621771, + 9938982, + 30406429, + ), + u32x8::new( + 54967954, + 65931918, + 5595602, + 25719523, + 64909864, + 30566415, + 15945272, + 8495317, + ), + u32x8::new( + 1167157, + 55265018, + 11507029, + 31641054, + 43497904, + 2367338, + 12937761, + 27517066, + ), + u32x8::new( + 656704, + 2544994, + 13006713, + 480979, + 38471594, + 62541240, + 25353597, + 11531760, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 22176662, + 3984313, + 27495285, + 4110608, + 2909584, + 30594106, + 15677919, + 2549183, + ), + u32x8::new( + 33979105, + 62269905, + 2071511, + 6894756, + 53189950, + 47232857, + 6408191, + 6123225, + ), + u32x8::new( + 32553873, + 63948030, + 12612401, + 3633166, + 24054373, + 37626618, + 14481327, + 8520484, + ), + u32x8::new( + 56552486, + 10749438, + 12034813, + 28811946, + 1445640, + 36755601, + 12104575, + 10257833, + ), + u32x8::new( + 22795808, + 48761311, + 1136056, + 9380768, + 1411523, + 5341811, + 27318329, + 9686767, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 21157200, + 39156966, + 20473176, + 4934657, + 61478183, + 45121537, + 5429856, + 13035023, + ), + u32x8::new( + 7954529, + 58789246, + 31440083, + 7054221, + 38438565, + 36856107, + 1364112, + 14548122, + ), + u32x8::new( + 26120083, + 36321360, + 4919997, + 31687496, + 33757765, + 36237559, + 15243054, + 32163861, + ), + u32x8::new( + 25878307, + 46544824, + 19455951, + 2414935, + 16844726, + 56521560, + 32680554, + 26660660, + ), + u32x8::new( + 48360220, + 43407178, + 12187042, + 24925816, + 7423722, + 25746484, + 12814654, + 17395963, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 63153652, + 32195955, + 4087908, + 8431689, + 30392384, + 47203165, + 8986649, + 9053039, + ), + u32x8::new( + 63659241, + 47988767, + 2931872, + 19953600, + 11747107, + 51610101, + 20952181, + 13364887, + ), + u32x8::new( + 3659197, + 58790649, + 5930099, + 2605312, + 28477896, + 580728, + 20579735, + 2610622, + ), + u32x8::new( + 41781607, + 17161358, + 10690531, + 24368015, + 47027031, + 36742339, + 5414694, + 13156365, + ), + u32x8::new( + 13237853, + 51182423, + 8954802, + 29006542, + 22643989, + 56896541, + 22830593, + 10289708, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 1401265, + 58846825, + 30911620, + 32239180, + 15391552, + 15200821, + 6339309, + 16403588, + ), + u32x8::new( + 55913797, + 29541724, + 1664461, + 21709410, + 38470488, + 47097092, + 17674945, + 32666066, + ), + u32x8::new( + 22844482, + 10797709, + 27548106, + 31638735, + 34500968, + 26611503, + 19727211, + 13160873, + ), + u32x8::new( + 31485204, + 14496164, + 13981208, + 10276888, + 5748808, + 35024436, + 2740987, + 7479021, + ), + u32x8::new( + 58541207, + 14866135, + 32344041, + 545930, + 62661488, + 6941250, + 27940205, + 11976112, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 39849808, + 44781685, + 15697329, + 24387845, + 12501486, + 50260092, + 23199481, + 31929024, + ), + u32x8::new( + 24823070, + 27956017, + 27034296, + 10316465, + 47664045, + 11152446, + 15719183, + 30181617, + ), + u32x8::new( + 20771189, + 19969144, + 31433937, + 19185213, + 27565920, + 10384445, + 2893359, + 9255362, + ), + u32x8::new( + 42894974, + 11925545, + 32134441, + 32738810, + 55916336, + 32479272, + 19563550, + 5511385, + ), + u32x8::new( + 17857161, + 47809169, + 14564114, + 27997751, + 33024640, + 38669671, + 31956536, + 27313245, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 58237774, + 15917425, + 18872208, + 19394230, + 17374297, + 6101419, + 4839741, + 6596900, + ), + u32x8::new( + 66947393, + 15744215, + 18368993, + 17750160, + 41006525, + 9205497, + 2629667, + 32170865, + ), + u32x8::new( + 66481381, + 1919414, + 28338762, + 7372967, + 33819153, + 4156199, + 27126309, + 12739816, + ), + u32x8::new( + 44117158, + 58545296, + 22521371, + 11809712, + 28998792, + 50731010, + 30215699, + 25748377, + ), + u32x8::new( + 23561284, + 4160244, + 9035405, + 24895184, + 39761639, + 59253416, + 8684759, + 22487864, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 12671134, + 56419053, + 16092401, + 30038207, + 4002647, + 47822606, + 7151311, + 28430768, + ), + u32x8::new( + 61041684, + 35765374, + 30598048, + 19666539, + 44150175, + 40140037, + 290469, + 28442674, + ), + u32x8::new( + 18847796, + 1371617, + 33316881, + 13199936, + 43646578, + 17068881, + 12074900, + 1537415, + ), + u32x8::new( + 10052225, + 38316070, + 27469797, + 5297537, + 50725570, + 20435349, + 10339121, + 2779737, + ), + u32x8::new( + 18372189, + 15466385, + 24762130, + 22217964, + 23503887, + 47844464, + 10415034, + 2606889, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 55082775, + 45300503, + 16032654, + 5964396, + 17743504, + 24634761, + 19493066, + 5184611, + ), + u32x8::new( + 50172633, + 35093294, + 10040575, + 23616256, + 4543900, + 61852191, + 4049821, + 7423669, + ), + u32x8::new( + 20295398, + 40009376, + 10487190, + 15670429, + 51972856, + 58649552, + 20436392, + 3432497, + ), + u32x8::new( + 35189420, + 54117751, + 12825868, + 6283038, + 27540739, + 30648758, + 22658912, + 9466689, + ), + u32x8::new( + 51737549, + 40725785, + 17409814, + 25201086, + 21156239, + 34176168, + 26814520, + 5956424, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 8211442, + 8014184, + 6260823, + 22108096, + 32182620, + 51844847, + 2466270, + 28582231, + ), + u32x8::new( + 27199739, + 3848333, + 31738017, + 10892045, + 4963982, + 65391770, + 32551997, + 28906469, + ), + u32x8::new( + 16606846, + 32207068, + 26404535, + 7614129, + 45416902, + 65584718, + 13821785, + 2646060, + ), + u32x8::new( + 36090634, + 57981287, + 32247670, + 22837502, + 31003861, + 55448117, + 6062915, + 20369975, + ), + u32x8::new( + 27381403, + 50578107, + 522631, + 29521058, + 31137497, + 40220737, + 27628049, + 1824195, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 59402443, + 17056879, + 29262689, + 6131785, + 52551472, + 43367471, + 29423199, + 18899208, + ), + u32x8::new( + 5749414, + 43514612, + 11365899, + 21514624, + 65591890, + 60945892, + 19841732, + 5628567, + ), + u32x8::new( + 19334369, + 52500268, + 12307673, + 5267367, + 3212103, + 9035822, + 29142161, + 30520954, + ), + u32x8::new( + 57261330, + 6819646, + 22089161, + 9800373, + 55155453, + 62250856, + 13766735, + 25244545, + ), + u32x8::new( + 54370226, + 61888301, + 24496089, + 2540581, + 65637506, + 60274355, + 18154273, + 11687259, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 12521903, + 26014045, + 13995625, + 33360175, + 23605474, + 7376434, + 27229267, + 17195036, + ), + u32x8::new( + 59482891, + 10074423, + 574357, + 3857753, + 61377787, + 50306685, + 5241065, + 20234396, + ), + u32x8::new( + 23674717, + 6997172, + 20771841, + 16858511, + 40565304, + 29973136, + 7049812, + 14585010, + ), + u32x8::new( + 1427477, + 13295732, + 31762066, + 31499740, + 60419925, + 54666164, + 22009424, + 8089609, + ), + u32x8::new( + 58154031, + 41593020, + 15342328, + 957047, + 38937260, + 37037498, + 24871992, + 32973409, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 30654745, + 51286025, + 21206982, + 2433562, + 12780105, + 31732574, + 33087964, + 33081189, + ), + u32x8::new( + 66640017, + 42720009, + 16567620, + 15300745, + 1530367, + 33001123, + 20930247, + 21042661, + ), + u32x8::new( + 15003356, + 5294119, + 22985605, + 18928772, + 32628461, + 18230172, + 14773298, + 27193722, + ), + u32x8::new( + 27555, + 65346287, + 17017174, + 7837720, + 21499787, + 42855613, + 22474984, + 13675085, + ), + u32x8::new( + 24164369, + 50130116, + 5973149, + 24152073, + 1577334, + 25400030, + 18648484, + 32228854, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 49518649, + 59119280, + 31670678, + 20396561, + 61728330, + 651402, + 176032, + 9529498, + ), + u32x8::new( + 61765532, + 9082232, + 32794568, + 15526956, + 48543100, + 32614212, + 19001206, + 25680229, + ), + u32x8::new( + 32086091, + 10373081, + 8996131, + 31822823, + 35788988, + 49973190, + 30542040, + 17858455, + ), + u32x8::new( + 48130197, + 58121889, + 27753291, + 29923268, + 54448075, + 43300790, + 9336565, + 15770022, + ), + u32x8::new( + 57725546, + 20557498, + 9366233, + 16023566, + 16189031, + 2837363, + 24315301, + 27003505, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 28286608, + 10767548, + 18220739, + 5413236, + 48253387, + 58255702, + 11864864, + 28527159, + ), + u32x8::new( + 45038176, + 58655197, + 25648758, + 10951484, + 42564382, + 34542843, + 23146954, + 22234334, + ), + u32x8::new( + 14858710, + 24978793, + 15040559, + 4379220, + 47621477, + 40271440, + 15650420, + 1998736, + ), + u32x8::new( + 24106391, + 9626149, + 344505, + 25253814, + 34579800, + 59687089, + 25718289, + 25904133, + ), + u32x8::new( + 1981195, + 37751302, + 26132048, + 1764722, + 13288231, + 28808622, + 12531301, + 18292949, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 13869851, + 31448904, + 14963539, + 7581293, + 20536485, + 35021083, + 21257574, + 33356609, + ), + u32x8::new( + 36903364, + 18429241, + 11097857, + 5943856, + 60583077, + 40015815, + 30509523, + 31915271, + ), + u32x8::new( + 49161801, + 40681915, + 67892, + 25454357, + 22779677, + 25798439, + 15964829, + 5863227, + ), + u32x8::new( + 60810637, + 4496471, + 5217137, + 14095116, + 50942411, + 50712663, + 2507380, + 26844507, + ), + u32x8::new( + 34579752, + 53519385, + 10859797, + 18816024, + 42552864, + 39478521, + 6783896, + 17277037, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 43287109, + 27900723, + 33182187, + 2766754, + 17041989, + 1018260, + 33392790, + 4830032, + ), + u32x8::new( + 60194178, + 30788903, + 24728888, + 14513195, + 20897010, + 28843233, + 20111980, + 17475240, + ), + u32x8::new( + 46042274, + 19257042, + 4628173, + 31649727, + 27388316, + 66631493, + 11541886, + 6408028, + ), + u32x8::new( + 57024680, + 49536568, + 32050358, + 31321917, + 17437691, + 49672356, + 2884755, + 20493991, + ), + u32x8::new( + 59553007, + 46782643, + 29001173, + 1814088, + 21930692, + 51319706, + 14965872, + 30748046, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 16441817, + 36111849, + 6900424, + 602234, + 46522199, + 16441484, + 8135070, + 21726541, + ), + u32x8::new( + 37711225, + 32701959, + 11679112, + 13125533, + 32154135, + 9407918, + 26554289, + 620848, + ), + u32x8::new( + 19233407, + 30086864, + 14679568, + 2797374, + 4892806, + 7993077, + 247658, + 5632804, + ), + u32x8::new( + 37427262, + 26675495, + 27125659, + 13496131, + 50718473, + 40115609, + 28505351, + 27837393, + ), + u32x8::new( + 196819, + 18410429, + 7070012, + 21691388, + 29763371, + 24754123, + 9727048, + 10930179, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 28319289, + 40734650, + 16225680, + 24739184, + 64272368, + 35356897, + 7866648, + 13635853, + ), + u32x8::new( + 34165295, + 48328447, + 27041670, + 23643655, + 48949950, + 52963288, + 30411133, + 6045174, + ), + u32x8::new( + 18583559, + 41649834, + 9813585, + 26098520, + 25682734, + 26733526, + 19276490, + 10654728, + ), + u32x8::new( + 34867476, + 52715968, + 5694571, + 13380978, + 15134994, + 1831255, + 8608001, + 17266401, + ), + u32x8::new( + 59925903, + 44282172, + 27802465, + 1855069, + 14234749, + 36635487, + 11302294, + 10938429, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 8373273, + 49064494, + 4932071, + 32997499, + 38472880, + 29335908, + 14504412, + 22460029, + ), + u32x8::new( + 31795930, + 50785923, + 25835990, + 25790073, + 65669841, + 11360450, + 9969157, + 9008164, + ), + u32x8::new( + 50262498, + 45869261, + 16124434, + 15336007, + 882762, + 42522623, + 11277198, + 26296377, + ), + u32x8::new( + 42332732, + 59129236, + 14452816, + 567985, + 208061, + 34722729, + 32008143, + 14828749, + ), + u32x8::new( + 17937794, + 36846032, + 32102665, + 4442466, + 19745435, + 31633451, + 7146411, + 15812027, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 30741269, + 38648744, + 12562645, + 30092623, + 25073992, + 28730659, + 27911745, + 30000958, + ), + u32x8::new( + 2859794, + 25991700, + 17776078, + 27091930, + 2328322, + 60061146, + 18581824, + 18039008, + ), + u32x8::new( + 58206333, + 17917354, + 1972306, + 11853766, + 2655376, + 60543390, + 18416710, + 13287440, + ), + u32x8::new( + 62746330, + 61423885, + 21246577, + 2266675, + 60099139, + 14804707, + 14772234, + 20679434, + ), + u32x8::new( + 26987698, + 15488817, + 715616, + 2339565, + 51980752, + 17333865, + 21965103, + 10839820, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 18672548, + 57660959, + 16042910, + 19519287, + 62865851, + 17580961, + 26628347, + 23774759, + ), + u32x8::new( + 368070, + 3464471, + 25888304, + 30370559, + 52396053, + 45426828, + 28745251, + 9246829, + ), + u32x8::new( + 29090099, + 57950037, + 23104657, + 4903923, + 10987778, + 56163684, + 23621539, + 10332760, + ), + u32x8::new( + 53338235, + 44851161, + 21606845, + 31069622, + 4243630, + 34464392, + 11286454, + 5802022, + ), + u32x8::new( + 46710757, + 63389067, + 11642865, + 1980986, + 12967337, + 28162061, + 3854192, + 30432268, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 12179834, + 41005450, + 12809619, + 33525228, + 4624405, + 46957889, + 16968743, + 11827816, + ), + u32x8::new( + 51521162, + 12466775, + 31791271, + 15303651, + 49798465, + 62714504, + 6509600, + 12918560, + ), + u32x8::new( + 20445559, + 1756449, + 28848701, + 7920171, + 9835040, + 5900071, + 28757409, + 12376688, + ), + u32x8::new( + 18259496, + 14281012, + 21767026, + 10232236, + 20000226, + 12400540, + 4104902, + 23570543, + ), + u32x8::new( + 3687440, + 26546648, + 13328821, + 26841081, + 49822734, + 22334054, + 244496, + 24862543, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 59523541, + 62195428, + 3853227, + 13954801, + 12387708, + 47627615, + 27221350, + 17899572, + ), + u32x8::new( + 63193587, + 36343307, + 14595132, + 6880795, + 1364792, + 37648434, + 3259017, + 20536046, + ), + u32x8::new( + 30362834, + 10440372, + 9574624, + 11729232, + 63861613, + 21748389, + 5530846, + 2721586, + ), + u32x8::new( + 18339760, + 1550632, + 17170271, + 25732971, + 28459263, + 63142237, + 21642345, + 31557672, + ), + u32x8::new( + 10611282, + 5204623, + 18049257, + 214175, + 19432723, + 49809070, + 26010406, + 27449522, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 19770733, + 26478685, + 9464541, + 29158041, + 28604307, + 45196604, + 7586524, + 6641859, + ), + u32x8::new( + 65654484, + 52230498, + 30886612, + 19112823, + 47271809, + 38942611, + 16020035, + 10773481, + ), + u32x8::new( + 27464323, + 54451016, + 20646645, + 17732915, + 23008717, + 53626684, + 3253189, + 15614410, + ), + u32x8::new( + 52381752, + 40693008, + 7063024, + 28469981, + 51159478, + 44543211, + 19941777, + 5985451, + ), + u32x8::new( + 13553668, + 35524849, + 14788737, + 1883845, + 12385775, + 47958835, + 29135466, + 1776722, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 36719806, + 20827965, + 23175373, + 32996806, + 42041892, + 65708790, + 5467143, + 20884008, + ), + u32x8::new( + 43256281, + 40770646, + 17244063, + 31959819, + 64366384, + 43544617, + 25057754, + 12628720, + ), + u32x8::new( + 17337782, + 58472057, + 27906934, + 15305274, + 30292418, + 39284317, + 16946773, + 24806712, + ), + u32x8::new( + 6485126, + 32447403, + 16261486, + 13561940, + 49439635, + 10738368, + 16419889, + 8897231, + ), + u32x8::new( + 44812203, + 40122262, + 25496058, + 2759794, + 25295304, + 52178368, + 24154195, + 29334408, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 42307254, + 57217102, + 1088936, + 3832827, + 33905401, + 23130334, + 6958056, + 12622851, + ), + u32x8::new( + 3881189, + 14870059, + 19712830, + 6071598, + 38147944, + 60776394, + 3427938, + 13765703, + ), + u32x8::new( + 7666911, + 24227591, + 17077136, + 22967588, + 6874639, + 30915523, + 11451695, + 24292224, + ), + u32x8::new( + 13659529, + 31984463, + 28764736, + 20506164, + 64729627, + 49321636, + 28284636, + 25472371, + ), + u32x8::new( + 39360308, + 42281399, + 9446504, + 868960, + 49227724, + 21351115, + 30561851, + 11292096, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 7071115, + 46444090, + 5387916, + 15432877, + 27226682, + 41506862, + 2398278, + 3978240, + ), + u32x8::new( + 51009614, + 54216973, + 24368938, + 31392616, + 38456150, + 62313644, + 6729154, + 99724, + ), + u32x8::new( + 17474332, + 62857913, + 2619930, + 30659308, + 18268181, + 32809239, + 22826292, + 24561895, + ), + u32x8::new( + 38187020, + 67003092, + 14118280, + 16500577, + 18808560, + 64983716, + 25712929, + 32518261, + ), + u32x8::new( + 25735813, + 62284262, + 10824872, + 20558596, + 48149681, + 31162667, + 22608274, + 26285185, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 963440, + 63742255, + 10230323, + 25515008, + 32506414, + 6105697, + 25980317, + 24645129, + ), + u32x8::new( + 7162189, + 8101249, + 14679265, + 33443386, + 2002396, + 8541405, + 19442276, + 4795881, + ), + u32x8::new( + 8116694, + 51463069, + 4415528, + 25599140, + 55805721, + 39582709, + 6719436, + 30033839, + ), + u32x8::new( + 14468202, + 42181869, + 25188826, + 9639755, + 47546189, + 62711146, + 32762447, + 18338064, + ), + u32x8::new( + 33880058, + 32810909, + 8969931, + 13095238, + 38360605, + 40138517, + 9246134, + 4928058, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 63655588, + 17883670, + 9410246, + 26162761, + 5000571, + 7349225, + 23785252, + 32751089, + ), + u32x8::new( + 28568737, + 10733123, + 9342397, + 21570673, + 54096560, + 32467591, + 20494687, + 21511513, + ), + u32x8::new( + 47675157, + 47932807, + 29250946, + 15672208, + 59760469, + 9945465, + 14939287, + 18437405, + ), + u32x8::new( + 37985267, + 8609815, + 31573002, + 3373596, + 47828883, + 20834216, + 13248616, + 24154292, + ), + u32x8::new( + 5543543, + 29553242, + 3386453, + 30501150, + 25058089, + 15236571, + 8814395, + 32462955, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 39158670, + 15322548, + 20495103, + 3312736, + 14557171, + 12985179, + 8044741, + 3176899, + ), + u32x8::new( + 24673290, + 29693310, + 21412266, + 18324699, + 2154518, + 40329021, + 17500543, + 3954277, + ), + u32x8::new( + 36758685, + 38738957, + 165513, + 14691866, + 3070475, + 10424235, + 17096536, + 16896898, + ), + u32x8::new( + 59790459, + 43094586, + 8720681, + 10423589, + 1122030, + 31545615, + 4463786, + 31811293, + ), + u32x8::new( + 49778992, + 60881044, + 20509974, + 5832494, + 64155961, + 31483358, + 4511231, + 20307815, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 2863373, + 40876242, + 26865913, + 24067353, + 15726407, + 40919070, + 12953902, + 9931535, + ), + u32x8::new( + 60934877, + 42512204, + 21649141, + 21945190, + 52211954, + 60984193, + 7046207, + 5363493, + ), + u32x8::new( + 4205971, + 64068464, + 18197273, + 7327176, + 51527794, + 21166920, + 20669933, + 11828242, + ), + u32x8::new( + 59782815, + 49617225, + 15379924, + 457923, + 9320508, + 21498914, + 3242540, + 31563182, + ), + u32x8::new( + 27714753, + 8664670, + 3366162, + 26338598, + 56775518, + 25796006, + 13129151, + 21388876, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 59276548, + 49972346, + 16795002, + 33455915, + 48430097, + 53857205, + 18627071, + 32474471, + ), + u32x8::new( + 42160315, + 50705892, + 13530540, + 28012698, + 19833221, + 55886870, + 20191784, + 9644313, + ), + u32x8::new( + 20372416, + 28414713, + 24084234, + 31804096, + 33815377, + 36131001, + 17251241, + 18291088, + ), + u32x8::new( + 56234667, + 14920441, + 2033267, + 29572003, + 1724043, + 45519699, + 17873735, + 501988, + ), + u32x8::new( + 50031659, + 31517850, + 15697583, + 1016845, + 43104661, + 54769582, + 8008601, + 27257051, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 52951491, + 66542164, + 14853573, + 30444631, + 12045973, + 24321813, + 16545674, + 18160646, + ), + u32x8::new( + 60107911, + 1126003, + 5947677, + 19486116, + 41119984, + 30860440, + 7935395, + 13354438, + ), + u32x8::new( + 17841328, + 11063269, + 1664538, + 26687568, + 6268968, + 22280371, + 17275484, + 4523163, + ), + u32x8::new( + 15886041, + 56799482, + 15446552, + 21712778, + 1005290, + 17827215, + 4978741, + 6854882, + ), + u32x8::new( + 34319277, + 47731002, + 20321804, + 28544575, + 29591814, + 63376351, + 24754545, + 26001714, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 66783087, + 5234346, + 46102, + 8566476, + 19947339, + 20180418, + 25398238, + 3726678, + ), + u32x8::new( + 63890180, + 46380965, + 20674069, + 5366544, + 59661487, + 48406612, + 31533614, + 7071217, + ), + u32x8::new( + 13104676, + 1406631, + 24326736, + 19854367, + 61039528, + 11019904, + 31967425, + 19219275, + ), + u32x8::new( + 39003597, + 30143957, + 15351834, + 8639435, + 57309582, + 61436794, + 15830475, + 10090318, + ), + u32x8::new( + 45923044, + 6700175, + 99413, + 21263025, + 23762647, + 53905481, + 6063914, + 10065424, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 42822326, + 57678669, + 4052879, + 25452667, + 54049411, + 2373092, + 22337016, + 7701046, + ), + u32x8::new( + 44382355, + 43307377, + 16761537, + 30373573, + 49790216, + 23230748, + 25655306, + 10519391, + ), + u32x8::new( + 919475, + 59371245, + 1273450, + 25558666, + 9724711, + 8556709, + 25755845, + 10887647, + ), + u32x8::new( + 25465699, + 44651158, + 17658392, + 11257418, + 29735193, + 22885150, + 7094716, + 26828565, + ), + u32x8::new( + 48237389, + 47661599, + 27054393, + 7328070, + 27280193, + 65616691, + 23062005, + 4170709, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 26535281, + 60238317, + 30343788, + 25790743, + 37993933, + 24614372, + 9523840, + 10401918, + ), + u32x8::new( + 2783987, + 29468958, + 4697011, + 19804475, + 37246678, + 46797720, + 10261254, + 18942252, + ), + u32x8::new( + 58135580, + 60247753, + 25301938, + 6844561, + 20949454, + 39844754, + 4552026, + 919057, + ), + u32x8::new( + 6694071, + 44126261, + 32285330, + 31370180, + 24603698, + 53328179, + 13971149, + 5325636, + ), + u32x8::new( + 64879487, + 582094, + 17982081, + 19190425, + 24951286, + 26923842, + 29077174, + 33286062, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 54863941, + 67016431, + 1224043, + 23371240, + 62940074, + 52101083, + 13523637, + 30366406, + ), + u32x8::new( + 36324581, + 25407485, + 18258623, + 4698602, + 50300544, + 2658516, + 26300935, + 2611030, + ), + u32x8::new( + 27183975, + 21791014, + 18105064, + 9875199, + 58118912, + 54198635, + 6400311, + 14767984, + ), + u32x8::new( + 33918318, + 42937962, + 14809334, + 22136592, + 10636588, + 29082337, + 29829692, + 28549776, + ), + u32x8::new( + 61080905, + 854212, + 12202487, + 20004503, + 9256495, + 6903981, + 20567109, + 347423, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 41391822, + 34336880, + 22362564, + 14247996, + 12115604, + 41583344, + 7639288, + 28910945, + ), + u32x8::new( + 62066617, + 59758859, + 26665947, + 11614812, + 65737664, + 45704543, + 30324810, + 12868376, + ), + u32x8::new( + 17491771, + 43589814, + 9454919, + 26047850, + 52629282, + 39304244, + 3868968, + 19296062, + ), + u32x8::new( + 17826638, + 30413590, + 32534225, + 32741469, + 15012391, + 14365713, + 33039233, + 14791399, + ), + u32x8::new( + 64115596, + 59197067, + 32739005, + 23275744, + 32954320, + 22241406, + 20788442, + 4942942, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 31956192, + 59570132, + 2784352, + 4237732, + 47222312, + 4860927, + 18658867, + 15279314, + ), + u32x8::new( + 63240583, + 28160478, + 23524941, + 13390861, + 66437406, + 57718120, + 33345312, + 28896298, + ), + u32x8::new( + 39026193, + 46239965, + 21440243, + 25070488, + 64012383, + 60999016, + 16517060, + 29565907, + ), + u32x8::new( + 18118181, + 60161496, + 4212092, + 23976240, + 36277753, + 62363144, + 5816868, + 16964362, + ), + u32x8::new( + 18196138, + 62490693, + 281468, + 7934713, + 56027312, + 62015725, + 4837237, + 32932252, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 29885826, + 51028067, + 30418143, + 33438769, + 62542283, + 39442528, + 31535876, + 143299, + ), + u32x8::new( + 17143063, + 56709783, + 14451852, + 15782104, + 32762665, + 14047066, + 26295037, + 5432487, + ), + u32x8::new( + 75151, + 533606, + 7539077, + 30926189, + 38410914, + 23771680, + 4872443, + 29199566, + ), + u32x8::new( + 61522396, + 48934708, + 16223126, + 207380, + 11171993, + 47975147, + 14164574, + 352966, + ), + u32x8::new( + 15449006, + 56530757, + 26796528, + 12045834, + 63738697, + 40667227, + 33001582, + 9101885, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 43331297, + 18431341, + 25801195, + 17267698, + 19365485, + 57295202, + 22218985, + 21284590, + ), + u32x8::new( + 2429849, + 19152559, + 10762172, + 22564684, + 21880390, + 66866426, + 20357935, + 22641906, + ), + u32x8::new( + 19771185, + 31652693, + 3666117, + 28136958, + 23624283, + 55101502, + 6313920, + 6783662, + ), + u32x8::new( + 3487137, + 7092443, + 11001876, + 26196524, + 47319246, + 44542068, + 17594073, + 15027760, + ), + u32x8::new( + 49563607, + 32191113, + 4991283, + 25400512, + 46539152, + 4155103, + 32368171, + 201203, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 20548943, + 14334571, + 4073874, + 6368588, + 53208883, + 56484515, + 15970071, + 25561889, + ), + u32x8::new( + 49915097, + 44030795, + 11202344, + 29284344, + 60258023, + 66225712, + 8075764, + 12383512, + ), + u32x8::new( + 45248912, + 4933668, + 9592153, + 5819559, + 31030983, + 38174071, + 32435814, + 7442522, + ), + u32x8::new( + 62688129, + 48218381, + 22089545, + 12897361, + 21050881, + 34278889, + 7569163, + 3225449, + ), + u32x8::new( + 19050183, + 51089071, + 32935757, + 22640195, + 66122318, + 47144608, + 18743677, + 25177079, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 41186817, + 46681702, + 31819867, + 32997133, + 38559207, + 27147015, + 30293819, + 16762988, + ), + u32x8::new( + 24154689, + 51762873, + 23883879, + 13510519, + 55338250, + 61224161, + 11663149, + 30803960, + ), + u32x8::new( + 18104238, + 14117824, + 11724021, + 21362053, + 65704761, + 35530242, + 13498058, + 33522849, + ), + u32x8::new( + 63812888, + 23995539, + 28920539, + 24005193, + 26412223, + 36582218, + 4251418, + 26160309, + ), + u32x8::new( + 16822053, + 66064082, + 3482145, + 31979593, + 45937188, + 54475379, + 612917, + 7976478, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 46509314, + 55327128, + 8944536, + 274914, + 26432930, + 53829300, + 21192572, + 3569894, + ), + u32x8::new( + 20919764, + 64356651, + 30642344, + 17215170, + 20335124, + 11203745, + 18663316, + 19024174, + ), + u32x8::new( + 59297055, + 53842463, + 3680204, + 9806710, + 54004169, + 51484914, + 29807998, + 20134199, + ), + u32x8::new( + 14781592, + 22628010, + 26877930, + 25880359, + 30434803, + 190607, + 30184292, + 8991040, + ), + u32x8::new( + 64400983, + 64591751, + 854562, + 28216111, + 20010398, + 50414793, + 9803872, + 22687008, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 15091184, + 32550863, + 8818643, + 4244752, + 43123513, + 64565526, + 408838, + 13206998, + ), + u32x8::new( + 16405061, + 60379639, + 31489017, + 20949281, + 27568751, + 38734986, + 8364264, + 12451020, + ), + u32x8::new( + 16005217, + 58008076, + 1406778, + 26546927, + 39571784, + 56365493, + 31274296, + 8918790, + ), + u32x8::new( + 23271122, + 19453469, + 27718201, + 32742670, + 234332, + 36785342, + 22601675, + 14331046, + ), + u32x8::new( + 40636025, + 22442705, + 22115403, + 23745859, + 41164945, + 61012, + 12499614, + 542137, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 62776018, + 32835413, + 17373246, + 17187309, + 54469193, + 21770290, + 15923753, + 28996575, + ), + u32x8::new( + 59385210, + 63082298, + 12568449, + 8509004, + 9483342, + 16105238, + 5756054, + 26890758, + ), + u32x8::new( + 53987996, + 38201748, + 5521661, + 19060159, + 18663191, + 9093637, + 27786835, + 31189196, + ), + u32x8::new( + 65872678, + 43635130, + 27903055, + 25020300, + 65772737, + 38110437, + 5213502, + 21909342, + ), + u32x8::new( + 4438979, + 9680838, + 10212446, + 4764184, + 13235684, + 58245995, + 20264570, + 21024049, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 60835961, + 48209103, + 31049052, + 4688268, + 12426713, + 59829045, + 22302488, + 29008521, + ), + u32x8::new( + 50401667, + 29716596, + 23531224, + 7581281, + 49071895, + 6952617, + 14934683, + 8218256, + ), + u32x8::new( + 1601446, + 36631413, + 31774811, + 29625330, + 56786114, + 8331539, + 23129509, + 19783344, + ), + u32x8::new( + 59514327, + 64513110, + 1772300, + 5701338, + 5737511, + 16147555, + 9461515, + 5703271, + ), + u32x8::new( + 33072974, + 54300426, + 11940114, + 1308663, + 15627555, + 4931627, + 28443714, + 20924342, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 18135013, + 20358426, + 4922557, + 10015355, + 65729669, + 34786528, + 26248549, + 29194359, + ), + u32x8::new( + 797666, + 34997544, + 24316856, + 25107230, + 24612576, + 4761401, + 15307321, + 32404252, + ), + u32x8::new( + 16501152, + 60565831, + 9487105, + 9316022, + 24986054, + 31917592, + 3962024, + 2501883, + ), + u32x8::new( + 63356796, + 50432342, + 18044926, + 30566881, + 42032028, + 31415202, + 13524600, + 16119907, + ), + u32x8::new( + 3927286, + 57022374, + 9265437, + 21620772, + 19481940, + 3806938, + 24836192, + 14572399, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 10785787, + 46564798, + 368445, + 33181384, + 5319843, + 52687136, + 30347110, + 29837357, + ), + u32x8::new( + 56436732, + 47859251, + 24141084, + 22250712, + 59046084, + 4963427, + 33463413, + 17168859, + ), + u32x8::new( + 15512044, + 6366740, + 4737504, + 27644548, + 30307977, + 25037929, + 14593903, + 12836490, + ), + u32x8::new( + 63878897, + 34013023, + 5860752, + 7244096, + 3689461, + 57012135, + 18389096, + 11589351, + ), + u32x8::new( + 4682110, + 36302830, + 653422, + 22316819, + 14081831, + 5657024, + 11088376, + 24110612, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 39907267, + 45940262, + 24887471, + 18342609, + 878445, + 40456159, + 12019082, + 345107, + ), + u32x8::new( + 12794982, + 28893944, + 9447505, + 11387200, + 16961963, + 13916996, + 10893728, + 25898006, + ), + u32x8::new( + 44934162, + 53465865, + 3583620, + 1102334, + 53917811, + 63478576, + 2426066, + 10389549, + ), + u32x8::new( + 45096036, + 37595344, + 19367718, + 20257175, + 10280866, + 41653449, + 27665642, + 375926, + ), + u32x8::new( + 45847901, + 24064074, + 32494820, + 32204556, + 10720704, + 51079060, + 1297436, + 29853825, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 66303987, + 36060363, + 16494578, + 24962147, + 11971403, + 49538586, + 25060560, + 1964341, + ), + u32x8::new( + 25988481, + 27641502, + 24909517, + 27237087, + 66646363, + 52777626, + 16360849, + 10459972, + ), + u32x8::new( + 43930529, + 34374176, + 31225968, + 8807030, + 10394758, + 35904854, + 25325589, + 19335583, + ), + u32x8::new( + 25094697, + 34380951, + 20051185, + 32287161, + 11739332, + 53887441, + 30517319, + 26601892, + ), + u32x8::new( + 8868546, + 35635502, + 32513071, + 28248087, + 51946989, + 14222744, + 19198839, + 23261841, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 51218008, + 5070126, + 11046681, + 5320810, + 61212079, + 34104447, + 23895089, + 6460727, + ), + u32x8::new( + 39843528, + 46278671, + 10426120, + 25624792, + 66658766, + 37140083, + 28933107, + 12969597, + ), + u32x8::new( + 59635793, + 40220191, + 5751421, + 173680, + 58321825, + 740337, + 1412847, + 7682623, + ), + u32x8::new( + 975962, + 56440763, + 20812276, + 22631115, + 49095824, + 19883130, + 2419746, + 31043648, + ), + u32x8::new( + 66208703, + 39669328, + 22525915, + 3748897, + 65994776, + 34533552, + 8126286, + 18326047, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 64176557, + 3912400, + 19351673, + 30068471, + 31190055, + 24221683, + 33142424, + 28698542, + ), + u32x8::new( + 34784792, + 4109933, + 3867193, + 19557314, + 2112512, + 32715890, + 24550117, + 16595976, + ), + u32x8::new( + 35542761, + 48024875, + 10925431, + 31526577, + 66577735, + 23189821, + 13375709, + 1735095, + ), + u32x8::new( + 59699254, + 43854093, + 29783239, + 24777271, + 19600372, + 39924461, + 2896720, + 1472185, + ), + u32x8::new( + 56389656, + 35980854, + 33172342, + 1370336, + 23707480, + 57654949, + 7850973, + 12655016, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 38372660, + 57101970, + 7044964, + 12732710, + 57535705, + 6043201, + 30858914, + 10946592, + ), + u32x8::new( + 21023468, + 6946992, + 26403324, + 23901823, + 35695559, + 23440687, + 4763891, + 6514074, + ), + u32x8::new( + 28662273, + 30933699, + 9352242, + 26354829, + 37402243, + 3145176, + 8770289, + 525937, + ), + u32x8::new( + 54933102, + 36695832, + 3281859, + 4755022, + 23043294, + 32794379, + 15618886, + 23602412, + ), + u32x8::new( + 9931565, + 29897140, + 2480737, + 24193701, + 7833615, + 2284939, + 893926, + 13421882, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 22917795, + 22088359, + 28978099, + 19794863, + 60542318, + 29878494, + 31053731, + 9080720, + ), + u32x8::new( + 23679072, + 52547035, + 28424916, + 20647332, + 4008761, + 28267029, + 12961289, + 1589095, + ), + u32x8::new( + 55616194, + 26678929, + 14998265, + 23274397, + 54625466, + 46244264, + 28627706, + 33030665, + ), + u32x8::new( + 11527330, + 6449415, + 26531607, + 3472938, + 41541592, + 62607682, + 19862690, + 20564723, + ), + u32x8::new( + 32843805, + 49066843, + 28425824, + 19521495, + 48792073, + 48242878, + 27392443, + 13175986, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 16185025, + 61537525, + 2961305, + 1492442, + 25123147, + 3095034, + 31896958, + 33089615, + ), + u32x8::new( + 64748157, + 18336595, + 16522231, + 25426312, + 65718949, + 35485695, + 30554083, + 10205918, + ), + u32x8::new( + 39626934, + 39271045, + 16420458, + 9826240, + 56483981, + 27128085, + 3783403, + 13360006, + ), + u32x8::new( + 30793778, + 66771960, + 17241420, + 6564573, + 61102581, + 29974476, + 32385512, + 9011754, + ), + u32x8::new( + 28068166, + 11862220, + 14323567, + 12380617, + 52090465, + 16029056, + 24495309, + 21409233, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 59411973, + 57437124, + 11695483, + 17586857, + 16108987, + 43449109, + 31098002, + 6248476, + ), + u32x8::new( + 42258047, + 61595931, + 29308533, + 11742653, + 43042345, + 27373650, + 30165249, + 21929989, + ), + u32x8::new( + 49907221, + 9620337, + 21888081, + 20981082, + 56288861, + 61562203, + 33223566, + 3582446, + ), + u32x8::new( + 57535017, + 41003416, + 22080416, + 14463796, + 65518565, + 18127889, + 24370863, + 33332664, + ), + u32x8::new( + 66655380, + 6430175, + 471782, + 11947673, + 30596400, + 18898659, + 15930721, + 4211851, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 6757410, + 65455566, + 13584784, + 11362173, + 10797127, + 24451471, + 19541370, + 29309435, + ), + u32x8::new( + 40360156, + 17685025, + 18326181, + 3846903, + 13693365, + 63049479, + 31900359, + 23385063, + ), + u32x8::new( + 52455038, + 57513503, + 22163311, + 27095042, + 48610726, + 66454160, + 12085341, + 26357004, + ), + u32x8::new( + 22097042, + 14063840, + 6705778, + 14342902, + 66139825, + 20702105, + 31279090, + 7495745, + ), + u32x8::new( + 27360710, + 49314837, + 18774847, + 7146436, + 37066216, + 42004961, + 22409916, + 10524446, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 1497507, + 33054449, + 11839906, + 2960428, + 40538463, + 18884538, + 25018820, + 4073970, + ), + u32x8::new( + 54484385, + 43640735, + 2808257, + 20710708, + 39840730, + 27222424, + 21783544, + 11848522, + ), + u32x8::new( + 45765237, + 48200555, + 9299019, + 9393151, + 34818188, + 56098995, + 13575233, + 21012731, + ), + u32x8::new( + 4265428, + 49627650, + 24960282, + 9425650, + 47883651, + 2797524, + 11853190, + 22877329, + ), + u32x8::new( + 25008173, + 64199503, + 380047, + 12107343, + 12329448, + 11914399, + 764281, + 29687002, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new( + 35889734, + 23047226, + 4022841, + 7017445, + 7274086, + 53316179, + 25100176, + 15310676, + ), + u32x8::new( + 42409427, + 30270106, + 6823853, + 31551384, + 40645017, + 66489807, + 18021817, + 32669351, + ), + u32x8::new( + 39827134, + 43680850, + 28297996, + 20258133, + 26058742, + 52643238, + 22238331, + 21690533, + ), + u32x8::new( + 60808002, + 17499995, + 30042246, + 29310584, + 48219954, + 29389518, + 8680514, + 17844709, + ), + u32x8::new( + 6452896, + 50116553, + 9532047, + 26821214, + 44524351, + 50428429, + 21904953, + 12608048, + ), + ])), +]); diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/edwards.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/edwards.rs new file mode 100644 index 0000000..821d516 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/edwards.rs @@ -0,0 +1,545 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Parallel Edwards Arithmetic for Curve25519. +//! +//! This module currently has two point types: +//! +//! * `ExtendedPoint`: a point stored in vector-friendly format, with +//! vectorized doubling and addition; +//! +//! * `CachedPoint`: used for readdition. +//! +//! Details on the formulas can be found in the documentation for the +//! parent `avx2` module. +//! +//! This API is designed to be safe: vectorized points can only be +//! created from serial points (which do validation on decompression), +//! and operations on valid points return valid points, so invalid +//! point states should be unrepresentable. +//! +//! This design goal is met, with one exception: the `Neg` +//! implementation for the `CachedPoint` performs a lazy negation, so +//! that subtraction can be efficiently implemented as a negation and +//! an addition. Repeatedly negating a `CachedPoint` will cause its +//! coefficients to grow and eventually overflow. Repeatedly negating +//! a point should not be necessary anyways. + +#![allow(non_snake_case)] + +use core::convert::From; +use core::ops::{Add, Neg, Sub}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use edwards; +use window::{LookupTable, NafLookupTable5, NafLookupTable8}; + +use traits::Identity; + +use super::constants; +use super::field::{FieldElement2625x4, Lanes, Shuffle}; + +/// A point on Curve25519, using parallel Edwards formulas for curve +/// operations. +/// +/// # Invariant +/// +/// The coefficients of an `ExtendedPoint` are bounded with +/// \\( b < 0.007 \\). +#[derive(Copy, Clone, Debug)] +pub struct ExtendedPoint(pub(super) FieldElement2625x4); + +impl From for ExtendedPoint { + fn from(P: edwards::EdwardsPoint) -> ExtendedPoint { + ExtendedPoint(FieldElement2625x4::new(&P.X, &P.Y, &P.Z, &P.T)) + } +} + +impl From for edwards::EdwardsPoint { + fn from(P: ExtendedPoint) -> edwards::EdwardsPoint { + let tmp = P.0.split(); + edwards::EdwardsPoint { + X: tmp[0], + Y: tmp[1], + Z: tmp[2], + T: tmp[3], + } + } +} + +impl ConditionallySelectable for ExtendedPoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + ExtendedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice)) + } + + fn conditional_assign(&mut self, other: &Self, choice: Choice) { + self.0.conditional_assign(&other.0, choice); + } +} + +impl Default for ExtendedPoint { + fn default() -> ExtendedPoint { + ExtendedPoint::identity() + } +} + +impl Identity for ExtendedPoint { + fn identity() -> ExtendedPoint { + constants::EXTENDEDPOINT_IDENTITY + } +} + +impl ExtendedPoint { + /// Compute the double of this point. + pub fn double(&self) -> ExtendedPoint { + // Want to compute (X1 Y1 Z1 X1+Y1). + // Not sure how to do this less expensively than computing + // (X1 Y1 Z1 T1) --(256bit shuffle)--> (X1 Y1 X1 Y1) + // (X1 Y1 X1 Y1) --(2x128b shuffle)--> (Y1 X1 Y1 X1) + // and then adding. + + // Set tmp0 = (X1 Y1 X1 Y1) + let mut tmp0 = self.0.shuffle(Shuffle::ABAB); + + // Set tmp1 = (Y1 X1 Y1 X1) + let mut tmp1 = tmp0.shuffle(Shuffle::BADC); + + // Set tmp0 = (X1 Y1 Z1 X1+Y1) + tmp0 = self.0.blend(tmp0 + tmp1, Lanes::D); + + // Set tmp1 = tmp0^2, negating the D values + tmp1 = tmp0.square_and_negate_D(); + // Now tmp1 = (S1 S2 S3 -S4) with b < 0.007 + + // See discussion of bounds in the module-level documentation. + // We want to compute + // + // + | S1 | S1 | S1 | S1 | + // + | S2 | | | S2 | + // + | | | S3 | | + // + | | | S3 | | + // + | | | |-S4 | + // + | | 2p | 2p | | + // - | | S2 | S2 | | + // ======================= + // S5 S6 S8 S9 + + let zero = FieldElement2625x4::zero(); + let S_1 = tmp1.shuffle(Shuffle::AAAA); + let S_2 = tmp1.shuffle(Shuffle::BBBB); + + tmp0 = zero.blend(tmp1 + tmp1, Lanes::C); + // tmp0 = (0, 0, 2S_3, 0) + tmp0 = tmp0.blend(tmp1, Lanes::D); + // tmp0 = (0, 0, 2S_3, -S_4) + tmp0 = tmp0 + S_1; + // tmp0 = ( S_1, S_1, S_1 + 2S_3, S_1 - S_4) + tmp0 = tmp0 + zero.blend(S_2, Lanes::AD); + // tmp0 = (S_1 + S_2, S_1, S_1 + 2S_3, S_1 + S_2 - S_4) + tmp0 = tmp0 + zero.blend(S_2.negate_lazy(), Lanes::BC); + // tmp0 = (S_1 + S_2, S_1 - S_2, S_1 - S_2 + 2S_3, S_1 + S_2 - S_4) + // b < ( 1.01, 1.6, 2.33, 1.6) + // Now tmp0 = (S_5, S_6, S_8, S_9) + + // Set tmp1 = ( S_9, S_6, S_6, S_9) + // b < ( 1.6, 1.6, 1.6, 1.6) + tmp1 = tmp0.shuffle(Shuffle::DBBD); + // Set tmp0 = ( S_8, S_5, S_8, S_5) + // b < (2.33, 1.01, 2.33, 1.01) + tmp0 = tmp0.shuffle(Shuffle::CACA); + + // Bounds on (tmp0, tmp1) are (2.33, 1.6) < (2.5, 1.75). + ExtendedPoint(&tmp0 * &tmp1) + } + + pub fn mul_by_pow_2(&self, k: u32) -> ExtendedPoint { + let mut tmp: ExtendedPoint = *self; + for _ in 0..k { + tmp = tmp.double(); + } + tmp + } +} + +/// A cached point with some precomputed variables used for readdition. +/// +/// # Warning +/// +/// It is not safe to negate this point more than once. +/// +/// # Invariant +/// +/// As long as the `CachedPoint` is not repeatedly negated, its +/// coefficients will be bounded with \\( b < 1.0 \\). +#[derive(Copy, Clone, Debug)] +pub struct CachedPoint(pub(super) FieldElement2625x4); + +impl From for CachedPoint { + fn from(P: ExtendedPoint) -> CachedPoint { + let mut x = P.0; + + x = x.blend(x.diff_sum(), Lanes::AB); + // x = (Y2 - X2, Y2 + X2, Z2, T2) = (S2 S3 Z2 T2) + + x = x * (121666, 121666, 2 * 121666, 2 * 121665); + // x = (121666*S2 121666*S3 2*121666*Z2 2*121665*T2) + + x = x.blend(-x, Lanes::D); + // x = (121666*S2 121666*S3 2*121666*Z2 -2*121665*T2) + + // The coefficients of the output are bounded with b < 0.007. + CachedPoint(x) + } +} + +impl Default for CachedPoint { + fn default() -> CachedPoint { + CachedPoint::identity() + } +} + +impl Identity for CachedPoint { + fn identity() -> CachedPoint { + constants::CACHEDPOINT_IDENTITY + } +} + +impl ConditionallySelectable for CachedPoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + CachedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice)) + } + + fn conditional_assign(&mut self, other: &Self, choice: Choice) { + self.0.conditional_assign(&other.0, choice); + } +} + +impl<'a> Neg for &'a CachedPoint { + type Output = CachedPoint; + /// Lazily negate the point. + /// + /// # Warning + /// + /// Because this method does not perform a reduction, it is not + /// safe to repeatedly negate a point. + fn neg(self) -> CachedPoint { + let swapped = self.0.shuffle(Shuffle::BACD); + CachedPoint(swapped.blend(swapped.negate_lazy(), Lanes::D)) + } +} + +impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { + type Output = ExtendedPoint; + + /// Add an `ExtendedPoint` and a `CachedPoint`. + fn add(self, other: &'b CachedPoint) -> ExtendedPoint { + // The coefficients of an `ExtendedPoint` are reduced after + // every operation. If the `CachedPoint` was negated, its + // coefficients grow by one bit. So on input, `self` is + // bounded with `b < 0.007` and `other` is bounded with + // `b < 1.0`. + + let mut tmp = self.0; + + tmp = tmp.blend(tmp.diff_sum(), Lanes::AB); + // tmp = (Y1-X1 Y1+X1 Z1 T1) = (S0 S1 Z1 T1) with b < 1.6 + + // (tmp, other) bounded with b < (1.6, 1.0) < (2.5, 1.75). + tmp = &tmp * &other.0; + // tmp = (S0*S2' S1*S3' Z1*Z2' T1*T2') = (S8 S9 S10 S11) + + tmp = tmp.shuffle(Shuffle::ABDC); + // tmp = (S8 S9 S11 S10) + + tmp = tmp.diff_sum(); + // tmp = (S9-S8 S9+S8 S10-S11 S10+S11) = (S12 S13 S14 S15) + + let t0 = tmp.shuffle(Shuffle::ADDA); + // t0 = (S12 S15 S15 S12) + let t1 = tmp.shuffle(Shuffle::CBCB); + // t1 = (S14 S13 S14 S13) + + // All coefficients of t0, t1 are bounded with b < 1.6. + // Return (S12*S14 S15*S13 S15*S14 S12*S13) = (X3 Y3 Z3 T3) + ExtendedPoint(&t0 * &t1) + } +} + +impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { + type Output = ExtendedPoint; + + /// Implement subtraction by negating the point and adding. + /// + /// Empirically, this seems about the same cost as a custom + /// subtraction impl (maybe because the benefit is cancelled by + /// increased code size?) + fn sub(self, other: &'b CachedPoint) -> ExtendedPoint { + self + &(-other) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let P = ExtendedPoint::from(*point); + let mut points = [CachedPoint::from(P); 8]; + for i in 0..7 { + points[i + 1] = (&P + &points[i]).into(); + } + LookupTable(points) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let A = ExtendedPoint::from(*point); + let mut Ai = [CachedPoint::from(A); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).into(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + NafLookupTable5(Ai) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let A = ExtendedPoint::from(*point); + let mut Ai = [CachedPoint::from(A); 64]; + let A2 = A.double(); + for i in 0..63 { + Ai[i + 1] = (&A2 + &Ai[i]).into(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] + NafLookupTable8(Ai) + } +} + +#[cfg(test)] +mod test { + use super::*; + + fn serial_add(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) -> edwards::EdwardsPoint { + use backend::serial::u64::field::FieldElement51; + + let (X1, Y1, Z1, T1) = (P.X, P.Y, P.Z, P.T); + let (X2, Y2, Z2, T2) = (Q.X, Q.Y, Q.Z, Q.T); + + macro_rules! print_var { + ($x:ident) => { + println!("{} = {:?}", stringify!($x), $x.to_bytes()); + }; + } + + let S0 = &Y1 - &X1; // R1 + let S1 = &Y1 + &X1; // R3 + let S2 = &Y2 - &X2; // R2 + let S3 = &Y2 + &X2; // R4 + print_var!(S0); + print_var!(S1); + print_var!(S2); + print_var!(S3); + println!(""); + + let S4 = &S0 * &S2; // R5 = R1 * R2 + let S5 = &S1 * &S3; // R6 = R3 * R4 + let S6 = &Z1 * &Z2; // R8 + let S7 = &T1 * &T2; // R7 + print_var!(S4); + print_var!(S5); + print_var!(S6); + print_var!(S7); + println!(""); + + let S8 = &S4 * &FieldElement51([ 121666,0,0,0,0]); // R5 + let S9 = &S5 * &FieldElement51([ 121666,0,0,0,0]); // R6 + let S10 = &S6 * &FieldElement51([2*121666,0,0,0,0]); // R8 + let S11 = &S7 * &(-&FieldElement51([2*121665,0,0,0,0])); // R7 + print_var!(S8); + print_var!(S9); + print_var!(S10); + print_var!(S11); + println!(""); + + let S12 = &S9 - &S8; // R1 + let S13 = &S9 + &S8; // R4 + let S14 = &S10 - &S11; // R2 + let S15 = &S10 + &S11; // R3 + print_var!(S12); + print_var!(S13); + print_var!(S14); + print_var!(S15); + println!(""); + + let X3 = &S12 * &S14; // R1 * R2 + let Y3 = &S15 * &S13; // R3 * R4 + let Z3 = &S15 * &S14; // R2 * R3 + let T3 = &S12 * &S13; // R1 * R4 + + edwards::EdwardsPoint { + X: X3, + Y: Y3, + Z: Z3, + T: T3, + } + } + + fn addition_test_helper(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) { + // Test the serial implementation of the parallel addition formulas + let R_serial: edwards::EdwardsPoint = serial_add(P.into(), Q.into()).into(); + + // Test the vector implementation of the parallel readdition formulas + let cached_Q = CachedPoint::from(ExtendedPoint::from(Q)); + let R_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) + &cached_Q).into(); + let S_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) - &cached_Q).into(); + + println!("Testing point addition:"); + println!("P = {:?}", P); + println!("Q = {:?}", Q); + println!("cached Q = {:?}", cached_Q); + println!("R = P + Q = {:?}", &P + &Q); + println!("R_serial = {:?}", R_serial); + println!("R_vector = {:?}", R_vector); + println!("S = P - Q = {:?}", &P - &Q); + println!("S_vector = {:?}", S_vector); + assert_eq!(R_serial.compress(), (&P + &Q).compress()); + assert_eq!(R_vector.compress(), (&P + &Q).compress()); + assert_eq!(S_vector.compress(), (&P - &Q).compress()); + println!("OK!\n"); + } + + #[test] + fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() { + use constants; + use scalar::Scalar; + + println!("Testing id +- id"); + let P = edwards::EdwardsPoint::identity(); + let Q = edwards::EdwardsPoint::identity(); + addition_test_helper(P, Q); + + println!("Testing id +- B"); + let P = edwards::EdwardsPoint::identity(); + let Q = constants::ED25519_BASEPOINT_POINT; + addition_test_helper(P, Q); + + println!("Testing B +- B"); + let P = constants::ED25519_BASEPOINT_POINT; + let Q = constants::ED25519_BASEPOINT_POINT; + addition_test_helper(P, Q); + + println!("Testing B +- kB"); + let P = constants::ED25519_BASEPOINT_POINT; + let Q = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + addition_test_helper(P, Q); + } + + fn serial_double(P: edwards::EdwardsPoint) -> edwards::EdwardsPoint { + let (X1, Y1, Z1, _T1) = (P.X, P.Y, P.Z, P.T); + + macro_rules! print_var { + ($x:ident) => { + println!("{} = {:?}", stringify!($x), $x.to_bytes()); + }; + } + + let S0 = &X1 + &Y1; // R1 + print_var!(S0); + println!(""); + + let S1 = X1.square(); + let S2 = Y1.square(); + let S3 = Z1.square(); + let S4 = S0.square(); + print_var!(S1); + print_var!(S2); + print_var!(S3); + print_var!(S4); + println!(""); + + let S5 = &S1 + &S2; + let S6 = &S1 - &S2; + let S7 = &S3 + &S3; + let S8 = &S7 + &S6; + let S9 = &S5 - &S4; + print_var!(S5); + print_var!(S6); + print_var!(S7); + print_var!(S8); + print_var!(S9); + println!(""); + + let X3 = &S8 * &S9; + let Y3 = &S5 * &S6; + let Z3 = &S8 * &S6; + let T3 = &S5 * &S9; + + edwards::EdwardsPoint { + X: X3, + Y: Y3, + Z: Z3, + T: T3, + } + } + + fn doubling_test_helper(P: edwards::EdwardsPoint) { + let R1: edwards::EdwardsPoint = serial_double(P.into()).into(); + let R2: edwards::EdwardsPoint = ExtendedPoint::from(P).double().into(); + println!("Testing point doubling:"); + println!("P = {:?}", P); + println!("(serial) R1 = {:?}", R1); + println!("(vector) R2 = {:?}", R2); + println!("P + P = {:?}", &P + &P); + assert_eq!(R1.compress(), (&P + &P).compress()); + assert_eq!(R2.compress(), (&P + &P).compress()); + println!("OK!\n"); + } + + #[test] + fn vector_doubling_vs_serial_doubling_vs_edwards_extendedpoint() { + use constants; + use scalar::Scalar; + + println!("Testing [2]id"); + let P = edwards::EdwardsPoint::identity(); + doubling_test_helper(P); + + println!("Testing [2]B"); + let P = constants::ED25519_BASEPOINT_POINT; + doubling_test_helper(P); + + println!("Testing [2]([k]B)"); + let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + doubling_test_helper(P); + } + + #[test] + fn basepoint_odd_lookup_table_verify() { + use constants; + use backend::vector::avx2::constants::{BASEPOINT_ODD_LOOKUP_TABLE}; + + let basepoint_odd_table = NafLookupTable8::::from(&constants::ED25519_BASEPOINT_POINT); + println!("basepoint_odd_lookup_table = {:?}", basepoint_odd_table); + + let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; + for (b_vec, base_vec) in table_B.0.iter().zip(basepoint_odd_table.0.iter()) { + let b_splits = b_vec.0.split(); + let base_splits = base_vec.0.split(); + + assert_eq!(base_splits[0], b_splits[0]); + assert_eq!(base_splits[1], b_splits[1]); + assert_eq!(base_splits[2], b_splits[2]); + assert_eq!(base_splits[3], b_splits[3]); + } + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/field.rs new file mode 100644 index 0000000..94a06ee --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/field.rs @@ -0,0 +1,986 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! An implementation of 4-way vectorized 32bit field arithmetic using +//! AVX2. +//! +//! The `FieldElement2625x4` struct provides a vector of four field +//! elements, implemented using AVX2 operations. Its API is designed +//! to abstract away the platform-dependent details, so that point +//! arithmetic can be implemented only in terms of a vector of field +//! elements. +//! +//! At this level, the API is optimized for speed and not safety. The +//! `FieldElement2625x4` does not always perform reductions. The pre- +//! and post-conditions on the bounds of the coefficients are +//! documented for each method, but it is the caller's responsibility +//! to ensure that there are no overflows. + +#![allow(non_snake_case)] + +const A_LANES: u8 = 0b0000_0101; +const B_LANES: u8 = 0b0000_1010; +const C_LANES: u8 = 0b0101_0000; +const D_LANES: u8 = 0b1010_0000; + +#[allow(unused)] +const A_LANES64: u8 = 0b00_00_00_11; +#[allow(unused)] +const B_LANES64: u8 = 0b00_00_11_00; +#[allow(unused)] +const C_LANES64: u8 = 0b00_11_00_00; +#[allow(unused)] +const D_LANES64: u8 = 0b11_00_00_00; + +use core::ops::{Add, Mul, Neg}; +use packed_simd::{i32x8, u32x8, u64x4, IntoBits}; + +use backend::vector::avx2::constants::{P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO}; +use backend::serial::u64::field::FieldElement51; + +/// Unpack 32-bit lanes into 64-bit lanes: +/// ```ascii,no_run +/// (a0, b0, a1, b1, c0, d0, c1, d1) +/// ``` +/// into +/// ```ascii,no_run +/// (a0, 0, b0, 0, c0, 0, d0, 0) +/// (a1, 0, b1, 0, c1, 0, d1, 0) +/// ``` +#[inline(always)] +fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { + let a: u32x8; + let b: u32x8; + let zero = i32x8::new(0, 0, 0, 0, 0, 0, 0, 0); + unsafe { + use core::arch::x86_64::_mm256_unpackhi_epi32; + use core::arch::x86_64::_mm256_unpacklo_epi32; + a = _mm256_unpacklo_epi32(src.into_bits(), zero.into_bits()).into_bits(); + b = _mm256_unpackhi_epi32(src.into_bits(), zero.into_bits()).into_bits(); + } + (a, b) +} + +/// Repack 64-bit lanes into 32-bit lanes: +/// ```ascii,no_run +/// (a0, 0, b0, 0, c0, 0, d0, 0) +/// (a1, 0, b1, 0, c1, 0, d1, 0) +/// ``` +/// into +/// ```ascii,no_run +/// (a0, b0, a1, b1, c0, d0, c1, d1) +/// ``` +#[inline(always)] +fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { + unsafe { + use core::arch::x86_64::_mm256_blend_epi32; + use core::arch::x86_64::_mm256_shuffle_epi32; + + // Input: x = (a0, 0, b0, 0, c0, 0, d0, 0) + // Input: y = (a1, 0, b1, 0, c1, 0, d1, 0) + + let x_shuffled = _mm256_shuffle_epi32(x.into_bits(), 0b11_01_10_00); + let y_shuffled = _mm256_shuffle_epi32(y.into_bits(), 0b10_00_11_01); + + // x' = (a0, b0, 0, 0, c0, d0, 0, 0) + // y' = ( 0, 0, a1, b1, 0, 0, c1, d1) + + return _mm256_blend_epi32(x_shuffled, y_shuffled, 0b11001100).into_bits(); + } +} + +/// The `Lanes` enum represents a subset of the lanes `A,B,C,D` of a +/// `FieldElement2625x4`. +/// +/// It's used to specify blend operations without +/// having to know details about the data layout of the +/// `FieldElement2625x4`. +#[derive(Copy, Clone, Debug)] +pub enum Lanes { + C, + D, + AB, + AC, + CD, + AD, + BC, + ABCD, +} + +/// The `Shuffle` enum represents a shuffle of a `FieldElement2625x4`. +/// +/// The enum variants are named by what they do to a vector \\( +/// (A,B,C,D) \\); for instance, `Shuffle::BADC` turns \\( (A, B, C, +/// D) \\) into \\( (B, A, D, C) \\). +#[derive(Copy, Clone, Debug)] +pub enum Shuffle { + AAAA, + BBBB, + CACA, + DBBD, + ADDA, + CBCB, + ABAB, + BADC, + BACD, + ABDC, +} + +/// A vector of four field elements. +/// +/// Each operation on a `FieldElement2625x4` has documented effects on +/// the bounds of the coefficients. This API is designed for speed +/// and not safety; it is the caller's responsibility to ensure that +/// the post-conditions of one operation are compatible with the +/// pre-conditions of the next. +#[derive(Clone, Copy, Debug)] +pub struct FieldElement2625x4(pub(crate) [u32x8; 5]); + +use subtle::Choice; +use subtle::ConditionallySelectable; + +impl ConditionallySelectable for FieldElement2625x4 { + fn conditional_select( + a: &FieldElement2625x4, + b: &FieldElement2625x4, + choice: Choice, + ) -> FieldElement2625x4 { + let mask = (-(choice.unwrap_u8() as i32)) as u32; + let mask_vec = u32x8::splat(mask); + FieldElement2625x4([ + a.0[0] ^ (mask_vec & (a.0[0] ^ b.0[0])), + a.0[1] ^ (mask_vec & (a.0[1] ^ b.0[1])), + a.0[2] ^ (mask_vec & (a.0[2] ^ b.0[2])), + a.0[3] ^ (mask_vec & (a.0[3] ^ b.0[3])), + a.0[4] ^ (mask_vec & (a.0[4] ^ b.0[4])), + ]) + } + + fn conditional_assign( + &mut self, + other: &FieldElement2625x4, + choice: Choice, + ) { + let mask = (-(choice.unwrap_u8() as i32)) as u32; + let mask_vec = u32x8::splat(mask); + self.0[0] ^= mask_vec & (self.0[0] ^ other.0[0]); + self.0[1] ^= mask_vec & (self.0[1] ^ other.0[1]); + self.0[2] ^= mask_vec & (self.0[2] ^ other.0[2]); + self.0[3] ^= mask_vec & (self.0[3] ^ other.0[3]); + self.0[4] ^= mask_vec & (self.0[4] ^ other.0[4]); + } +} + +impl FieldElement2625x4 { + /// Split this vector into an array of four (serial) field + /// elements. + pub fn split(&self) -> [FieldElement51; 4] { + let mut out = [FieldElement51::zero(); 4]; + for i in 0..5 { + let a_2i = self.0[i].extract(0) as u64; // + let b_2i = self.0[i].extract(1) as u64; // + let a_2i_1 = self.0[i].extract(2) as u64; // `. + let b_2i_1 = self.0[i].extract(3) as u64; // | pre-swapped to avoid + let c_2i = self.0[i].extract(4) as u64; // | a cross lane shuffle + let d_2i = self.0[i].extract(5) as u64; // .' + let c_2i_1 = self.0[i].extract(6) as u64; // + let d_2i_1 = self.0[i].extract(7) as u64; // + + out[0].0[i] = a_2i + (a_2i_1 << 26); + out[1].0[i] = b_2i + (b_2i_1 << 26); + out[2].0[i] = c_2i + (c_2i_1 << 26); + out[3].0[i] = d_2i + (d_2i_1 << 26); + } + + out + } + + /// Rearrange the elements of this vector according to `control`. + /// + /// The `control` parameter should be a compile-time constant, so + /// that when this function is inlined, LLVM is able to lower the + /// shuffle using an immediate. + #[inline] + pub fn shuffle(&self, control: Shuffle) -> FieldElement2625x4 { + #[inline(always)] + fn shuffle_lanes(x: u32x8, control: Shuffle) -> u32x8 { + unsafe { + use core::arch::x86_64::_mm256_permutevar8x32_epi32; + + let c: u32x8 = match control { + Shuffle::AAAA => u32x8::new(0, 0, 2, 2, 0, 0, 2, 2), + Shuffle::BBBB => u32x8::new(1, 1, 3, 3, 1, 1, 3, 3), + Shuffle::CACA => u32x8::new(4, 0, 6, 2, 4, 0, 6, 2), + Shuffle::DBBD => u32x8::new(5, 1, 7, 3, 1, 5, 3, 7), + Shuffle::ADDA => u32x8::new(0, 5, 2, 7, 5, 0, 7, 2), + Shuffle::CBCB => u32x8::new(4, 1, 6, 3, 4, 1, 6, 3), + Shuffle::ABAB => u32x8::new(0, 1, 2, 3, 0, 1, 2, 3), + Shuffle::BADC => u32x8::new(1, 0, 3, 2, 5, 4, 7, 6), + Shuffle::BACD => u32x8::new(1, 0, 3, 2, 4, 5, 6, 7), + Shuffle::ABDC => u32x8::new(0, 1, 2, 3, 5, 4, 7, 6), + }; + // Note that this gets turned into a generic LLVM + // shuffle-by-constants, which can be lowered to a simpler + // instruction than a generic permute. + _mm256_permutevar8x32_epi32(x.into_bits(), c.into_bits()).into_bits() + } + } + + FieldElement2625x4([ + shuffle_lanes(self.0[0], control), + shuffle_lanes(self.0[1], control), + shuffle_lanes(self.0[2], control), + shuffle_lanes(self.0[3], control), + shuffle_lanes(self.0[4], control), + ]) + } + + /// Blend `self` with `other`, taking lanes specified in `control` from `other`. + /// + /// The `control` parameter should be a compile-time constant, so + /// that this function can be inlined and LLVM can lower it to a + /// blend instruction using an immediate. + #[inline] + pub fn blend(&self, other: FieldElement2625x4, control: Lanes) -> FieldElement2625x4 { + #[inline(always)] + fn blend_lanes(x: u32x8, y: u32x8, control: Lanes) -> u32x8 { + unsafe { + use core::arch::x86_64::_mm256_blend_epi32; + + // This would be much cleaner if we could factor out the match + // statement on the control. Unfortunately, rustc forgets + // constant-info very quickly, so we can't even write + // ``` + // match control { + // Lanes::C => { + // let imm = C_LANES as i32; + // _mm256_blend_epi32(..., imm) + // ``` + // let alone + // ``` + // let imm = match control { + // Lanes::C => C_LANES as i32, + // } + // _mm256_blend_epi32(..., imm) + // ``` + // even though both of these would be constant-folded by LLVM + // at a lower level (as happens in the shuffle implementation, + // which does not require a shuffle immediate but *is* lowered + // to immediate shuffles anyways). + match control { + Lanes::C => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), C_LANES as i32).into_bits() + } + Lanes::D => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), D_LANES as i32).into_bits() + } + Lanes::AD => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | D_LANES) as i32) + .into_bits() + } + Lanes::AB => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | B_LANES) as i32) + .into_bits() + } + Lanes::AC => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | C_LANES) as i32) + .into_bits() + } + Lanes::CD => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), (C_LANES | D_LANES) as i32) + .into_bits() + } + Lanes::BC => { + _mm256_blend_epi32(x.into_bits(), y.into_bits(), (B_LANES | C_LANES) as i32) + .into_bits() + } + Lanes::ABCD => _mm256_blend_epi32( + x.into_bits(), + y.into_bits(), + (A_LANES | B_LANES | C_LANES | D_LANES) as i32, + ).into_bits(), + } + } + } + + FieldElement2625x4([ + blend_lanes(self.0[0], other.0[0], control), + blend_lanes(self.0[1], other.0[1], control), + blend_lanes(self.0[2], other.0[2], control), + blend_lanes(self.0[3], other.0[3], control), + blend_lanes(self.0[4], other.0[4], control), + ]) + } + + /// Construct a vector of zeros. + pub fn zero() -> FieldElement2625x4 { + FieldElement2625x4([u32x8::splat(0); 5]) + } + + /// Convenience wrapper around `new(x,x,x,x)`. + pub fn splat(x: &FieldElement51) -> FieldElement2625x4 { + FieldElement2625x4::new(x, x, x, x) + } + + /// Create a `FieldElement2625x4` from four `FieldElement51`s. + /// + /// # Postconditions + /// + /// The resulting `FieldElement2625x4` is bounded with \\( b < 0.0002 \\). + pub fn new( + x0: &FieldElement51, + x1: &FieldElement51, + x2: &FieldElement51, + x3: &FieldElement51, + ) -> FieldElement2625x4 { + let mut buf = [u32x8::splat(0); 5]; + let low_26_bits = (1 << 26) - 1; + for i in 0..5 { + let a_2i = (x0.0[i] & low_26_bits) as u32; + let a_2i_1 = (x0.0[i] >> 26) as u32; + let b_2i = (x1.0[i] & low_26_bits) as u32; + let b_2i_1 = (x1.0[i] >> 26) as u32; + let c_2i = (x2.0[i] & low_26_bits) as u32; + let c_2i_1 = (x2.0[i] >> 26) as u32; + let d_2i = (x3.0[i] & low_26_bits) as u32; + let d_2i_1 = (x3.0[i] >> 26) as u32; + + buf[i] = u32x8::new(a_2i, b_2i, a_2i_1, b_2i_1, c_2i, d_2i, c_2i_1, d_2i_1); + } + + // We don't know that the original `FieldElement51`s were + // fully reduced, so the odd limbs may exceed 2^25. + // Reduce them to be sure. + FieldElement2625x4(buf).reduce() + } + + /// Given \\((A,B,C,D)\\), compute \\((-A,-B,-C,-D)\\), without + /// performing a reduction. + /// + /// # Preconditions + /// + /// The coefficients of `self` must be bounded with \\( b < 0.999 \\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 1 \\). + #[inline] + pub fn negate_lazy(&self) -> FieldElement2625x4 { + // The limbs of self are bounded with b < 0.999, while the + // smallest limb of 2*p is 67108845 > 2^{26+0.9999}, so + // underflows are not possible. + FieldElement2625x4([ + P_TIMES_2_LO - self.0[0], + P_TIMES_2_HI - self.0[1], + P_TIMES_2_HI - self.0[2], + P_TIMES_2_HI - self.0[3], + P_TIMES_2_HI - self.0[4], + ]) + } + + /// Given `self = (A,B,C,D)`, compute `(B - A, B + A, D - C, D + C)`. + /// + /// # Preconditions + /// + /// The coefficients of `self` must be bounded with \\( b < 0.01 \\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 1.6 \\). + #[inline] + pub fn diff_sum(&self) -> FieldElement2625x4 { + // tmp1 = (B, A, D, C) + let tmp1 = self.shuffle(Shuffle::BADC); + // tmp2 = (-A, B, -C, D) + let tmp2 = self.blend(self.negate_lazy(), Lanes::AC); + // (B - A, B + A, D - C, D + C) bounded with b < 1.6 + tmp1 + tmp2 + } + + /// Reduce this vector of field elements \\(\mathrm{mod} p\\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.0002 \\). + #[inline] + pub fn reduce(&self) -> FieldElement2625x4 { + let shifts = i32x8::new(26, 26, 25, 25, 26, 26, 25, 25); + let masks = u32x8::new( + (1 << 26) - 1, + (1 << 26) - 1, + (1 << 25) - 1, + (1 << 25) - 1, + (1 << 26) - 1, + (1 << 26) - 1, + (1 << 25) - 1, + (1 << 25) - 1, + ); + + // Let c(x) denote the carryout of the coefficient x. + // + // Given ( x0, y0, x1, y1, z0, w0, z1, w1), + // compute (c(x1), c(y1), c(x0), c(y0), c(z1), c(w1), c(z0), c(w0)). + // + // The carryouts are bounded by 2^(32 - 25) = 2^7. + let rotated_carryout = |v: u32x8| -> u32x8 { + unsafe { + use core::arch::x86_64::_mm256_srlv_epi32; + use core::arch::x86_64::_mm256_shuffle_epi32; + + let c = _mm256_srlv_epi32(v.into_bits(), shifts.into_bits()); + _mm256_shuffle_epi32(c, 0b01_00_11_10).into_bits() + } + }; + + // Combine (lo, lo, lo, lo, lo, lo, lo, lo) + // with (hi, hi, hi, hi, hi, hi, hi, hi) + // to (lo, lo, hi, hi, lo, lo, hi, hi) + // + // This allows combining carryouts, e.g., + // + // lo (c(x1), c(y1), c(x0), c(y0), c(z1), c(w1), c(z0), c(w0)) + // hi (c(x3), c(y3), c(x2), c(y2), c(z3), c(w3), c(z2), c(w2)) + // -> (c(x1), c(y1), c(x2), c(y2), c(z1), c(w1), c(z2), c(w2)) + // + // which is exactly the vector of carryins for + // + // ( x2, y2, x3, y3, z2, w2, z3, w3). + // + let combine = |v_lo: u32x8, v_hi: u32x8| -> u32x8 { + unsafe { + use core::arch::x86_64::_mm256_blend_epi32; + _mm256_blend_epi32(v_lo.into_bits(), v_hi.into_bits(), 0b11_00_11_00).into_bits() + } + }; + + let mut v = self.0; + + let c10 = rotated_carryout(v[0]); + v[0] = (v[0] & masks) + combine(u32x8::splat(0), c10); + + let c32 = rotated_carryout(v[1]); + v[1] = (v[1] & masks) + combine(c10, c32); + + let c54 = rotated_carryout(v[2]); + v[2] = (v[2] & masks) + combine(c32, c54); + + let c76 = rotated_carryout(v[3]); + v[3] = (v[3] & masks) + combine(c54, c76); + + let c98 = rotated_carryout(v[4]); + v[4] = (v[4] & masks) + combine(c76, c98); + + let c9_19: u32x8 = unsafe { + use core::arch::x86_64::_mm256_mul_epu32; + use core::arch::x86_64::_mm256_shuffle_epi32; + + // Need to rearrange c98, since vpmuludq uses the low + // 32-bits of each 64-bit lane to compute the product: + // + // c98 = (c(x9), c(y9), c(x8), c(y8), c(z9), c(w9), c(z8), c(w8)); + // c9_spread = (c(x9), c(x8), c(y9), c(y8), c(z9), c(z8), c(w9), c(w8)). + let c9_spread = _mm256_shuffle_epi32(c98.into_bits(), 0b11_01_10_00); + + // Since the carryouts are bounded by 2^7, their products with 19 + // are bounded by 2^11.25. This means that + // + // c9_19_spread = (19*c(x9), 0, 19*c(y9), 0, 19*c(z9), 0, 19*c(w9), 0). + let c9_19_spread = _mm256_mul_epu32(c9_spread, u64x4::splat(19).into_bits()); + + // Unshuffle: + // c9_19 = (19*c(x9), 19*c(y9), 0, 0, 19*c(z9), 19*c(w9), 0, 0). + _mm256_shuffle_epi32(c9_19_spread, 0b11_01_10_00).into_bits() + }; + + // Add the final carryin. + v[0] = v[0] + c9_19; + + // Each output coefficient has exactly one carryin, which is + // bounded by 2^11.25, so they are bounded as + // + // c_even < 2^26 + 2^11.25 < 26.00006 < 2^{26+b} + // c_odd < 2^25 + 2^11.25 < 25.0001 < 2^{25+b} + // + // where b = 0.0002. + FieldElement2625x4(v) + } + + /// Given an array of wide coefficients, reduce them to a `FieldElement2625x4`. + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.007 \\). + #[inline] + fn reduce64(mut z: [u64x4; 10]) -> FieldElement2625x4 { + // These aren't const because splat isn't a const fn + let LOW_25_BITS: u64x4 = u64x4::splat((1 << 25) - 1); + let LOW_26_BITS: u64x4 = u64x4::splat((1 << 26) - 1); + + // Carry the value from limb i = 0..8 to limb i+1 + let carry = |z: &mut [u64x4; 10], i: usize| { + debug_assert!(i < 9); + if i % 2 == 0 { + // Even limbs have 26 bits + z[i + 1] = z[i + 1] + (z[i] >> 26); + z[i] = z[i] & LOW_26_BITS; + } else { + // Odd limbs have 25 bits + z[i + 1] = z[i + 1] + (z[i] >> 25); + z[i] = z[i] & LOW_25_BITS; + } + }; + + // Perform two halves of the carry chain in parallel. + carry(&mut z, 0); carry(&mut z, 4); + carry(&mut z, 1); carry(&mut z, 5); + carry(&mut z, 2); carry(&mut z, 6); + carry(&mut z, 3); carry(&mut z, 7); + // Since z[3] < 2^64, c < 2^(64-25) = 2^39, + // so z[4] < 2^26 + 2^39 < 2^39.0002 + carry(&mut z, 4); carry(&mut z, 8); + // Now z[4] < 2^26 + // and z[5] < 2^25 + 2^13.0002 < 2^25.0004 (good enough) + + // Last carry has a multiplication by 19. In the serial case we + // do a 64-bit multiplication by 19, but here we want to do a + // 32-bit multiplication. However, if we only know z[9] < 2^64, + // the carry is bounded as c < 2^(64-25) = 2^39, which is too + // big. To ensure c < 2^32, we would need z[9] < 2^57. + // Instead, we split the carry in two, with c = c_0 + c_1*2^26. + + let c = z[9] >> 25; + z[9] = z[9] & LOW_25_BITS; + let mut c0: u64x4 = c & LOW_26_BITS; // c0 < 2^26; + let mut c1: u64x4 = c >> 26; // c1 < 2^(39-26) = 2^13; + + unsafe { + use core::arch::x86_64::_mm256_mul_epu32; + let x19 = u64x4::splat(19); + c0 = _mm256_mul_epu32(c0.into_bits(), x19.into_bits()).into_bits(); // c0 < 2^30.25 + c1 = _mm256_mul_epu32(c1.into_bits(), x19.into_bits()).into_bits(); // c1 < 2^17.25 + } + + z[0] = z[0] + c0; // z0 < 2^26 + 2^30.25 < 2^30.33 + z[1] = z[1] + c1; // z1 < 2^25 + 2^17.25 < 2^25.0067 + carry(&mut z, 0); // z0 < 2^26, z1 < 2^25.0067 + 2^4.33 = 2^25.007 + + // The output coefficients are bounded with + // + // b = 0.007 for z[1] + // b = 0.0004 for z[5] + // b = 0 for other z[i]. + // + // So the packed result is bounded with b = 0.007. + FieldElement2625x4([ + repack_pair(z[0].into_bits(), z[1].into_bits()), + repack_pair(z[2].into_bits(), z[3].into_bits()), + repack_pair(z[4].into_bits(), z[5].into_bits()), + repack_pair(z[6].into_bits(), z[7].into_bits()), + repack_pair(z[8].into_bits(), z[9].into_bits()), + ]) + } + + /// Square this field element, and negate the result's \\(D\\) value. + /// + /// # Preconditions + /// + /// The coefficients of `self` must be bounded with \\( b < 1.5 \\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.007 \\). + pub fn square_and_negate_D(&self) -> FieldElement2625x4 { + #[inline(always)] + fn m(x: u32x8, y: u32x8) -> u64x4 { + use core::arch::x86_64::_mm256_mul_epu32; + unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + } + + #[inline(always)] + fn m_lo(x: u32x8, y: u32x8) -> u32x8 { + use core::arch::x86_64::_mm256_mul_epu32; + unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + } + + let v19 = u32x8::new(19, 0, 19, 0, 19, 0, 19, 0); + + let (x0, x1) = unpack_pair(self.0[0]); + let (x2, x3) = unpack_pair(self.0[1]); + let (x4, x5) = unpack_pair(self.0[2]); + let (x6, x7) = unpack_pair(self.0[3]); + let (x8, x9) = unpack_pair(self.0[4]); + + let x0_2 = x0 << 1; + let x1_2 = x1 << 1; + let x2_2 = x2 << 1; + let x3_2 = x3 << 1; + let x4_2 = x4 << 1; + let x5_2 = x5 << 1; + let x6_2 = x6 << 1; + let x7_2 = x7 << 1; + + let x5_19 = m_lo(v19, x5); + let x6_19 = m_lo(v19, x6); + let x7_19 = m_lo(v19, x7); + let x8_19 = m_lo(v19, x8); + let x9_19 = m_lo(v19, x9); + + let mut z0 = m(x0, x0) + m(x2_2,x8_19) + m(x4_2,x6_19) + ((m(x1_2,x9_19) + m(x3_2,x7_19) + m(x5,x5_19)) << 1); + let mut z1 = m(x0_2,x1) + m(x3_2,x8_19) + m(x5_2,x6_19) + ((m(x2,x9_19) + m(x4,x7_19)) << 1); + let mut z2 = m(x0_2,x2) + m(x1_2,x1) + m(x4_2,x8_19) + m(x6,x6_19) + ((m(x3_2,x9_19) + m(x5_2,x7_19)) << 1); + let mut z3 = m(x0_2,x3) + m(x1_2,x2) + m(x5_2,x8_19) + ((m(x4,x9_19) + m(x6,x7_19)) << 1); + let mut z4 = m(x0_2,x4) + m(x1_2,x3_2) + m(x2, x2) + m(x6_2,x8_19) + ((m(x5_2,x9_19) + m(x7,x7_19)) << 1); + let mut z5 = m(x0_2,x5) + m(x1_2,x4) + m(x2_2,x3) + m(x7_2,x8_19) + ((m(x6,x9_19)) << 1); + let mut z6 = m(x0_2,x6) + m(x1_2,x5_2) + m(x2_2,x4) + m(x3_2,x3) + m(x8,x8_19) + ((m(x7_2,x9_19)) << 1); + let mut z7 = m(x0_2,x7) + m(x1_2,x6) + m(x2_2,x5) + m(x3_2,x4) + ((m(x8,x9_19)) << 1); + let mut z8 = m(x0_2,x8) + m(x1_2,x7_2) + m(x2_2,x6) + m(x3_2,x5_2) + m(x4,x4) + ((m(x9,x9_19)) << 1); + let mut z9 = m(x0_2,x9) + m(x1_2,x8) + m(x2_2,x7) + m(x3_2,x6) + m(x4_2,x5); + + // The biggest z_i is bounded as z_i < 249*2^(51 + 2*b); + // if b < 1.5 we get z_i < 4485585228861014016. + // + // The limbs of the multiples of p are bounded above by + // + // 0x3fffffff << 37 = 9223371899415822336 < 2^63 + // + // and below by + // + // 0x1fffffff << 37 = 4611685880988434432 + // > 4485585228861014016 + // + // So these multiples of p are big enough to avoid underflow + // in subtraction, and small enough to fit within u64 + // with room for a carry. + + let low__p37 = u64x4::splat(0x3ffffed << 37); + let even_p37 = u64x4::splat(0x3ffffff << 37); + let odd__p37 = u64x4::splat(0x1ffffff << 37); + + let negate_D = |x: u64x4, p: u64x4| -> u64x4 { + unsafe { + use core::arch::x86_64::_mm256_blend_epi32; + _mm256_blend_epi32(x.into_bits(), (p - x).into_bits(), D_LANES64 as i32).into_bits() + } + }; + + z0 = negate_D(z0, low__p37); + z1 = negate_D(z1, odd__p37); + z2 = negate_D(z2, even_p37); + z3 = negate_D(z3, odd__p37); + z4 = negate_D(z4, even_p37); + z5 = negate_D(z5, odd__p37); + z6 = negate_D(z6, even_p37); + z7 = negate_D(z7, odd__p37); + z8 = negate_D(z8, even_p37); + z9 = negate_D(z9, odd__p37); + + FieldElement2625x4::reduce64([z0, z1, z2, z3, z4, z5, z6, z7, z8, z9]) + } +} + +impl Neg for FieldElement2625x4 { + type Output = FieldElement2625x4; + + /// Negate this field element, performing a reduction. + /// + /// If the coefficients are known to be small, use `negate_lazy` + /// to avoid performing a reduction. + /// + /// # Preconditions + /// + /// The coefficients of `self` must be bounded with \\( b < 4.0 \\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.0002 \\). + #[inline] + fn neg(self) -> FieldElement2625x4 { + FieldElement2625x4([ + P_TIMES_16_LO - self.0[0], + P_TIMES_16_HI - self.0[1], + P_TIMES_16_HI - self.0[2], + P_TIMES_16_HI - self.0[3], + P_TIMES_16_HI - self.0[4], + ]).reduce() + } +} + +impl Add for FieldElement2625x4 { + type Output = FieldElement2625x4; + /// Add two `FieldElement2625x4`s, without performing a reduction. + #[inline] + fn add(self, rhs: FieldElement2625x4) -> FieldElement2625x4 { + FieldElement2625x4([ + self.0[0] + rhs.0[0], + self.0[1] + rhs.0[1], + self.0[2] + rhs.0[2], + self.0[3] + rhs.0[3], + self.0[4] + rhs.0[4], + ]) + } +} + +impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { + type Output = FieldElement2625x4; + /// Perform a multiplication by a vector of small constants. + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.007 \\). + #[inline] + fn mul(self, scalars: (u32, u32, u32, u32)) -> FieldElement2625x4 { + unsafe { + use core::arch::x86_64::_mm256_mul_epu32; + + let consts = u32x8::new(scalars.0, 0, scalars.1, 0, scalars.2, 0, scalars.3, 0); + + let (b0, b1) = unpack_pair(self.0[0]); + let (b2, b3) = unpack_pair(self.0[1]); + let (b4, b5) = unpack_pair(self.0[2]); + let (b6, b7) = unpack_pair(self.0[3]); + let (b8, b9) = unpack_pair(self.0[4]); + + FieldElement2625x4::reduce64([ + _mm256_mul_epu32(b0.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b1.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b2.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b3.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b4.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b5.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b6.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b7.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b8.into_bits(), consts.into_bits()).into_bits(), + _mm256_mul_epu32(b9.into_bits(), consts.into_bits()).into_bits(), + ]) + } + } +} + +impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { + type Output = FieldElement2625x4; + /// Multiply `self` by `rhs`. + /// + /// # Preconditions + /// + /// The coefficients of `self` must be bounded with \\( b < 2.5 \\). + /// + /// The coefficients of `rhs` must be bounded with \\( b < 1.75 \\). + /// + /// # Postconditions + /// + /// The coefficients of the result are bounded with \\( b < 0.007 \\). + /// + fn mul(self, rhs: &'b FieldElement2625x4) -> FieldElement2625x4 { + #[inline(always)] + fn m(x: u32x8, y: u32x8) -> u64x4 { + use core::arch::x86_64::_mm256_mul_epu32; + unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + } + + #[inline(always)] + fn m_lo(x: u32x8, y: u32x8) -> u32x8 { + use core::arch::x86_64::_mm256_mul_epu32; + unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + } + + let (x0, x1) = unpack_pair(self.0[0]); + let (x2, x3) = unpack_pair(self.0[1]); + let (x4, x5) = unpack_pair(self.0[2]); + let (x6, x7) = unpack_pair(self.0[3]); + let (x8, x9) = unpack_pair(self.0[4]); + + let (y0, y1) = unpack_pair(rhs.0[0]); + let (y2, y3) = unpack_pair(rhs.0[1]); + let (y4, y5) = unpack_pair(rhs.0[2]); + let (y6, y7) = unpack_pair(rhs.0[3]); + let (y8, y9) = unpack_pair(rhs.0[4]); + + let v19 = u32x8::new(19, 0, 19, 0, 19, 0, 19, 0); + + let y1_19 = m_lo(v19, y1); // This fits in a u32 + let y2_19 = m_lo(v19, y2); // iff 26 + b + lg(19) < 32 + let y3_19 = m_lo(v19, y3); // if b < 32 - 26 - 4.248 = 1.752 + let y4_19 = m_lo(v19, y4); + let y5_19 = m_lo(v19, y5); + let y6_19 = m_lo(v19, y6); + let y7_19 = m_lo(v19, y7); + let y8_19 = m_lo(v19, y8); + let y9_19 = m_lo(v19, y9); + + let x1_2 = x1 + x1; // This fits in a u32 iff 25 + b + 1 < 32 + let x3_2 = x3 + x3; // iff b < 6 + let x5_2 = x5 + x5; + let x7_2 = x7 + x7; + let x9_2 = x9 + x9; + + let z0 = m(x0,y0) + m(x1_2,y9_19) + m(x2,y8_19) + m(x3_2,y7_19) + m(x4,y6_19) + m(x5_2,y5_19) + m(x6,y4_19) + m(x7_2,y3_19) + m(x8,y2_19) + m(x9_2,y1_19); + let z1 = m(x0,y1) + m(x1,y0) + m(x2,y9_19) + m(x3,y8_19) + m(x4,y7_19) + m(x5,y6_19) + m(x6,y5_19) + m(x7,y4_19) + m(x8,y3_19) + m(x9,y2_19); + let z2 = m(x0,y2) + m(x1_2,y1) + m(x2,y0) + m(x3_2,y9_19) + m(x4,y8_19) + m(x5_2,y7_19) + m(x6,y6_19) + m(x7_2,y5_19) + m(x8,y4_19) + m(x9_2,y3_19); + let z3 = m(x0,y3) + m(x1,y2) + m(x2,y1) + m(x3,y0) + m(x4,y9_19) + m(x5,y8_19) + m(x6,y7_19) + m(x7,y6_19) + m(x8,y5_19) + m(x9,y4_19); + let z4 = m(x0,y4) + m(x1_2,y3) + m(x2,y2) + m(x3_2,y1) + m(x4,y0) + m(x5_2,y9_19) + m(x6,y8_19) + m(x7_2,y7_19) + m(x8,y6_19) + m(x9_2,y5_19); + let z5 = m(x0,y5) + m(x1,y4) + m(x2,y3) + m(x3,y2) + m(x4,y1) + m(x5,y0) + m(x6,y9_19) + m(x7,y8_19) + m(x8,y7_19) + m(x9,y6_19); + let z6 = m(x0,y6) + m(x1_2,y5) + m(x2,y4) + m(x3_2,y3) + m(x4,y2) + m(x5_2,y1) + m(x6,y0) + m(x7_2,y9_19) + m(x8,y8_19) + m(x9_2,y7_19); + let z7 = m(x0,y7) + m(x1,y6) + m(x2,y5) + m(x3,y4) + m(x4,y3) + m(x5,y2) + m(x6,y1) + m(x7,y0) + m(x8,y9_19) + m(x9,y8_19); + let z8 = m(x0,y8) + m(x1_2,y7) + m(x2,y6) + m(x3_2,y5) + m(x4,y4) + m(x5_2,y3) + m(x6,y2) + m(x7_2,y1) + m(x8,y0) + m(x9_2,y9_19); + let z9 = m(x0,y9) + m(x1,y8) + m(x2,y7) + m(x3,y6) + m(x4,y5) + m(x5,y4) + m(x6,y3) + m(x7,y2) + m(x8,y1) + m(x9,y0); + + // The bounds on z[i] are the same as in the serial 32-bit code + // and the comment below is copied from there: + + // How big is the contribution to z[i+j] from x[i], y[j]? + // + // Using the bounds above, we get: + // + // i even, j even: x[i]*y[j] < 2^(26+b)*2^(26+b) = 2*2^(51+2*b) + // i odd, j even: x[i]*y[j] < 2^(25+b)*2^(26+b) = 1*2^(51+2*b) + // i even, j odd: x[i]*y[j] < 2^(26+b)*2^(25+b) = 1*2^(51+2*b) + // i odd, j odd: 2*x[i]*y[j] < 2*2^(25+b)*2^(25+b) = 1*2^(51+2*b) + // + // We perform inline reduction mod p by replacing 2^255 by 19 + // (since 2^255 - 19 = 0 mod p). This adds a factor of 19, so + // we get the bounds (z0 is the biggest one, but calculated for + // posterity here in case finer estimation is needed later): + // + // z0 < ( 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 249*2^(51 + 2*b) + // z1 < ( 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 154*2^(51 + 2*b) + // z2 < ( 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 195*2^(51 + 2*b) + // z3 < ( 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 118*2^(51 + 2*b) + // z4 < ( 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 141*2^(51 + 2*b) + // z5 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 + 1*19 + 1*19 )*2^(51 + 2b) = 82*2^(51 + 2*b) + // z6 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 + 2*19 + 1*19 )*2^(51 + 2b) = 87*2^(51 + 2*b) + // z7 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1*19 + 1*19 )*2^(51 + 2b) = 46*2^(51 + 2*b) + // z8 < ( 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1*19 )*2^(51 + 2b) = 33*2^(51 + 2*b) + // z9 < ( 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 )*2^(51 + 2b) = 10*2^(51 + 2*b) + // + // So z[0] fits into a u64 if 51 + 2*b + lg(249) < 64 + // if b < 2.5. + + // In fact this bound is slightly sloppy, since it treats both + // inputs x and y as being bounded by the same parameter b, + // while they are in fact bounded by b_x and b_y, and we + // already require that b_y < 1.75 in order to fit the + // multiplications by 19 into a u32. The tighter bound on b_y + // means we could get a tighter bound on the outputs, or a + // looser bound on b_x. + FieldElement2625x4::reduce64([z0, z1, z2, z3, z4, z5, z6, z7, z8, z9]) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn scale_by_curve_constants() { + let mut x = FieldElement2625x4::splat(&FieldElement51::one()); + + x = x * (121666, 121666, 2*121666, 2*121665); + + let xs = x.split(); + assert_eq!(xs[0], FieldElement51([121666, 0, 0, 0, 0])); + assert_eq!(xs[1], FieldElement51([121666, 0, 0, 0, 0])); + assert_eq!(xs[2], FieldElement51([2 * 121666, 0, 0, 0, 0])); + assert_eq!(xs[3], FieldElement51([2 * 121665, 0, 0, 0, 0])); + } + + #[test] + fn diff_sum_vs_serial() { + let x0 = FieldElement51([10000, 10001, 10002, 10003, 10004]); + let x1 = FieldElement51([10100, 10101, 10102, 10103, 10104]); + let x2 = FieldElement51([10200, 10201, 10202, 10203, 10204]); + let x3 = FieldElement51([10300, 10301, 10302, 10303, 10304]); + + let vec = FieldElement2625x4::new(&x0, &x1, &x2, &x3).diff_sum(); + + let result = vec.split(); + + assert_eq!(result[0], &x1 - &x0); + assert_eq!(result[1], &x1 + &x0); + assert_eq!(result[2], &x3 - &x2); + assert_eq!(result[3], &x3 + &x2); + } + + #[test] + fn square_vs_serial() { + let x0 = FieldElement51([10000, 10001, 10002, 10003, 10004]); + let x1 = FieldElement51([10100, 10101, 10102, 10103, 10104]); + let x2 = FieldElement51([10200, 10201, 10202, 10203, 10204]); + let x3 = FieldElement51([10300, 10301, 10302, 10303, 10304]); + + let vec = FieldElement2625x4::new(&x0, &x1, &x2, &x3); + + let result = vec.square_and_negate_D().split(); + + assert_eq!(result[0], &x0 * &x0); + assert_eq!(result[1], &x1 * &x1); + assert_eq!(result[2], &x2 * &x2); + assert_eq!(result[3], -&(&x3 * &x3)); + } + + #[test] + fn multiply_vs_serial() { + let x0 = FieldElement51([10000, 10001, 10002, 10003, 10004]); + let x1 = FieldElement51([10100, 10101, 10102, 10103, 10104]); + let x2 = FieldElement51([10200, 10201, 10202, 10203, 10204]); + let x3 = FieldElement51([10300, 10301, 10302, 10303, 10304]); + + let vec = FieldElement2625x4::new(&x0, &x1, &x2, &x3); + let vecprime = vec.clone(); + + let result = (&vec * &vecprime).split(); + + assert_eq!(result[0], &x0 * &x0); + assert_eq!(result[1], &x1 * &x1); + assert_eq!(result[2], &x2 * &x2); + assert_eq!(result[3], &x3 * &x3); + } + + #[test] + fn test_unpack_repack_pair() { + let x0 = FieldElement51([10000 + (10001 << 26), 0, 0, 0, 0]); + let x1 = FieldElement51([10100 + (10101 << 26), 0, 0, 0, 0]); + let x2 = FieldElement51([10200 + (10201 << 26), 0, 0, 0, 0]); + let x3 = FieldElement51([10300 + (10301 << 26), 0, 0, 0, 0]); + + let vec = FieldElement2625x4::new(&x0, &x1, &x2, &x3); + + let src = vec.0[0]; + + let (a, b) = unpack_pair(src); + + let expected_a = u32x8::new(10000, 0, 10100, 0, 10200, 0, 10300, 0); + let expected_b = u32x8::new(10001, 0, 10101, 0, 10201, 0, 10301, 0); + + assert_eq!(a, expected_a); + assert_eq!(b, expected_b); + + let expected_src = repack_pair(a, b); + + assert_eq!(src, expected_src); + } + + #[test] + fn new_split_roundtrips() { + let x0 = FieldElement51::from_bytes(&[0x10; 32]); + let x1 = FieldElement51::from_bytes(&[0x11; 32]); + let x2 = FieldElement51::from_bytes(&[0x12; 32]); + let x3 = FieldElement51::from_bytes(&[0x13; 32]); + + let vec = FieldElement2625x4::new(&x0, &x1, &x2, &x3); + + let splits = vec.split(); + + assert_eq!(x0, splits[0]); + assert_eq!(x1, splits[1]); + assert_eq!(x2, splits[2]); + assert_eq!(x3, splits[3]); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/mod.rs new file mode 100644 index 0000000..527fdc1 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/avx2/mod.rs @@ -0,0 +1,21 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +#![cfg_attr( + feature = "nightly", + doc(include = "../../../../docs/avx2-notes.md") +)] + +pub(crate) mod field; + +pub(crate) mod edwards; + +pub(crate) mod constants; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/constants.rs new file mode 100644 index 0000000..fd89058 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/constants.rs @@ -0,0 +1,2062 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2018-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +//! This module contains constants used by the IFMA backend. + +use packed_simd::u64x4; + +use window::NafLookupTable8; + +use super::edwards::{CachedPoint, ExtendedPoint}; +use super::field::{F51x4Reduced, F51x4Unreduced}; + +/// The identity element as an `ExtendedPoint`. +pub(crate) static EXTENDEDPOINT_IDENTITY: ExtendedPoint = ExtendedPoint(F51x4Unreduced([ + u64x4::new(0, 1, 1, 0), + u64x4::new(0, 0, 0, 0), + u64x4::new(0, 0, 0, 0), + u64x4::new(0, 0, 0, 0), + u64x4::new(0, 0, 0, 0), +])); + +/// The identity element as a `CachedPoint`. +pub(crate) static CACHEDPOINT_IDENTITY: CachedPoint = CachedPoint(F51x4Reduced([ + u64x4::new(121647, 121666, 243332, 2251799813685229), + u64x4::new(2251799813685248, 0, 0, 2251799813685247), + u64x4::new(2251799813685247, 0, 0, 2251799813685247), + u64x4::new(2251799813685247, 0, 0, 2251799813685247), + u64x4::new(2251799813685247, 0, 0, 2251799813685247), +])); + +/// Odd multiples of the Ed25519 basepoint: +pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = NafLookupTable8([ + CachedPoint(F51x4Reduced([ + u64x4::new(1277522120965857, 73557767439946, 243332, 1943719795065404), + u64x4::new(108375142003455, 341984820733594, 0, 2097709862669256), + u64x4::new(150073485536043, 750646439938056, 0, 581130035634455), + u64x4::new(2149983732744869, 1903255931888577, 0, 646644904824193), + u64x4::new(291045673509296, 1060034214701851, 0, 325245010451737), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1970681836121889, + 1660307753655178, + 1077207637163462, + 1436413309977108, + ), + u64x4::new( + 158785710838757, + 919645875412951, + 174577133496574, + 2213787394009350, + ), + u64x4::new( + 1017606396438281, + 1240932851489554, + 918203302506967, + 1239827708070863, + ), + u64x4::new( + 1748989883612327, + 1745367742532782, + 1168385548387, + 1211387683826673, + ), + u64x4::new( + 799349980018733, + 1471088235739693, + 1505351346057417, + 2104975925096407, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 171437462972293, + 36016853025886, + 1184164975342640, + 1633525003912147, + ), + u64x4::new( + 2113383632509037, + 1946216474924125, + 1884174984466256, + 1373317790955847, + ), + u64x4::new( + 791293623466401, + 1796466048084189, + 444977763198796, + 629823271230872, + ), + u64x4::new( + 1093217720067380, + 2157024270666135, + 238122980108466, + 806820763806847, + ), + u64x4::new( + 793658959468458, + 368578641413741, + 11592529764159, + 2144017075993471, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1538027396670268, + 1588896993892061, + 675619548648376, + 788373514423313, + ), + u64x4::new( + 1987517656073805, + 1940987929951188, + 666993851697339, + 2040540928108427, + ), + u64x4::new( + 375514548584082, + 1726008037083790, + 1070069155000872, + 570111103756303, + ), + u64x4::new( + 772223645372213, + 2123395244967674, + 868238486911408, + 1846639042240362, + ), + u64x4::new( + 872865734460736, + 32277956842850, + 1701451131455402, + 773883376061880, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1845177363882902, + 275858237213625, + 1052127336883600, + 171072805852218, + ), + u64x4::new( + 139016783952609, + 462699304987089, + 430046471494974, + 410922720999257, + ), + u64x4::new( + 846403935976337, + 243817706931454, + 971825428236901, + 571800039596794, + ), + u64x4::new( + 807642685434918, + 1933536976438782, + 812324278898440, + 688391556487313, + ), + u64x4::new( + 76239450396192, + 629532732688863, + 1833302026979779, + 650067934544499, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1373931604989264, + 331159264656614, + 364391529321767, + 874765630865409, + ), + u64x4::new( + 2109908262150241, + 473400816504190, + 91544045127333, + 976307977609515, + ), + u64x4::new( + 330175435673491, + 2126511895885904, + 1022944071588421, + 2158480209801463, + ), + u64x4::new( + 1305666795527971, + 162063591028664, + 2193154870675382, + 1789166662611800, + ), + u64x4::new( + 817858592500508, + 1672743239440202, + 859976879916778, + 1167423340862516, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 274334925170164, + 565841102587251, + 603083835949120, + 607539210240861, + ), + u64x4::new( + 196754662972649, + 1339063476699167, + 1406077076979491, + 896902435668469, + ), + u64x4::new( + 397962210956733, + 174839587476217, + 1381082665748936, + 175195877334136, + ), + u64x4::new( + 717429432748391, + 1635309821746318, + 363374010274647, + 882908746261699, + ), + u64x4::new( + 600946602802781, + 1946596133370711, + 1532135183320341, + 690530671668253, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2074443704000945, + 2163534804938345, + 425423840926528, + 1100826171404853, + ), + u64x4::new( + 111700142796101, + 1456893872751964, + 1186145518682968, + 2192182627706116, + ), + u64x4::new( + 1848722121856066, + 2123239575044749, + 1323870754599272, + 883211262889775, + ), + u64x4::new( + 938263017712916, + 689670293631396, + 183944529557576, + 501908638166580, + ), + u64x4::new( + 2170571907220631, + 36636756989655, + 1875035480138608, + 803703278398018, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1053429956874064, + 1636640618139765, + 1556890827801070, + 2142720579528828, + ), + u64x4::new( + 1814240918422814, + 692326274601777, + 1054896561802157, + 2025454041705534, + ), + u64x4::new( + 2109495823888757, + 1287497869997176, + 194170063200096, + 621116840113213, + ), + u64x4::new( + 2156505873679998, + 2197064359737385, + 1312887672223536, + 369862818895912, + ), + u64x4::new( + 977381163563657, + 1878897311974033, + 2144566861359744, + 1832960882773351, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1266492498289486, + 1301524759372145, + 324789537938521, + 442710471023019, + ), + u64x4::new( + 1232722320001345, + 1191193089162455, + 176474006074813, + 2158950213252857, + ), + u64x4::new( + 1901782191467749, + 494791441598902, + 1820415815322129, + 854954583485223, + ), + u64x4::new( + 1511383667649702, + 792536415032464, + 2027741263854728, + 1727944381044738, + ), + u64x4::new( + 606355788891204, + 1670687521471220, + 582824350365415, + 1509135066079912, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1079942762813598, + 2015830004785901, + 479916361323351, + 1907956590950158, + ), + u64x4::new( + 2053400302939156, + 1319799126867070, + 19493088767391, + 1908755581402373, + ), + u64x4::new( + 2235858054780980, + 885832711204321, + 810332865560178, + 103174191215441, + ), + u64x4::new( + 1843466881032833, + 355511728384038, + 693846715794114, + 186545012724117, + ), + u64x4::new( + 1661758432892509, + 1491022339899281, + 698941123765263, + 174945407208560, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1075933251927831, + 400263885306647, + 1308157532880528, + 347933379126665, + ), + u64x4::new( + 673811632329433, + 1584860147186478, + 271778891257244, + 498194055154207, + ), + u64x4::new( + 703783427747558, + 1051624728592032, + 1371463103351544, + 230351033002960, + ), + u64x4::new( + 860729466483372, + 421647596766583, + 1520613871336707, + 635298775280054, + ), + u64x4::new( + 1168352891728845, + 1691216293752089, + 1799491997061519, + 399728882318504, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 420156727446514, + 1483649215777128, + 165508610199900, + 1918121104840431, + ), + u64x4::new( + 2129902293682427, + 730952770435213, + 2184527544565390, + 1939880362232986, + ), + u64x4::new( + 1771978364905086, + 510975579746524, + 927564335219142, + 177574146260558, + ), + u64x4::new( + 2164104536437514, + 1532598873799015, + 406875369182421, + 1367005937406517, + ), + u64x4::new( + 35073200082587, + 1981124717036219, + 1854087014063833, + 122419694385217, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1963785875777739, + 411497142699119, + 1974557512687408, + 1268304422747183, + ), + u64x4::new( + 762752575978150, + 1443822019541748, + 1331556159904338, + 377726798263780, + ), + u64x4::new( + 825953972847841, + 353487068141356, + 1955697322427207, + 2048226560172078, + ), + u64x4::new( + 1482378558684434, + 657691905625918, + 923870001994493, + 1694132799397736, + ), + u64x4::new( + 1643904759603122, + 170495566698285, + 1218312703413378, + 784318735038131, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 939230507241903, + 2238763473105245, + 1827325199528162, + 1153939339775538, + ), + u64x4::new( + 38544505283339, + 258889431497015, + 351721979677947, + 1357907379592829, + ), + u64x4::new( + 1393974676373341, + 1131355528938676, + 473104915298872, + 978783482501776, + ), + u64x4::new( + 2131516168980501, + 2113911780991092, + 1477027502354261, + 542884524860340, + ), + u64x4::new( + 1029606261349423, + 64226378557628, + 1669131167474348, + 2212808057234874, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1423176501543193, + 163313632579593, + 2220495688893001, + 2220041045291870, + ), + u64x4::new( + 1111834224023697, + 1026815658023689, + 1404605100939775, + 1412149108248227, + ), + u64x4::new( + 1542537854906076, + 1270288391129127, + 991419278941933, + 1824939809581980, + ), + u64x4::new( + 1142003215657891, + 525980550896367, + 1508270666157963, + 917719462309053, + ), + u64x4::new( + 400851268057105, + 1620818232405188, + 1251478578139510, + 2162841805361886, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2125383272208441, + 1368790097335984, + 11813369275978, + 639513785921674, + ), + u64x4::new( + 2200806265616284, + 1041996387620216, + 1275149397833084, + 1723371028064068, + ), + u64x4::new( + 603720163891275, + 2135593511176153, + 2049641644431548, + 1198460677818310, + ), + u64x4::new( + 1862491879401621, + 2008116580769441, + 626566325260235, + 1058308304975798, + ), + u64x4::new( + 628557314314858, + 1075323332046522, + 1631772244117095, + 1812174547405683, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1222773123817104, + 363276129291452, + 796237592807883, + 1914425291893078, + ), + u64x4::new( + 1721259057429088, + 734941709009373, + 1553365830564638, + 1492120931079419, + ), + u64x4::new( + 1009354843273686, + 293884504384873, + 1050281954944357, + 134132942667344, + ), + u64x4::new( + 23119363298711, + 1694754778833445, + 1725925193393496, + 1738396998222001, + ), + u64x4::new( + 1753692057254667, + 118428526447110, + 840961387840295, + 1227619055408558, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1004186117579547, + 508771992330056, + 1426571663072421, + 2238524171903259, + ), + u64x4::new( + 744764613007812, + 398885442368825, + 2047459490294949, + 2141797621077959, + ), + u64x4::new( + 4556204156489, + 1708213022802363, + 1071381560923933, + 393474529142567, + ), + u64x4::new( + 350116198213005, + 945907227204695, + 168267474358731, + 1801504420122711, + ), + u64x4::new( + 728788674520360, + 1262722049156121, + 455259596607008, + 1159442365834489, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2226818917892677, + 185673745808179, + 2240952219732549, + 324137961621908, + ), + u64x4::new( + 1659527641857410, + 973964060249383, + 1349692151487730, + 1172743533370593, + ), + u64x4::new( + 310591478467746, + 2123977244137170, + 774562885265820, + 430035546191685, + ), + u64x4::new( + 2150863173197992, + 2101978317708856, + 193592648406011, + 1375328504508580, + ), + u64x4::new( + 1946235834250479, + 121741431658675, + 1004342690620100, + 2063466488599450, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 463079632200153, + 40415275714025, + 545935352782679, + 1458043501600908, + ), + u64x4::new( + 783771976559993, + 880839641726471, + 1782028201271831, + 41664413404590, + ), + u64x4::new( + 985129151724159, + 187728621410000, + 16620051933318, + 378011085567733, + ), + u64x4::new( + 1820372198168638, + 905710046480679, + 1912961774249737, + 1868135861067161, + ), + u64x4::new( + 474460473983187, + 1455684425673661, + 652771171116843, + 733511920760779, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1088886980746809, + 1660218575261626, + 527921875040240, + 915086639857889, + ), + u64x4::new( + 1814735788528175, + 1586698876186367, + 2040856637532862, + 405684812785624, + ), + u64x4::new( + 658578559700999, + 1751442070931114, + 1293623371490094, + 715026719042518, + ), + u64x4::new( + 382156225644820, + 897982285504960, + 577673183555858, + 1158728558309719, + ), + u64x4::new( + 1865791902475663, + 124491617513788, + 758484125168765, + 734065580770143, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 330985690350617, + 2214424721795630, + 973374650780848, + 1507267060932964, + ), + u64x4::new( + 1733823971011290, + 1730742552292995, + 669018866977489, + 604527664126146, + ), + u64x4::new( + 1082092498645474, + 1029182053935309, + 756799947765834, + 1764720030308351, + ), + u64x4::new( + 969912105693756, + 38116887248276, + 2148030115687613, + 995140534653865, + ), + u64x4::new( + 2154373397460354, + 298128883464656, + 479587543632539, + 1061127201140779, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 843064865526549, + 2019481782959016, + 1873125524281672, + 2013330239022371, + ), + u64x4::new( + 1192932403815186, + 1818108671859220, + 1247005102016258, + 1210577394628058, + ), + u64x4::new( + 132359273326717, + 795492788299178, + 1235924489372816, + 891705064411550, + ), + u64x4::new( + 1425833709104858, + 152114045731085, + 991347902581315, + 1387773338707683, + ), + u64x4::new( + 48024203807922, + 157005564892977, + 1474053161953744, + 727448023498345, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1076621484026788, + 1309917234320927, + 1786998180233659, + 1595497085944737, + ), + u64x4::new( + 1737334672694726, + 2038133716999447, + 1929061192400917, + 620544235219084, + ), + u64x4::new( + 1550527313469747, + 329096759623509, + 1585214659209474, + 693419841748324, + ), + u64x4::new( + 1450010875912315, + 2085047082180569, + 757421110771886, + 389367139787400, + ), + u64x4::new( + 781339490566117, + 132941783448971, + 258650459725225, + 2042274962585613, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 859638991542650, + 2249840007426442, + 1138753070862357, + 793751342318913, + ), + u64x4::new( + 2133476133447306, + 1027010646129239, + 436851910892865, + 866949948830344, + ), + u64x4::new( + 1936003572431223, + 531513680252193, + 1929877059408416, + 830585477662503, + ), + u64x4::new( + 1460760405777960, + 686673748420916, + 275475330051554, + 1581792376993692, + ), + u64x4::new( + 894482039456784, + 1801274480988632, + 16407898635278, + 1668497039215206, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 258585746227669, + 936490904651492, + 1826793887434108, + 1201219990633823, + ), + u64x4::new( + 979462791643635, + 461762372210187, + 218708929991480, + 1378150755760178, + ), + u64x4::new( + 642542170229970, + 787135445552820, + 371168855880557, + 182642566486693, + ), + u64x4::new( + 1152277399721904, + 1726910452705576, + 1452393215705343, + 2117799581546845, + ), + u64x4::new( + 1211265143925330, + 14373046151823, + 1745528818271507, + 1842106288572078, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 635154614562157, + 1956763034454109, + 509123035953043, + 445727657534780, + ), + u64x4::new( + 2072765509783252, + 1282639891593570, + 1075086397362049, + 722996110178195, + ), + u64x4::new( + 1385572918825603, + 1190035835509576, + 218317841176013, + 1047865370756924, + ), + u64x4::new( + 473991569426488, + 1910588123704592, + 1338270051770806, + 401676861680875, + ), + u64x4::new( + 992455353618436, + 126422733426929, + 1955248037756399, + 119233843022643, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1555272991526078, + 2214378187116349, + 366893798097444, + 1401502118355702, + ), + u64x4::new( + 1157229521930713, + 2144787187506262, + 1681597469697840, + 847499096518697, + ), + u64x4::new( + 1872802655800758, + 1027119609820793, + 1137278714788290, + 1664750301179485, + ), + u64x4::new( + 1091289858897030, + 910126419483563, + 1101920147235731, + 597083075893952, + ), + u64x4::new( + 1711011533670315, + 185206680336278, + 1620960612579784, + 1968598849170880, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 73077300235958, + 257216723095630, + 466947267713785, + 847105214181598, + ), + u64x4::new( + 1322905631406309, + 407458059314731, + 230045063190376, + 923800751267786, + ), + u64x4::new( + 1146027205000415, + 1541328763727623, + 768510249199119, + 1630223587589059, + ), + u64x4::new( + 1930368769879433, + 1376145403022159, + 1898149855343131, + 1709421930518180, + ), + u64x4::new( + 633944191571764, + 58314960742839, + 2050971151574988, + 757799756090059, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 361576929158539, + 1035682890165818, + 160945739362874, + 266975208626222, + ), + u64x4::new( + 1635371797076046, + 2106722851965197, + 451585919077206, + 6692426667180, + ), + u64x4::new( + 175820543533852, + 2057511393764025, + 1531846543720469, + 1648320903946519, + ), + u64x4::new( + 947461770620940, + 1107335044817620, + 1725565474111216, + 2182263619949220, + ), + u64x4::new( + 726444888601221, + 1379664085279206, + 1517215633290417, + 1763968936542507, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 686545355846512, + 1712283265573167, + 1743509592736302, + 1653906616429153, + ), + u64x4::new( + 985108805667149, + 2244347650874753, + 1304749057936860, + 321846134330589, + ), + u64x4::new( + 296321076156886, + 1717929256240029, + 450933772486425, + 2015536856431605, + ), + u64x4::new( + 1690393512821866, + 646913049470189, + 2198650647576397, + 1230646705710442, + ), + u64x4::new( + 601961913448442, + 878806578800541, + 620497587492381, + 330716414244629, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 631510982676132, + 1755753187697174, + 1596201246674299, + 2197888384902121, + ), + u64x4::new( + 626957678275745, + 1447583371478595, + 1375375216702128, + 1443613232818823, + ), + u64x4::new( + 1962997804660501, + 1051744123184519, + 1002558639300437, + 1237313314603385, + ), + u64x4::new( + 2118828335274995, + 226398203764759, + 889099617161107, + 1620967117678504, + ), + u64x4::new( + 227261019362935, + 2046897556746842, + 591524060355369, + 2178552047369691, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1375403119051662, + 222313965014452, + 539873444241395, + 213198095917915, + ), + u64x4::new( + 1436952871599114, + 1229749762725246, + 1174441562267670, + 265367077740349, + ), + u64x4::new( + 11107426165917, + 985954476039181, + 1147329112365579, + 1133931640328107, + ), + u64x4::new( + 585235055006843, + 699515259687482, + 299559608721134, + 2134819767146767, + ), + u64x4::new( + 1376401105588528, + 391412107507860, + 302743651807545, + 1362834426455518, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1802940904616205, + 1615132760193234, + 869321663313735, + 666494072545310, + ), + u64x4::new( + 1452849320020701, + 1472716813676364, + 472862999490802, + 359937983286145, + ), + u64x4::new( + 1221198323133843, + 491718521756528, + 1387135774113906, + 793779904904008, + ), + u64x4::new( + 1032129287829151, + 30730741946697, + 217603185195068, + 2118169309744162, + ), + u64x4::new( + 225899335574721, + 1767553399797342, + 881082465669982, + 1435383196392870, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1127093564374276, + 2245188499702906, + 1250041622887441, + 2179324911668149, + ), + u64x4::new( + 908019210866875, + 1879900391060964, + 1355047706206597, + 647218945377302, + ), + u64x4::new( + 1616265604422592, + 2134336781521657, + 1157711219915601, + 1227494173135033, + ), + u64x4::new( + 136450294813355, + 1984543542455033, + 1199486053011083, + 33687889941331, + ), + u64x4::new( + 1053447012707371, + 68239344331930, + 537448158443925, + 1829189783369646, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 996806463322563, + 2043104667851348, + 1110361398300309, + 1218740346887957, + ), + u64x4::new( + 399141907016839, + 1307691109658227, + 532535384961264, + 896201194398872, + ), + u64x4::new( + 111705272106160, + 1790972382466021, + 1159338112559144, + 303544352897203, + ), + u64x4::new( + 1036600573322969, + 1457119922663674, + 334117653665514, + 460023361701263, + ), + u64x4::new( + 1363773215189933, + 1915594049343802, + 1661249423378694, + 1744945551969247, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 3093919631215, + 574886478077610, + 1704446919728971, + 250093147254210, + ), + u64x4::new( + 1387413348737796, + 360142717826981, + 2116185073015983, + 474541388374100, + ), + u64x4::new( + 1632539630892580, + 1332404016215719, + 2145297637794728, + 1289783723173504, + ), + u64x4::new( + 1030244179060173, + 579782698595797, + 1062365251139982, + 677149839815546, + ), + u64x4::new( + 6671539419876, + 1426937459653775, + 406942403696343, + 675479224223817, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 271984148441782, + 1708099625818957, + 1499011822959235, + 516808451044836, + ), + u64x4::new( + 1124847751346323, + 2038336022958449, + 1721698491022600, + 705944403212572, + ), + u64x4::new( + 85459783780275, + 1715213099986669, + 1728445509034791, + 730657630359717, + ), + u64x4::new( + 1185034652652387, + 755472578204310, + 476118360897817, + 1800434542785310, + ), + u64x4::new( + 1815589628676941, + 491778500674079, + 1547664984392513, + 279891608681267, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2036337168672113, + 1730787524684269, + 639134121311693, + 698060925015524, + ), + u64x4::new( + 315211075189491, + 1329055848835358, + 688621136402134, + 1271193060119448, + ), + u64x4::new( + 1697984374314012, + 459330773536457, + 305481314707918, + 61676911066002, + ), + u64x4::new( + 2166631826859191, + 2105217187401781, + 937587962768434, + 357397435365683, + ), + u64x4::new( + 1206757093145471, + 1287847622009294, + 1951336140421622, + 2233789834777410, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 82144190081093, + 1568417433687791, + 907555979158442, + 2037855062523867, + ), + u64x4::new( + 1225315484058853, + 315317868015613, + 1765025920288384, + 175223259828436, + ), + u64x4::new( + 1215010304871271, + 662713408454950, + 429517658575616, + 991062684008811, + ), + u64x4::new( + 993837615254894, + 1485561584889450, + 2001836754226476, + 1915943063896801, + ), + u64x4::new( + 818895101625673, + 1342479472068804, + 1380235330010671, + 23315169761453, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1500726307559118, + 956166860173424, + 512663951564436, + 1940180717699824, + ), + u64x4::new( + 1789521472720825, + 779456898652427, + 2035063615853504, + 863582140589407, + ), + u64x4::new( + 634508890793787, + 1748041666732214, + 259642099961634, + 1294936839797812, + ), + u64x4::new( + 2183334898697038, + 2197242820694806, + 2217225409073703, + 992633998226449, + ), + u64x4::new( + 2197077498155916, + 1562008797791883, + 1395088759904208, + 331715244679294, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 186854731652320, + 284389440026580, + 1252175415119400, + 1025377410100223, + ), + u64x4::new( + 1578732129417607, + 898645497852382, + 2237766074482974, + 1939197790303592, + ), + u64x4::new( + 1438830390640145, + 1682452015845597, + 1108441197232223, + 1984134492898664, + ), + u64x4::new( + 282668727301669, + 1609018289552856, + 390363439795705, + 1138459124667912, + ), + u64x4::new( + 18889015928490, + 532489638086725, + 324621535996080, + 2210046082697453, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2041327051605378, + 2244037852176483, + 2116336876147147, + 9616672544864, + ), + u64x4::new( + 969847387559191, + 1059119127679639, + 1764630094670633, + 364568045311834, + ), + u64x4::new( + 505938893153679, + 2075421412172902, + 326984153045666, + 1959549727324704, + ), + u64x4::new( + 1088715617911260, + 13917085151028, + 950568481355929, + 23687195265771, + ), + u64x4::new( + 1798284568673198, + 808382292203333, + 2214698741961545, + 610817203275867, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1731488929623777, + 1158815615106413, + 1491090861948525, + 1428384712900962, + ), + u64x4::new( + 722237139522457, + 1514290328911535, + 1366197913116230, + 1519472657321210, + ), + u64x4::new( + 246028966932273, + 1888239319448405, + 423720022211163, + 455243905681470, + ), + u64x4::new( + 738323403716001, + 1758018973481179, + 1180718299482318, + 1008495946606708, + ), + u64x4::new( + 334959381596119, + 1704599537529481, + 2172191232106896, + 13502508918495, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 273393076768079, + 427388720298603, + 1071733376018227, + 1715429388968611, + ), + u64x4::new( + 751776629892313, + 1965239102856011, + 541955408230119, + 831043488876080, + ), + u64x4::new( + 643718536393104, + 390543998404644, + 2176730661486279, + 499459234889079, + ), + u64x4::new( + 1482404333915009, + 865527293526285, + 507957951411713, + 216456252558825, + ), + u64x4::new( + 2210281256300231, + 1519357818277551, + 1257866936775246, + 1689605217672864, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2135395168187905, + 2214400157568614, + 2032983817870823, + 1124945109072647, + ), + u64x4::new( + 1602820011758145, + 906675633903289, + 782700735390986, + 2067218823525601, + ), + u64x4::new( + 786785748926382, + 1433583123655616, + 905839404290873, + 2249680349963778, + ), + u64x4::new( + 1940824582370584, + 1610961256326291, + 285307858781375, + 1755588655461194, + ), + u64x4::new( + 233682812055333, + 2146114223476434, + 41132209533476, + 535292431776371, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 600257696476418, + 18449221564824, + 1422209458591138, + 239571584769716, + ), + u64x4::new( + 2056372917056980, + 1155290566623531, + 1252473955568148, + 1276690716882081, + ), + u64x4::new( + 246974369025311, + 658117221519903, + 2000380937898441, + 1351183273924850, + ), + u64x4::new( + 1803747363753112, + 1736801515030186, + 2025633577199091, + 603378480769167, + ), + u64x4::new( + 57348749438551, + 1893551220299655, + 657926732731806, + 1522499384853705, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 591809128842736, + 284860517232591, + 27436696863545, + 886306697195798, + ), + u64x4::new( + 2113192175751749, + 1405882509906423, + 561316282804847, + 835573846576266, + ), + u64x4::new( + 94407289485409, + 1781534171669004, + 2098782516531528, + 598529921520053, + ), + u64x4::new( + 1860137004504786, + 2197323407480349, + 1516772733981532, + 961740253777086, + ), + u64x4::new( + 1484139612868217, + 1593557644636881, + 838834937143441, + 36382198263380, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1165898865828562, + 1153420815042389, + 1068625028915785, + 1945927229911090, + ), + u64x4::new( + 843454394017146, + 571029655293754, + 386282254545998, + 1804608237584150, + ), + u64x4::new( + 370552451091100, + 1279105656351124, + 1864742949668631, + 2093071521726981, + ), + u64x4::new( + 1872542389052198, + 1679083953574330, + 349872262454465, + 1470311090717925, + ), + u64x4::new( + 685345654160323, + 319718985807814, + 1359932285384164, + 1410900103316331, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 2083666668832889, + 314624387816655, + 1496694646480345, + 1946728950459189, + ), + u64x4::new( + 1579153761571203, + 508771185291380, + 1002249659402007, + 551517831173801, + ), + u64x4::new( + 2132371471626150, + 1988122278556533, + 1552195130653890, + 1327637750292755, + ), + u64x4::new( + 118937099181527, + 382610380973142, + 634951529106471, + 382740054041699, + ), + u64x4::new( + 801287519643470, + 87822941589258, + 1908825350108451, + 1404208826499115, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 330347226380261, + 672119116965146, + 1761510370768005, + 1959200302484704, + ), + u64x4::new( + 1631876583009250, + 1684917718484264, + 1027256947805920, + 2174612545251129, + ), + u64x4::new( + 636668855699872, + 625187713984839, + 265886954766790, + 167898557908504, + ), + u64x4::new( + 1210974548180860, + 2051308710365526, + 907620584086428, + 1081788677970850, + ), + u64x4::new( + 621792955460854, + 1450945504745382, + 1666728650687828, + 977937146451674, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 24725936182267, + 2226765032752574, + 2036560083102883, + 2002351185719584, + ), + u64x4::new( + 1620080779405308, + 1493220053370419, + 2245691691038916, + 1152182628629603, + ), + u64x4::new( + 317928527147500, + 1855194218440212, + 979380281964169, + 861442286685289, + ), + u64x4::new( + 393308472784625, + 486143087279967, + 1234071346236405, + 777748237119399, + ), + u64x4::new( + 43850412814718, + 1497656407486446, + 744128331046695, + 1618035787321792, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1670169946550211, + 1230951698726438, + 806586940221293, + 23159779184607, + ), + u64x4::new( + 634011340979302, + 764182085034744, + 731065727766955, + 1737985776442180, + ), + u64x4::new( + 240492712141842, + 73976435954441, + 162810587166835, + 697230894340912, + ), + u64x4::new( + 1299745598348388, + 1359436039694544, + 1856609816731554, + 25228008461513, + ), + u64x4::new( + 2180690501932381, + 2161211192848458, + 87069466793408, + 2003456332883860, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1106932458043379, + 1675181364231371, + 1681785724775243, + 131824742557210, + ), + u64x4::new( + 1671649414647169, + 1827849994880670, + 1097958057111899, + 701956891169434, + ), + u64x4::new( + 2095539283710881, + 591029812888096, + 1699571518315654, + 1297589045812566, + ), + u64x4::new( + 1345612272298537, + 2166754730876055, + 2047982622154948, + 1785222806258129, + ), + u64x4::new( + 2181915268829890, + 1895697064378670, + 1288412327355885, + 1561075738281368, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 741330264098392, + 357073519729966, + 1603572339180975, + 433572083688575, + ), + u64x4::new( + 699685108971208, + 1719650727634959, + 1941668009419214, + 870374958347891, + ), + u64x4::new( + 385971389331537, + 11655507719711, + 94814615497633, + 515572102810609, + ), + u64x4::new( + 1396688200590426, + 1518748475144123, + 162386454324368, + 2083303971579002, + ), + u64x4::new( + 1511688632419263, + 251584258592336, + 545345887993880, + 1229840230314160, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1298668855706029, + 2017860934939344, + 2224150456036391, + 1925926576297971, + ), + u64x4::new( + 259522963883544, + 1312469129541229, + 1647530465049600, + 1113737129047154, + ), + u64x4::new( + 733193298663145, + 2115712816303403, + 897628702762311, + 116440277571901, + ), + u64x4::new( + 1998719395229750, + 1662774553684237, + 194395608126452, + 98796702872301, + ), + u64x4::new( + 2226158244229144, + 91961728239158, + 526869903032152, + 849263805316773, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 472779569333556, + 854477760843410, + 2070906720349401, + 734613359834689, + ), + u64x4::new( + 1771897100487404, + 1604024196006064, + 319699348925383, + 437152129592623, + ), + u64x4::new( + 627618365135361, + 1768642666037955, + 588564169143939, + 35295037750744, + ), + u64x4::new( + 220241884231278, + 319104161410840, + 1048165719448798, + 1583931089774347, + ), + u64x4::new( + 166479451884333, + 1623611819962804, + 59990366193679, + 900727256046987, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 1944687327687331, + 1328410791053991, + 2083980670913902, + 609396833380574, + ), + u64x4::new( + 1907563845734496, + 1385619047697883, + 869817384774457, + 106642388505109, + ), + u64x4::new( + 1006516581737154, + 1561918369633937, + 1921172883211450, + 2216650451558824, + ), + u64x4::new( + 1780506017391778, + 233064930371847, + 1332962603425752, + 1380075261612354, + ), + u64x4::new( + 1907624789747741, + 1310065402098523, + 1838275780706825, + 884225500782782, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 198729830692545, + 100156148743413, + 2140568641558859, + 2220606475942394, + ), + u64x4::new( + 1108788217903741, + 1706330932366163, + 2050449866410661, + 684907598542847, + ), + u64x4::new( + 1101958322366646, + 659427843062405, + 253899933868173, + 896574852821269, + ), + u64x4::new( + 1157052140740658, + 440541103447032, + 2173354981480949, + 604768603561932, + ), + u64x4::new( + 961238337866054, + 830849154351308, + 1643852412409441, + 1436749321770368, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 784870637473285, + 1180234052037572, + 2086951602998715, + 419328169540373, + ), + u64x4::new( + 1966862397394559, + 788036164772123, + 2024355635709481, + 1471696676696146, + ), + u64x4::new( + 1468884300957205, + 1408016588131185, + 2229595828577885, + 240413942963547, + ), + u64x4::new( + 1481791691942441, + 970648959691160, + 1635500996148197, + 2236917233261585, + ), + u64x4::new( + 31660820731028, + 801794768903647, + 1069092619607344, + 282652554845923, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 911659428682786, + 762502588057038, + 1311399152500807, + 1966922911783311, + ), + u64x4::new( + 1229849228728540, + 258161307933217, + 2140796867375541, + 1569345075547911, + ), + u64x4::new( + 1487354676143742, + 1818317546165791, + 811033554173350, + 1768788663337616, + ), + u64x4::new( + 450017165913234, + 962535873747168, + 2099104262993585, + 503030952485785, + ), + u64x4::new( + 1259958681304518, + 479589250923541, + 1503904042161640, + 706283657294305, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 794562643024291, + 198670993088241, + 1678984629358943, + 273399517554618, + ), + u64x4::new( + 188458991574433, + 1389872130156447, + 1461868931574746, + 795140878721432, + ), + u64x4::new( + 624046647169653, + 630363741191019, + 911018499983500, + 1410140563046579, + ), + u64x4::new( + 1675056174405076, + 632544713589250, + 795454163559811, + 1535271563341780, + ), + u64x4::new( + 25504547444781, + 812510098987855, + 51290042016232, + 1992260991700127, + ), + ])), + CachedPoint(F51x4Reduced([ + u64x4::new( + 269968325452358, + 470932785179706, + 1684444304834150, + 1027482126748243, + ), + u64x4::new( + 457941065342419, + 2117377568137882, + 1209423706730905, + 2192403099717071, + ), + u64x4::new( + 1899046404863678, + 1359500336071762, + 1492389156724726, + 1455627081827750, + ), + u64x4::new( + 2016101061876546, + 1967000012916571, + 582539481696050, + 1197538178790094, + ), + u64x4::new( + 639684852217504, + 1799941252757449, + 1470016556327743, + 846111828965901, + ), + ])), +]); diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/edwards.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/edwards.rs new file mode 100644 index 0000000..5c8d819 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/edwards.rs @@ -0,0 +1,315 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2018-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +#![allow(non_snake_case)] + +use traits::Identity; + +use std::ops::{Add, Neg, Sub}; + +use subtle::Choice; +use subtle::ConditionallySelectable; + +use edwards; +use window::{LookupTable, NafLookupTable5, NafLookupTable8}; + +use super::constants; +use super::field::{F51x4Reduced, F51x4Unreduced, Lanes, Shuffle}; + +#[derive(Copy, Clone, Debug)] +pub struct ExtendedPoint(pub(super) F51x4Unreduced); + +#[derive(Copy, Clone, Debug)] +pub struct CachedPoint(pub(super) F51x4Reduced); + +impl From for ExtendedPoint { + fn from(P: edwards::EdwardsPoint) -> ExtendedPoint { + ExtendedPoint(F51x4Unreduced::new(&P.X, &P.Y, &P.Z, &P.T)) + } +} + +impl From for edwards::EdwardsPoint { + fn from(P: ExtendedPoint) -> edwards::EdwardsPoint { + let reduced = F51x4Reduced::from(P.0); + let tmp = F51x4Unreduced::from(reduced).split(); + edwards::EdwardsPoint { + X: tmp[0], + Y: tmp[1], + Z: tmp[2], + T: tmp[3], + } + } +} + +impl From for CachedPoint { + fn from(P: ExtendedPoint) -> CachedPoint { + let mut x = P.0; + + x = x.blend(&x.diff_sum(), Lanes::AB); + x = &F51x4Reduced::from(x) * (121666, 121666, 2 * 121666, 2 * 121665); + x = x.blend(&x.negate_lazy(), Lanes::D); + + CachedPoint(F51x4Reduced::from(x)) + } +} + +impl Default for ExtendedPoint { + fn default() -> ExtendedPoint { + ExtendedPoint::identity() + } +} + +impl Identity for ExtendedPoint { + fn identity() -> ExtendedPoint { + constants::EXTENDEDPOINT_IDENTITY + } +} + +impl ExtendedPoint { + pub fn double(&self) -> ExtendedPoint { + // (Y1 X1 T1 Z1) -- uses vpshufd (1c latency @ 1/c) + let mut tmp0 = self.0.shuffle(Shuffle::BADC); + + // (X1+Y1 X1+Y1 X1+Y1 X1+Y1) -- can use vpinserti128 + let mut tmp1 = (self.0 + tmp0).shuffle(Shuffle::ABAB); + + // (X1 Y1 Z1 X1+Y1) + tmp0 = self.0.blend(&tmp1, Lanes::D); + + tmp1 = F51x4Reduced::from(tmp0).square(); + // Now tmp1 = (S1 S2 S3 S4) + + // We want to compute + // + // + | S1 | S1 | S1 | S1 | + // + | S2 | | | S2 | + // + | | | S3 | | + // + | | | S3 | | + // + | |16p |16p |16p | + // - | | S2 | S2 | | + // - | | | | S4 | + // ======================= + // S5 S6 S8 S9 + + let zero = F51x4Unreduced::zero(); + + let S1_S1_S1_S1 = tmp1.shuffle(Shuffle::AAAA); + let S2_S2_S2_S2 = tmp1.shuffle(Shuffle::BBBB); + + let S2_S2_S2_S4 = S2_S2_S2_S2.blend(&tmp1, Lanes::D).negate_lazy(); + + tmp0 = S1_S1_S1_S1 + zero.blend(&(tmp1 + tmp1), Lanes::C); + tmp0 = tmp0 + zero.blend(&S2_S2_S2_S2, Lanes::AD); + tmp0 = tmp0 + zero.blend(&S2_S2_S2_S4, Lanes::BCD); + + let tmp2 = F51x4Reduced::from(tmp0); + + ExtendedPoint(&tmp2.shuffle(Shuffle::DBBD) * &tmp2.shuffle(Shuffle::CACA)) + } + + pub fn mul_by_pow_2(&self, k: u32) -> ExtendedPoint { + let mut tmp: ExtendedPoint = *self; + for _ in 0..k { + tmp = tmp.double(); + } + tmp + } +} + +impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { + type Output = ExtendedPoint; + + /// Add an `ExtendedPoint` and a `CachedPoint`. + fn add(self, other: &'b CachedPoint) -> ExtendedPoint { + let mut tmp = self.0; + + tmp = tmp.blend(&tmp.diff_sum(), Lanes::AB); + // tmp = (Y1-X1 Y1+X1 Z1 T1) = (S0 S1 Z1 T1) + + tmp = &F51x4Reduced::from(tmp) * &other.0; + // tmp = (S0*S2' S1*S3' Z1*Z2' T1*T2') = (S8 S9 S10 S11) + + tmp = tmp.shuffle(Shuffle::ABDC); + // tmp = (S8 S9 S11 S10) + + let tmp = F51x4Reduced::from(tmp.diff_sum()); + // tmp = (S9-S8 S9+S8 S10-S11 S10+S11) = (S12 S13 S14 S15) + + let t0 = tmp.shuffle(Shuffle::ADDA); + // t0 = (S12 S15 S15 S12) + let t1 = tmp.shuffle(Shuffle::CBCB); + // t1 = (S14 S13 S14 S13) + + // Return (S12*S14 S15*S13 S15*S14 S12*S13) = (X3 Y3 Z3 T3) + ExtendedPoint(&t0 * &t1) + } +} + +impl Default for CachedPoint { + fn default() -> CachedPoint { + CachedPoint::identity() + } +} + +impl Identity for CachedPoint { + fn identity() -> CachedPoint { + constants::CACHEDPOINT_IDENTITY + } +} + +impl ConditionallySelectable for CachedPoint { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + CachedPoint(F51x4Reduced::conditional_select(&a.0, &b.0, choice)) + } + + fn conditional_assign(&mut self, other: &Self, choice: Choice) { + self.0.conditional_assign(&other.0, choice); + } +} + +impl<'a> Neg for &'a CachedPoint { + type Output = CachedPoint; + + fn neg(self) -> CachedPoint { + let swapped = self.0.shuffle(Shuffle::BACD); + CachedPoint(swapped.blend(&(-self.0), Lanes::D)) + } +} + +impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { + type Output = ExtendedPoint; + + /// Implement subtraction by negating the point and adding. + fn sub(self, other: &'b CachedPoint) -> ExtendedPoint { + self + &(-other) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let P = ExtendedPoint::from(*point); + let mut points = [CachedPoint::from(P); 8]; + for i in 0..7 { + points[i + 1] = (&P + &points[i]).into(); + } + LookupTable(points) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let A = ExtendedPoint::from(*point); + let mut Ai = [CachedPoint::from(A); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).into(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + NafLookupTable5(Ai) + } +} + +impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { + fn from(point: &'a edwards::EdwardsPoint) -> Self { + let A = ExtendedPoint::from(*point); + let mut Ai = [CachedPoint::from(A); 64]; + let A2 = A.double(); + for i in 0..63 { + Ai[i + 1] = (&A2 + &Ai[i]).into(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] + NafLookupTable8(Ai) + } +} + +#[cfg(test)] +mod test { + use super::*; + + fn addition_test_helper(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) { + // Test the serial implementation of the parallel addition formulas + //let R_serial: edwards::EdwardsPoint = serial_add(P.into(), Q.into()).into(); + + // Test the vector implementation of the parallel readdition formulas + let cached_Q = CachedPoint::from(ExtendedPoint::from(Q)); + let R_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) + &cached_Q).into(); + let S_vector: edwards::EdwardsPoint = (&ExtendedPoint::from(P) - &cached_Q).into(); + + println!("Testing point addition:"); + println!("P = {:?}", P); + println!("Q = {:?}", Q); + println!("cached Q = {:?}", cached_Q); + println!("R = P + Q = {:?}", &P + &Q); + //println!("R_serial = {:?}", R_serial); + println!("R_vector = {:?}", R_vector); + println!("S = P - Q = {:?}", &P - &Q); + println!("S_vector = {:?}", S_vector); + //assert_eq!(R_serial.compress(), (&P + &Q).compress()); + assert_eq!(R_vector.compress(), (&P + &Q).compress()); + assert_eq!(S_vector.compress(), (&P - &Q).compress()); + println!("OK!\n"); + } + + #[test] + fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() { + use constants; + use scalar::Scalar; + + println!("Testing id +- id"); + let P = edwards::EdwardsPoint::identity(); + let Q = edwards::EdwardsPoint::identity(); + addition_test_helper(P, Q); + + println!("Testing id +- B"); + let P = edwards::EdwardsPoint::identity(); + let Q = constants::ED25519_BASEPOINT_POINT; + addition_test_helper(P, Q); + + println!("Testing B +- B"); + let P = constants::ED25519_BASEPOINT_POINT; + let Q = constants::ED25519_BASEPOINT_POINT; + addition_test_helper(P, Q); + + println!("Testing B +- kB"); + let P = constants::ED25519_BASEPOINT_POINT; + let Q = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + addition_test_helper(P, Q); + } + + fn doubling_test_helper(P: edwards::EdwardsPoint) { + //let R1: edwards::EdwardsPoint = serial_double(P.into()).into(); + let R2: edwards::EdwardsPoint = ExtendedPoint::from(P).double().into(); + println!("Testing point doubling:"); + println!("P = {:?}", P); + //println!("(serial) R1 = {:?}", R1); + println!("(vector) R2 = {:?}", R2); + println!("P + P = {:?}", &P + &P); + //assert_eq!(R1.compress(), (&P + &P).compress()); + assert_eq!(R2.compress(), (&P + &P).compress()); + println!("OK!\n"); + } + + #[test] + fn vector_doubling_vs_serial_doubling_vs_edwards_extendedpoint() { + use constants; + use scalar::Scalar; + + println!("Testing [2]id"); + let P = edwards::EdwardsPoint::identity(); + doubling_test_helper(P); + + println!("Testing [2]B"); + let P = constants::ED25519_BASEPOINT_POINT; + doubling_test_helper(P); + + println!("Testing [2]([k]B)"); + let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + doubling_test_helper(P); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/field.rs new file mode 100644 index 0000000..a393b22 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/field.rs @@ -0,0 +1,826 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +#![allow(non_snake_case)] + +use core::ops::{Add, Mul, Neg}; +use packed_simd::{u64x4, IntoBits}; + +use backend::serial::u64::field::FieldElement51; + +/// A wrapper around `vpmadd52luq` that works on `u64x4`. +#[inline(always)] +unsafe fn madd52lo(z: u64x4, x: u64x4, y: u64x4) -> u64x4 { + use core::arch::x86_64::_mm256_madd52lo_epu64; + _mm256_madd52lo_epu64(z.into_bits(), x.into_bits(), y.into_bits()).into_bits() +} + +/// A wrapper around `vpmadd52huq` that works on `u64x4`. +#[inline(always)] +unsafe fn madd52hi(z: u64x4, x: u64x4, y: u64x4) -> u64x4 { + use core::arch::x86_64::_mm256_madd52hi_epu64; + _mm256_madd52hi_epu64(z.into_bits(), x.into_bits(), y.into_bits()).into_bits() +} + +/// A vector of four field elements in radix 2^51, with unreduced coefficients. +#[derive(Copy, Clone, Debug)] +pub struct F51x4Unreduced(pub(crate) [u64x4; 5]); + +/// A vector of four field elements in radix 2^51, with reduced coefficients. +#[derive(Copy, Clone, Debug)] +pub struct F51x4Reduced(pub(crate) [u64x4; 5]); + +#[derive(Copy, Clone)] +pub enum Shuffle { + AAAA, + BBBB, + BADC, + BACD, + ADDA, + CBCB, + ABDC, + ABAB, + DBBD, + CACA, +} + +#[inline(always)] +fn shuffle_lanes(x: u64x4, control: Shuffle) -> u64x4 { + unsafe { + use core::arch::x86_64::_mm256_permute4x64_epi64 as perm; + + match control { + Shuffle::AAAA => perm(x.into_bits(), 0b00_00_00_00).into_bits(), + Shuffle::BBBB => perm(x.into_bits(), 0b01_01_01_01).into_bits(), + Shuffle::BADC => perm(x.into_bits(), 0b10_11_00_01).into_bits(), + Shuffle::BACD => perm(x.into_bits(), 0b11_10_00_01).into_bits(), + Shuffle::ADDA => perm(x.into_bits(), 0b00_11_11_00).into_bits(), + Shuffle::CBCB => perm(x.into_bits(), 0b01_10_01_10).into_bits(), + Shuffle::ABDC => perm(x.into_bits(), 0b10_11_01_00).into_bits(), + Shuffle::ABAB => perm(x.into_bits(), 0b01_00_01_00).into_bits(), + Shuffle::DBBD => perm(x.into_bits(), 0b11_01_01_11).into_bits(), + Shuffle::CACA => perm(x.into_bits(), 0b00_10_00_10).into_bits(), + } + } +} + +#[derive(Copy, Clone)] +pub enum Lanes { + D, + C, + AB, + AC, + AD, + BCD, +} + +#[inline] +fn blend_lanes(x: u64x4, y: u64x4, control: Lanes) -> u64x4 { + unsafe { + use core::arch::x86_64::_mm256_blend_epi32 as blend; + + match control { + Lanes::D => blend(x.into_bits(), y.into_bits(), 0b11_00_00_00).into_bits(), + Lanes::C => blend(x.into_bits(), y.into_bits(), 0b00_11_00_00).into_bits(), + Lanes::AB => blend(x.into_bits(), y.into_bits(), 0b00_00_11_11).into_bits(), + Lanes::AC => blend(x.into_bits(), y.into_bits(), 0b00_11_00_11).into_bits(), + Lanes::AD => blend(x.into_bits(), y.into_bits(), 0b11_00_00_11).into_bits(), + Lanes::BCD => blend(x.into_bits(), y.into_bits(), 0b11_11_11_00).into_bits(), + } + } +} + +impl F51x4Unreduced { + pub fn zero() -> F51x4Unreduced { + F51x4Unreduced([u64x4::splat(0); 5]) + } + + pub fn new( + x0: &FieldElement51, + x1: &FieldElement51, + x2: &FieldElement51, + x3: &FieldElement51, + ) -> F51x4Unreduced { + F51x4Unreduced([ + u64x4::new(x0.0[0], x1.0[0], x2.0[0], x3.0[0]), + u64x4::new(x0.0[1], x1.0[1], x2.0[1], x3.0[1]), + u64x4::new(x0.0[2], x1.0[2], x2.0[2], x3.0[2]), + u64x4::new(x0.0[3], x1.0[3], x2.0[3], x3.0[3]), + u64x4::new(x0.0[4], x1.0[4], x2.0[4], x3.0[4]), + ]) + } + + pub fn split(&self) -> [FieldElement51; 4] { + let x = &self.0; + [ + FieldElement51([ + x[0].extract(0), + x[1].extract(0), + x[2].extract(0), + x[3].extract(0), + x[4].extract(0), + ]), + FieldElement51([ + x[0].extract(1), + x[1].extract(1), + x[2].extract(1), + x[3].extract(1), + x[4].extract(1), + ]), + FieldElement51([ + x[0].extract(2), + x[1].extract(2), + x[2].extract(2), + x[3].extract(2), + x[4].extract(2), + ]), + FieldElement51([ + x[0].extract(3), + x[1].extract(3), + x[2].extract(3), + x[3].extract(3), + x[4].extract(3), + ]), + ] + } + + #[inline] + pub fn diff_sum(&self) -> F51x4Unreduced { + // tmp1 = (B, A, D, C) + let tmp1 = self.shuffle(Shuffle::BADC); + // tmp2 = (-A, B, -C, D) + let tmp2 = self.blend(&self.negate_lazy(), Lanes::AC); + // (B - A, B + A, D - C, D + C) + tmp1 + tmp2 + } + + #[inline] + pub fn negate_lazy(&self) -> F51x4Unreduced { + let lo = u64x4::splat(36028797018963664u64); + let hi = u64x4::splat(36028797018963952u64); + F51x4Unreduced([ + lo - self.0[0], + hi - self.0[1], + hi - self.0[2], + hi - self.0[3], + hi - self.0[4], + ]) + } + + #[inline] + pub fn shuffle(&self, control: Shuffle) -> F51x4Unreduced { + F51x4Unreduced([ + shuffle_lanes(self.0[0], control), + shuffle_lanes(self.0[1], control), + shuffle_lanes(self.0[2], control), + shuffle_lanes(self.0[3], control), + shuffle_lanes(self.0[4], control), + ]) + } + + #[inline] + pub fn blend(&self, other: &F51x4Unreduced, control: Lanes) -> F51x4Unreduced { + F51x4Unreduced([ + blend_lanes(self.0[0], other.0[0], control), + blend_lanes(self.0[1], other.0[1], control), + blend_lanes(self.0[2], other.0[2], control), + blend_lanes(self.0[3], other.0[3], control), + blend_lanes(self.0[4], other.0[4], control), + ]) + } +} + +impl Neg for F51x4Reduced { + type Output = F51x4Reduced; + + fn neg(self) -> F51x4Reduced { + F51x4Unreduced::from(self).negate_lazy().into() + } +} + +use subtle::Choice; +use subtle::ConditionallySelectable; + +impl ConditionallySelectable for F51x4Reduced { + #[inline] + fn conditional_select(a: &F51x4Reduced, b: &F51x4Reduced, choice: Choice) -> F51x4Reduced { + let mask = (-(choice.unwrap_u8() as i64)) as u64; + let mask_vec = u64x4::splat(mask); + F51x4Reduced([ + a.0[0] ^ (mask_vec & (a.0[0] ^ b.0[0])), + a.0[1] ^ (mask_vec & (a.0[1] ^ b.0[1])), + a.0[2] ^ (mask_vec & (a.0[2] ^ b.0[2])), + a.0[3] ^ (mask_vec & (a.0[3] ^ b.0[3])), + a.0[4] ^ (mask_vec & (a.0[4] ^ b.0[4])), + ]) + } + + #[inline] + fn conditional_assign(&mut self, other: &F51x4Reduced, choice: Choice) { + let mask = (-(choice.unwrap_u8() as i64)) as u64; + let mask_vec = u64x4::splat(mask); + self.0[0] ^= mask_vec & (self.0[0] ^ other.0[0]); + self.0[1] ^= mask_vec & (self.0[1] ^ other.0[1]); + self.0[2] ^= mask_vec & (self.0[2] ^ other.0[2]); + self.0[3] ^= mask_vec & (self.0[3] ^ other.0[3]); + self.0[4] ^= mask_vec & (self.0[4] ^ other.0[4]); + } +} + +impl F51x4Reduced { + #[inline] + pub fn shuffle(&self, control: Shuffle) -> F51x4Reduced { + F51x4Reduced([ + shuffle_lanes(self.0[0], control), + shuffle_lanes(self.0[1], control), + shuffle_lanes(self.0[2], control), + shuffle_lanes(self.0[3], control), + shuffle_lanes(self.0[4], control), + ]) + } + + #[inline] + pub fn blend(&self, other: &F51x4Reduced, control: Lanes) -> F51x4Reduced { + F51x4Reduced([ + blend_lanes(self.0[0], other.0[0], control), + blend_lanes(self.0[1], other.0[1], control), + blend_lanes(self.0[2], other.0[2], control), + blend_lanes(self.0[3], other.0[3], control), + blend_lanes(self.0[4], other.0[4], control), + ]) + } + + #[inline] + pub fn square(&self) -> F51x4Unreduced { + unsafe { + let x = &self.0; + + // Represent values with coeff. 2 + let mut z0_2 = u64x4::splat(0); + let mut z1_2 = u64x4::splat(0); + let mut z2_2 = u64x4::splat(0); + let mut z3_2 = u64x4::splat(0); + let mut z4_2 = u64x4::splat(0); + let mut z5_2 = u64x4::splat(0); + let mut z6_2 = u64x4::splat(0); + let mut z7_2 = u64x4::splat(0); + let mut z9_2 = u64x4::splat(0); + + // Represent values with coeff. 4 + let mut z2_4 = u64x4::splat(0); + let mut z3_4 = u64x4::splat(0); + let mut z4_4 = u64x4::splat(0); + let mut z5_4 = u64x4::splat(0); + let mut z6_4 = u64x4::splat(0); + let mut z7_4 = u64x4::splat(0); + let mut z8_4 = u64x4::splat(0); + + let mut z0_1 = u64x4::splat(0); + z0_1 = madd52lo(z0_1, x[0], x[0]); + + let mut z1_1 = u64x4::splat(0); + z1_2 = madd52lo(z1_2, x[0], x[1]); + z1_2 = madd52hi(z1_2, x[0], x[0]); + + z2_4 = madd52hi(z2_4, x[0], x[1]); + let mut z2_1 = z2_4 << 2; + z2_2 = madd52lo(z2_2, x[0], x[2]); + z2_1 = madd52lo(z2_1, x[1], x[1]); + + z3_4 = madd52hi(z3_4, x[0], x[2]); + let mut z3_1 = z3_4 << 2; + z3_2 = madd52lo(z3_2, x[1], x[2]); + z3_2 = madd52lo(z3_2, x[0], x[3]); + z3_2 = madd52hi(z3_2, x[1], x[1]); + + z4_4 = madd52hi(z4_4, x[1], x[2]); + z4_4 = madd52hi(z4_4, x[0], x[3]); + let mut z4_1 = z4_4 << 2; + z4_2 = madd52lo(z4_2, x[1], x[3]); + z4_2 = madd52lo(z4_2, x[0], x[4]); + z4_1 = madd52lo(z4_1, x[2], x[2]); + + z5_4 = madd52hi(z5_4, x[1], x[3]); + z5_4 = madd52hi(z5_4, x[0], x[4]); + let mut z5_1 = z5_4 << 2; + z5_2 = madd52lo(z5_2, x[2], x[3]); + z5_2 = madd52lo(z5_2, x[1], x[4]); + z5_2 = madd52hi(z5_2, x[2], x[2]); + + z6_4 = madd52hi(z6_4, x[2], x[3]); + z6_4 = madd52hi(z6_4, x[1], x[4]); + let mut z6_1 = z6_4 << 2; + z6_2 = madd52lo(z6_2, x[2], x[4]); + z6_1 = madd52lo(z6_1, x[3], x[3]); + + z7_4 = madd52hi(z7_4, x[2], x[4]); + let mut z7_1 = z7_4 << 2; + z7_2 = madd52lo(z7_2, x[3], x[4]); + z7_2 = madd52hi(z7_2, x[3], x[3]); + + z8_4 = madd52hi(z8_4, x[3], x[4]); + let mut z8_1 = z8_4 << 2; + z8_1 = madd52lo(z8_1, x[4], x[4]); + + let mut z9_1 = u64x4::splat(0); + z9_2 = madd52hi(z9_2, x[4], x[4]); + + z5_1 += z5_2 << 1; + z6_1 += z6_2 << 1; + z7_1 += z7_2 << 1; + z9_1 += z9_2 << 1; + + let mut t0 = u64x4::splat(0); + let mut t1 = u64x4::splat(0); + let r19 = u64x4::splat(19); + + t0 = madd52hi(t0, r19, z9_1); + t1 = madd52lo(t1, r19, z9_1 >> 52); + + z4_2 = madd52lo(z4_2, r19, z8_1 >> 52); + z3_2 = madd52lo(z3_2, r19, z7_1 >> 52); + z2_2 = madd52lo(z2_2, r19, z6_1 >> 52); + z1_2 = madd52lo(z1_2, r19, z5_1 >> 52); + + z0_2 = madd52lo(z0_2, r19, t0 + t1); + z1_2 = madd52hi(z1_2, r19, z5_1); + z2_2 = madd52hi(z2_2, r19, z6_1); + z3_2 = madd52hi(z3_2, r19, z7_1); + z4_2 = madd52hi(z4_2, r19, z8_1); + + z0_1 = madd52lo(z0_1, r19, z5_1); + z1_1 = madd52lo(z1_1, r19, z6_1); + z2_1 = madd52lo(z2_1, r19, z7_1); + z3_1 = madd52lo(z3_1, r19, z8_1); + z4_1 = madd52lo(z4_1, r19, z9_1); + + F51x4Unreduced([ + z0_1 + z0_2 + z0_2, + z1_1 + z1_2 + z1_2, + z2_1 + z2_2 + z2_2, + z3_1 + z3_2 + z3_2, + z4_1 + z4_2 + z4_2, + ]) + } + } +} + +impl From for F51x4Unreduced { + #[inline] + fn from(x: F51x4Reduced) -> F51x4Unreduced { + F51x4Unreduced(x.0) + } +} + +impl From for F51x4Reduced { + #[inline] + fn from(x: F51x4Unreduced) -> F51x4Reduced { + let mask = u64x4::splat((1 << 51) - 1); + let r19 = u64x4::splat(19); + + // Compute carryouts in parallel + let c0 = x.0[0] >> 51; + let c1 = x.0[1] >> 51; + let c2 = x.0[2] >> 51; + let c3 = x.0[3] >> 51; + let c4 = x.0[4] >> 51; + + unsafe { + F51x4Reduced([ + madd52lo(x.0[0] & mask, c4, r19), + (x.0[1] & mask) + c0, + (x.0[2] & mask) + c1, + (x.0[3] & mask) + c2, + (x.0[4] & mask) + c3, + ]) + } + } +} + +impl Add for F51x4Unreduced { + type Output = F51x4Unreduced; + #[inline] + fn add(self, rhs: F51x4Unreduced) -> F51x4Unreduced { + F51x4Unreduced([ + self.0[0] + rhs.0[0], + self.0[1] + rhs.0[1], + self.0[2] + rhs.0[2], + self.0[3] + rhs.0[3], + self.0[4] + rhs.0[4], + ]) + } +} + +impl<'a> Mul<(u32, u32, u32, u32)> for &'a F51x4Reduced { + type Output = F51x4Unreduced; + #[inline] + fn mul(self, scalars: (u32, u32, u32, u32)) -> F51x4Unreduced { + unsafe { + let x = &self.0; + let y = u64x4::new( + scalars.0 as u64, + scalars.1 as u64, + scalars.2 as u64, + scalars.3 as u64, + ); + let r19 = u64x4::splat(19); + + let mut z0_1 = u64x4::splat(0); + let mut z1_1 = u64x4::splat(0); + let mut z2_1 = u64x4::splat(0); + let mut z3_1 = u64x4::splat(0); + let mut z4_1 = u64x4::splat(0); + let mut z1_2 = u64x4::splat(0); + let mut z2_2 = u64x4::splat(0); + let mut z3_2 = u64x4::splat(0); + let mut z4_2 = u64x4::splat(0); + let mut z5_2 = u64x4::splat(0); + + // Wave 0 + z4_2 = madd52hi(z4_2, y, x[3]); + z5_2 = madd52hi(z5_2, y, x[4]); + z4_1 = madd52lo(z4_1, y, x[4]); + z0_1 = madd52lo(z0_1, y, x[0]); + z3_1 = madd52lo(z3_1, y, x[3]); + z2_1 = madd52lo(z2_1, y, x[2]); + z1_1 = madd52lo(z1_1, y, x[1]); + z3_2 = madd52hi(z3_2, y, x[2]); + + // Wave 2 + z2_2 = madd52hi(z2_2, y, x[1]); + z1_2 = madd52hi(z1_2, y, x[0]); + z0_1 = madd52lo(z0_1, z5_2 + z5_2, r19); + + F51x4Unreduced([ + z0_1, + z1_1 + z1_2 + z1_2, + z2_1 + z2_2 + z2_2, + z3_1 + z3_2 + z3_2, + z4_1 + z4_2 + z4_2, + ]) + } + } +} + +impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced { + type Output = F51x4Unreduced; + #[inline] + fn mul(self, rhs: &'b F51x4Reduced) -> F51x4Unreduced { + unsafe { + // Inputs + let x = &self.0; + let y = &rhs.0; + + // Accumulators for terms with coeff 1 + let mut z0_1 = u64x4::splat(0); + let mut z1_1 = u64x4::splat(0); + let mut z2_1 = u64x4::splat(0); + let mut z3_1 = u64x4::splat(0); + let mut z4_1 = u64x4::splat(0); + let mut z5_1 = u64x4::splat(0); + let mut z6_1 = u64x4::splat(0); + let mut z7_1 = u64x4::splat(0); + let mut z8_1 = u64x4::splat(0); + + // Accumulators for terms with coeff 2 + let mut z0_2 = u64x4::splat(0); + let mut z1_2 = u64x4::splat(0); + let mut z2_2 = u64x4::splat(0); + let mut z3_2 = u64x4::splat(0); + let mut z4_2 = u64x4::splat(0); + let mut z5_2 = u64x4::splat(0); + let mut z6_2 = u64x4::splat(0); + let mut z7_2 = u64x4::splat(0); + let mut z8_2 = u64x4::splat(0); + let mut z9_2 = u64x4::splat(0); + + // LLVM doesn't seem to do much work reordering IFMA + // instructions, so try to organize them into "waves" of 8 + // independent operations (4c latency, 0.5 c throughput + // means 8 in flight) + + // Wave 0 + z4_1 = madd52lo(z4_1, x[2], y[2]); + z5_2 = madd52hi(z5_2, x[2], y[2]); + z5_1 = madd52lo(z5_1, x[4], y[1]); + z6_2 = madd52hi(z6_2, x[4], y[1]); + z6_1 = madd52lo(z6_1, x[4], y[2]); + z7_2 = madd52hi(z7_2, x[4], y[2]); + z7_1 = madd52lo(z7_1, x[4], y[3]); + z8_2 = madd52hi(z8_2, x[4], y[3]); + + // Wave 1 + z4_1 = madd52lo(z4_1, x[3], y[1]); + z5_2 = madd52hi(z5_2, x[3], y[1]); + z5_1 = madd52lo(z5_1, x[3], y[2]); + z6_2 = madd52hi(z6_2, x[3], y[2]); + z6_1 = madd52lo(z6_1, x[3], y[3]); + z7_2 = madd52hi(z7_2, x[3], y[3]); + z7_1 = madd52lo(z7_1, x[3], y[4]); + z8_2 = madd52hi(z8_2, x[3], y[4]); + + // Wave 2 + z8_1 = madd52lo(z8_1, x[4], y[4]); + z9_2 = madd52hi(z9_2, x[4], y[4]); + z4_1 = madd52lo(z4_1, x[4], y[0]); + z5_2 = madd52hi(z5_2, x[4], y[0]); + z5_1 = madd52lo(z5_1, x[2], y[3]); + z6_2 = madd52hi(z6_2, x[2], y[3]); + z6_1 = madd52lo(z6_1, x[2], y[4]); + z7_2 = madd52hi(z7_2, x[2], y[4]); + + let z8 = z8_1 + z8_2 + z8_2; + let z9 = z9_2 + z9_2; + + // Wave 3 + z3_1 = madd52lo(z3_1, x[3], y[0]); + z4_2 = madd52hi(z4_2, x[3], y[0]); + z4_1 = madd52lo(z4_1, x[1], y[3]); + z5_2 = madd52hi(z5_2, x[1], y[3]); + z5_1 = madd52lo(z5_1, x[1], y[4]); + z6_2 = madd52hi(z6_2, x[1], y[4]); + z2_1 = madd52lo(z2_1, x[2], y[0]); + z3_2 = madd52hi(z3_2, x[2], y[0]); + + let z6 = z6_1 + z6_2 + z6_2; + let z7 = z7_1 + z7_2 + z7_2; + + // Wave 4 + z3_1 = madd52lo(z3_1, x[2], y[1]); + z4_2 = madd52hi(z4_2, x[2], y[1]); + z4_1 = madd52lo(z4_1, x[0], y[4]); + z5_2 = madd52hi(z5_2, x[0], y[4]); + z1_1 = madd52lo(z1_1, x[1], y[0]); + z2_2 = madd52hi(z2_2, x[1], y[0]); + z2_1 = madd52lo(z2_1, x[1], y[1]); + z3_2 = madd52hi(z3_2, x[1], y[1]); + + let z5 = z5_1 + z5_2 + z5_2; + + // Wave 5 + z3_1 = madd52lo(z3_1, x[1], y[2]); + z4_2 = madd52hi(z4_2, x[1], y[2]); + z0_1 = madd52lo(z0_1, x[0], y[0]); + z1_2 = madd52hi(z1_2, x[0], y[0]); + z1_1 = madd52lo(z1_1, x[0], y[1]); + z2_1 = madd52lo(z2_1, x[0], y[2]); + z2_2 = madd52hi(z2_2, x[0], y[1]); + z3_2 = madd52hi(z3_2, x[0], y[2]); + + let mut t0 = u64x4::splat(0); + let mut t1 = u64x4::splat(0); + let r19 = u64x4::splat(19); + + // Wave 6 + t0 = madd52hi(t0, r19, z9); + t1 = madd52lo(t1, r19, z9 >> 52); + z3_1 = madd52lo(z3_1, x[0], y[3]); + z4_2 = madd52hi(z4_2, x[0], y[3]); + z1_2 = madd52lo(z1_2, r19, z5 >> 52); + z2_2 = madd52lo(z2_2, r19, z6 >> 52); + z3_2 = madd52lo(z3_2, r19, z7 >> 52); + z0_1 = madd52lo(z0_1, r19, z5); + + // Wave 7 + z4_1 = madd52lo(z4_1, r19, z9); + z1_1 = madd52lo(z1_1, r19, z6); + z0_2 = madd52lo(z0_2, r19, t0 + t1); + z4_2 = madd52hi(z4_2, r19, z8); + z2_1 = madd52lo(z2_1, r19, z7); + z1_2 = madd52hi(z1_2, r19, z5); + z2_2 = madd52hi(z2_2, r19, z6); + z3_2 = madd52hi(z3_2, r19, z7); + + // Wave 8 + z3_1 = madd52lo(z3_1, r19, z8); + z4_2 = madd52lo(z4_2, r19, z8 >> 52); + + F51x4Unreduced([ + z0_1 + z0_2 + z0_2, + z1_1 + z1_2 + z1_2, + z2_1 + z2_2 + z2_2, + z3_1 + z3_2 + z3_2, + z4_1 + z4_2 + z4_2, + ]) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn vpmadd52luq() { + let x = u64x4::splat(2); + let y = u64x4::splat(3); + let mut z = u64x4::splat(5); + + z = unsafe { madd52lo(z, x, y) }; + + assert_eq!(z, u64x4::splat(5 + 2 * 3)); + } + + #[test] + fn new_split_round_trip_on_reduced_input() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + + let ax4 = F51x4Unreduced::new(&a, &a, &a, &a); + let splits = ax4.split(); + + for i in 0..4 { + assert_eq!(a, splits[i]); + } + } + + #[test] + fn new_split_round_trip_on_unreduced_input() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + // ... but now multiply it by 16 without reducing coeffs + let a16 = FieldElement51([ + a.0[0] << 4, + a.0[1] << 4, + a.0[2] << 4, + a.0[3] << 4, + a.0[4] << 4, + ]); + + let a16x4 = F51x4Unreduced::new(&a16, &a16, &a16, &a16); + let splits = a16x4.split(); + + for i in 0..4 { + assert_eq!(a16, splits[i]); + } + } + + #[test] + fn test_reduction() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + // ... but now multiply it by 128 without reducing coeffs + let abig = FieldElement51([ + a.0[0] << 4, + a.0[1] << 4, + a.0[2] << 4, + a.0[3] << 4, + a.0[4] << 4, + ]); + + let abigx4: F51x4Reduced = F51x4Unreduced::new(&abig, &abig, &abig, &abig).into(); + + let splits = F51x4Unreduced::from(abigx4).split(); + let c = &a * &FieldElement51([(1 << 4), 0, 0, 0, 0]); + + for i in 0..4 { + assert_eq!(c, splits[i]); + } + } + + #[test] + fn mul_matches_serial() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + let b = FieldElement51([98098, 87987897, 0, 1, 0]).invert(); + let c = &a * &b; + + let ax4: F51x4Reduced = F51x4Unreduced::new(&a, &a, &a, &a).into(); + let bx4: F51x4Reduced = F51x4Unreduced::new(&b, &b, &b, &b).into(); + let cx4 = &ax4 * &bx4; + + let splits = cx4.split(); + + for i in 0..4 { + assert_eq!(c, splits[i]); + } + } + + #[test] + fn iterated_mul_matches_serial() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + let b = FieldElement51([98098, 87987897, 0, 1, 0]).invert(); + let mut c = &a * &b; + for _i in 0..1024 { + c = &a * &c; + c = &b * &c; + } + + let ax4: F51x4Reduced = F51x4Unreduced::new(&a, &a, &a, &a).into(); + let bx4: F51x4Reduced = F51x4Unreduced::new(&b, &b, &b, &b).into(); + let mut cx4 = &ax4 * &bx4; + for _i in 0..1024 { + cx4 = &ax4 * &F51x4Reduced::from(cx4); + cx4 = &bx4 * &F51x4Reduced::from(cx4); + } + + let splits = cx4.split(); + + for i in 0..4 { + assert_eq!(c, splits[i]); + } + } + + #[test] + fn square_matches_mul() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + + let ax4: F51x4Reduced = F51x4Unreduced::new(&a, &a, &a, &a).into(); + let cx4 = &ax4 * &ax4; + let cx4_sq = ax4.square(); + + let splits = cx4.split(); + let splits_sq = cx4_sq.split(); + + for i in 0..4 { + assert_eq!(splits_sq[i], splits[i]); + } + } + + #[test] + fn iterated_square_matches_serial() { + // Invert a small field element to get a big one + let mut a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + let mut ax4 = F51x4Unreduced::new(&a, &a, &a, &a); + for _j in 0..1024 { + a = a.square(); + ax4 = F51x4Reduced::from(ax4).square(); + + let splits = ax4.split(); + for i in 0..4 { + assert_eq!(a, splits[i]); + } + } + } + + #[test] + fn iterated_u32_mul_matches_serial() { + // Invert a small field element to get a big one + let a = FieldElement51([2438, 24, 243, 0, 0]).invert(); + let b = FieldElement51([121665, 0, 0, 0, 0]); + let mut c = &a * &b; + for _i in 0..1024 { + c = &b * &c; + } + + let ax4 = F51x4Unreduced::new(&a, &a, &a, &a); + let bx4 = (121665u32, 121665u32, 121665u32, 121665u32); + let mut cx4 = &F51x4Reduced::from(ax4) * bx4; + for _i in 0..1024 { + cx4 = &F51x4Reduced::from(cx4) * bx4; + } + + let splits = cx4.split(); + + for i in 0..4 { + assert_eq!(c, splits[i]); + } + } + + #[test] + fn shuffle_AAAA() { + let x0 = FieldElement51::from_bytes(&[0x10; 32]); + let x1 = FieldElement51::from_bytes(&[0x11; 32]); + let x2 = FieldElement51::from_bytes(&[0x12; 32]); + let x3 = FieldElement51::from_bytes(&[0x13; 32]); + + let x = F51x4Unreduced::new(&x0, &x1, &x2, &x3); + + let y = x.shuffle(Shuffle::AAAA); + let splits = y.split(); + + assert_eq!(splits[0], x0); + assert_eq!(splits[1], x0); + assert_eq!(splits[2], x0); + assert_eq!(splits[3], x0); + } + + #[test] + fn blend_AB() { + let x0 = FieldElement51::from_bytes(&[0x10; 32]); + let x1 = FieldElement51::from_bytes(&[0x11; 32]); + let x2 = FieldElement51::from_bytes(&[0x12; 32]); + let x3 = FieldElement51::from_bytes(&[0x13; 32]); + + let x = F51x4Unreduced::new(&x0, &x1, &x2, &x3); + let z = F51x4Unreduced::new(&x3, &x2, &x1, &x0); + + let y = x.blend(&z, Lanes::AB); + let splits = y.split(); + + assert_eq!(splits[0], x3); + assert_eq!(splits[1], x2); + assert_eq!(splits[2], x2); + assert_eq!(splits[3], x3); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/mod.rs new file mode 100644 index 0000000..6191ecc --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/ifma/mod.rs @@ -0,0 +1,19 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2018-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +#![cfg_attr( + feature = "nightly", + doc(include = "../../../../docs/ifma-notes.md") +)] + +pub mod field; + +pub mod edwards; + +pub mod constants; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/mod.rs new file mode 100644 index 0000000..29a6f65 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/mod.rs @@ -0,0 +1,43 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +// Conditionally include the notes if we're on nightly (so we can include docs at all). +#![cfg_attr( + feature = "nightly", + doc(include = "../../../docs/parallel-formulas.md") +)] + +#[cfg(not(any(target_feature = "avx2", target_feature = "avx512ifma", rustdoc)))] +compile_error!("simd_backend selected without target_feature=+avx2 or +avx512ifma"); + +#[cfg(any( + all(target_feature = "avx2", not(target_feature = "avx512ifma")), + rustdoc +))] +#[doc(cfg(all(target_feature = "avx2", not(target_feature = "avx512ifma"))))] +pub mod avx2; +#[cfg(any( + all(target_feature = "avx2", not(target_feature = "avx512ifma")), + rustdoc +))] +pub(crate) use self::avx2::{ + constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, +}; + +#[cfg(any(target_feature = "avx512ifma", rustdoc))] +#[doc(cfg(target_feature = "avx512ifma"))] +pub mod ifma; +#[cfg(target_feature = "avx512ifma")] +pub(crate) use self::ifma::{ + constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, +}; + +pub mod scalar_mul; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/mod.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/mod.rs new file mode 100644 index 0000000..36a7047 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/mod.rs @@ -0,0 +1,23 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +pub mod variable_base; + +pub mod vartime_double_base; + +#[cfg(feature = "alloc")] +pub mod straus; + +#[cfg(feature = "alloc")] +pub mod precomputed_straus; + +#[cfg(feature = "alloc")] +pub mod pippenger; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs new file mode 100644 index 0000000..7f9e241 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs @@ -0,0 +1,164 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Oleg Andreev +// See LICENSE for licensing information. +// +// Authors: +// - Oleg Andreev + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use backend::vector::{CachedPoint, ExtendedPoint}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::{Identity, VartimeMultiscalarMul}; + +#[allow(unused_imports)] +use prelude::*; + +/// Implements a version of Pippenger's algorithm. +/// +/// See the documentation in the serial `scalar_mul::pippenger` module for details. +pub struct Pippenger; + +#[cfg(any(feature = "alloc", feature = "std"))] +impl VartimeMultiscalarMul for Pippenger { + type Point = EdwardsPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + let mut scalars = scalars.into_iter(); + let size = scalars.by_ref().size_hint().0; + let w = if size < 500 { + 6 + } else if size < 800 { + 7 + } else { + 8 + }; + + let max_digit: usize = 1 << w; + let digits_count: usize = Scalar::to_radix_2w_size_hint(w); + let buckets_count: usize = max_digit / 2; // digits are signed+centered hence 2^w/2, excluding 0-th bucket + + // Collect optimized scalars and points in a buffer for repeated access + // (scanning the whole collection per each digit position). + let scalars = scalars + .into_iter() + .map(|s| s.borrow().to_radix_2w(w)); + + let points = points + .into_iter() + .map(|p| p.map(|P| CachedPoint::from(ExtendedPoint::from(P)))); + + let scalars_points = scalars + .zip(points) + .map(|(s, maybe_p)| maybe_p.map(|p| (s, p))) + .collect::>>()?; + + // Prepare 2^w/2 buckets. + // buckets[i] corresponds to a multiplication factor (i+1). + let mut buckets: Vec = (0..buckets_count) + .map(|_| ExtendedPoint::identity()) + .collect(); + + let mut columns = (0..digits_count).rev().map(|digit_index| { + // Clear the buckets when processing another digit. + for i in 0..buckets_count { + buckets[i] = ExtendedPoint::identity(); + } + + // Iterate over pairs of (point, scalar) + // and add/sub the point to the corresponding bucket. + // Note: if we add support for precomputed lookup tables, + // we'll be adding/subtractiong point premultiplied by `digits[i]` to buckets[0]. + for (digits, pt) in scalars_points.iter() { + // Widen digit so that we don't run into edge cases when w=8. + let digit = digits[digit_index] as i16; + if digit > 0 { + let b = (digit - 1) as usize; + buckets[b] = &buckets[b] + pt; + } else if digit < 0 { + let b = (-digit - 1) as usize; + buckets[b] = &buckets[b] - pt; + } + } + + // Add the buckets applying the multiplication factor to each bucket. + // The most efficient way to do that is to have a single sum with two running sums: + // an intermediate sum from last bucket to the first, and a sum of intermediate sums. + // + // For example, to add buckets 1*A, 2*B, 3*C we need to add these points: + // C + // C B + // C B A Sum = C + (C+B) + (C+B+A) + let mut buckets_intermediate_sum = buckets[buckets_count - 1]; + let mut buckets_sum = buckets[buckets_count - 1]; + for i in (0..(buckets_count - 1)).rev() { + buckets_intermediate_sum = + &buckets_intermediate_sum + &CachedPoint::from(buckets[i]); + buckets_sum = &buckets_sum + &CachedPoint::from(buckets_intermediate_sum); + } + + buckets_sum + }); + + // Take the high column as an initial value to avoid wasting time doubling the identity element in `fold()`. + // `unwrap()` always succeeds because we know we have more than zero digits. + let hi_column = columns.next().unwrap(); + + Some( + columns + .fold(hi_column, |total, p| { + &total.mul_by_pow_2(w as u32) + &CachedPoint::from(p) + }) + .into(), + ) + } +} + +#[cfg(test)] +mod test { + use super::*; + use constants; + use scalar::Scalar; + + #[test] + fn test_vartime_pippenger() { + // Reuse points across different tests + let mut n = 512; + let x = Scalar::from(2128506u64).invert(); + let y = Scalar::from(4443282u64).invert(); + let points: Vec<_> = (0..n) + .map(|i| constants::ED25519_BASEPOINT_POINT * Scalar::from(1 + i as u64)) + .collect(); + let scalars: Vec<_> = (0..n) + .map(|i| x + (Scalar::from(i as u64) * y)) // fast way to make ~random but deterministic scalars + .collect(); + + let premultiplied: Vec = scalars + .iter() + .zip(points.iter()) + .map(|(sc, pt)| sc * pt) + .collect(); + + while n > 0 { + let scalars = &scalars[0..n].to_vec(); + let points = &points[0..n].to_vec(); + let control: EdwardsPoint = premultiplied[0..n].iter().sum(); + + let subject = Pippenger::vartime_multiscalar_mul(scalars.clone(), points.clone()); + + assert_eq!(subject.compress(), control.compress()); + + n = n / 2; + } + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs new file mode 100644 index 0000000..2c6fdf5 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -0,0 +1,107 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Henry de Valence. +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +//! Precomputation for Straus's method. + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use backend::vector::{CachedPoint, ExtendedPoint}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::Identity; +use traits::VartimePrecomputedMultiscalarMul; +use window::{NafLookupTable5, NafLookupTable8}; + +#[allow(unused_imports)] +use prelude::*; + + +pub struct VartimePrecomputedStraus { + static_lookup_tables: Vec>, +} + +impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { + type Point = EdwardsPoint; + + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + Self { + static_lookup_tables: static_points + .into_iter() + .map(|P| NafLookupTable8::::from(P.borrow())) + .collect(), + } + } + + fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator>, + { + let static_nafs = static_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + let dynamic_nafs: Vec<_> = dynamic_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + + let dynamic_lookup_tables = dynamic_points + .into_iter() + .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) + .collect::>>()?; + + let sp = self.static_lookup_tables.len(); + let dp = dynamic_lookup_tables.len(); + assert_eq!(sp, static_nafs.len()); + assert_eq!(dp, dynamic_nafs.len()); + + // We could save some doublings by looking for the highest + // nonzero NAF coefficient, but since we might have a lot of + // them to search, it's not clear it's worthwhile to check. + let mut R = ExtendedPoint::identity(); + for j in (0..256).rev() { + R = R.double(); + + for i in 0..dp { + let t_ij = dynamic_nafs[i][j]; + if t_ij > 0 { + R = &R + &dynamic_lookup_tables[i].select(t_ij as usize); + } else if t_ij < 0 { + R = &R - &dynamic_lookup_tables[i].select(-t_ij as usize); + } + } + + for i in 0..sp { + let t_ij = static_nafs[i][j]; + if t_ij > 0 { + R = &R + &self.static_lookup_tables[i].select(t_ij as usize); + } else if t_ij < 0 { + R = &R - &self.static_lookup_tables[i].select(-t_ij as usize); + } + } + } + + Some(R.into()) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/straus.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/straus.rs new file mode 100644 index 0000000..b6c02f9 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/straus.rs @@ -0,0 +1,108 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use zeroize::Zeroizing; + +use backend::vector::{CachedPoint, ExtendedPoint}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use window::{LookupTable, NafLookupTable5}; +use traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; + +#[allow(unused_imports)] +use prelude::*; + +/// Multiscalar multiplication using interleaved window / Straus' +/// method. See the `Straus` struct in the serial backend for more +/// details. +/// +/// This exists as a seperate implementation from that one because the +/// AVX2 code uses different curve models (it does not pass between +/// multiple models during scalar mul), and it has to convert the +/// point representation on the fly. +pub struct Straus {} + +impl MultiscalarMul for Straus { + type Point = EdwardsPoint; + + fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + { + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + // for each input point P + let lookup_tables: Vec<_> = points + .into_iter() + .map(|point| LookupTable::::from(point.borrow())) + .collect(); + + let scalar_digits_vec: Vec<_> = scalars + .into_iter() + .map(|s| s.borrow().to_radix_16()) + .collect(); + // Pass ownership to a `Zeroizing` wrapper + let scalar_digits = Zeroizing::new(scalar_digits_vec); + + let mut Q = ExtendedPoint::identity(); + for j in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + let it = scalar_digits.iter().zip(lookup_tables.iter()); + for (s_i, lookup_table_i) in it { + // Q = Q + s_{i,j} * P_i + Q = &Q + &lookup_table_i.select(s_i[j]); + } + } + Q.into() + } +} + +impl VartimeMultiscalarMul for Straus { + type Point = EdwardsPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + let nafs: Vec<_> = scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect(); + let lookup_tables: Vec<_> = points + .into_iter() + .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) + .collect::>>()?; + + let mut Q = ExtendedPoint::identity(); + + for i in (0..256).rev() { + Q = Q.double(); + + for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) { + if naf[i] > 0 { + Q = &Q + &lookup_table.select(naf[i] as usize); + } else if naf[i] < 0 { + Q = &Q - &lookup_table.select(-naf[i] as usize); + } + } + } + + Some(Q.into()) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/variable_base.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/variable_base.rs new file mode 100644 index 0000000..f53c4a0 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/variable_base.rs @@ -0,0 +1,32 @@ +#![allow(non_snake_case)] + +use backend::vector::{CachedPoint, ExtendedPoint}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::Identity; +use window::LookupTable; + +/// Perform constant-time, variable-base scalar multiplication. +pub fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + let lookup_table = LookupTable::::from(point); + // Setting s = scalar, compute + // + // s = s_0 + s_1*16^1 + ... + s_63*16^63, + // + // with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`. + let scalar_digits = scalar.to_radix_16(); + // Compute s*P as + // + // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) + // s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63 + // s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...)) + // + // We sum right-to-left. + let mut Q = ExtendedPoint::identity(); + for i in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + Q = &Q + &lookup_table.select(scalar_digits[i]); + } + Q.into() +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/vartime_double_base.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/vartime_double_base.rs new file mode 100644 index 0000000..3f7cc3e --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/backend/vector/scalar_mul/vartime_double_base.rs @@ -0,0 +1,62 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +#![allow(non_snake_case)] + +use backend::vector::BASEPOINT_ODD_LOOKUP_TABLE; +use backend::vector::{CachedPoint, ExtendedPoint}; +use edwards::EdwardsPoint; +use scalar::Scalar; +use traits::Identity; +use window::NafLookupTable5; + +/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. +pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { + let a_naf = a.non_adjacent_form(5); + let b_naf = b.non_adjacent_form(8); + + // Find starting index + let mut i: usize = 255; + for j in (0..256).rev() { + i = j; + if a_naf[i] != 0 || b_naf[i] != 0 { + break; + } + } + + let table_A = NafLookupTable5::::from(A); + let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; + + let mut Q = ExtendedPoint::identity(); + + loop { + Q = Q.double(); + + if a_naf[i] > 0 { + Q = &Q + &table_A.select(a_naf[i] as usize); + } else if a_naf[i] < 0 { + Q = &Q - &table_A.select(-a_naf[i] as usize); + } + + if b_naf[i] > 0 { + Q = &Q + &table_B.select(b_naf[i] as usize); + } else if b_naf[i] < 0 { + Q = &Q - &table_B.select(-b_naf[i] as usize); + } + + if i == 0 { + break; + } + i -= 1; + } + + Q.into() +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/constants.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/constants.rs new file mode 100644 index 0000000..19c46e5 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/constants.rs @@ -0,0 +1,181 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Various constants, such as the Ristretto and Ed25519 basepoints. +//! +//! Most of the constants are given with +//! `LONG_DESCRIPTIVE_UPPER_CASE_NAMES`, but they can be brought into +//! scope using a `let` binding: +//! +//! ``` +//! use curve25519_dalek::constants; +//! use curve25519_dalek::traits::IsIdentity; +//! +//! let B = &constants::RISTRETTO_BASEPOINT_TABLE; +//! let l = &constants::BASEPOINT_ORDER; +//! +//! let A = l * B; +//! assert!(A.is_identity()); +//! ``` + +#![allow(non_snake_case)] + +use edwards::CompressedEdwardsY; +use ristretto::RistrettoPoint; +use ristretto::CompressedRistretto; +use montgomery::MontgomeryPoint; +use scalar::Scalar; + +#[cfg(feature = "fiat_u32_backend")] +pub use backend::serial::fiat_u32::constants::*; +#[cfg(feature = "fiat_u64_backend")] +pub use backend::serial::fiat_u64::constants::*; +#[cfg(feature = "u64_backend")] +pub use backend::serial::u64::constants::*; +#[cfg(feature = "u32_backend")] +pub use backend::serial::u32::constants::*; + +/// The Ed25519 basepoint, in `CompressedEdwardsY` format. +/// +/// This is the little-endian byte encoding of \\( 4/5 \pmod p \\), +/// which is the \\(y\\)-coordinate of the Ed25519 basepoint. +/// +/// The sign bit is 0 since the basepoint has \\(x\\) chosen to be positive. +pub const ED25519_BASEPOINT_COMPRESSED: CompressedEdwardsY = + CompressedEdwardsY([0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]); + +/// The X25519 basepoint, in `MontgomeryPoint` format. +pub const X25519_BASEPOINT: MontgomeryPoint = + MontgomeryPoint([0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); + +/// The Ristretto basepoint, in `CompressedRistretto` format. +pub const RISTRETTO_BASEPOINT_COMPRESSED: CompressedRistretto = + CompressedRistretto([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]); + +/// The Ristretto basepoint, as a `RistrettoPoint`. +/// +/// This is called `_POINT` to distinguish it from `_TABLE`, which +/// provides fast scalar multiplication. +pub const RISTRETTO_BASEPOINT_POINT: RistrettoPoint = RistrettoPoint(ED25519_BASEPOINT_POINT); + +/// `BASEPOINT_ORDER` is the order of the Ristretto group and of the Ed25519 basepoint, i.e., +/// $$ +/// \ell = 2^\{252\} + 27742317777372353535851937790883648493. +/// $$ +pub const BASEPOINT_ORDER: Scalar = Scalar{ + bytes: [ + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + ], +}; + +use ristretto::RistrettoBasepointTable; +/// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication. +pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable + = RistrettoBasepointTable(ED25519_BASEPOINT_TABLE); + +#[cfg(test)] +mod test { + use field::FieldElement; + use traits::{IsIdentity, ValidityCheck}; + use constants; + + #[test] + fn test_eight_torsion() { + for i in 0..8 { + let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(3); + assert!(Q.is_valid()); + assert!(Q.is_identity()); + } + } + + #[test] + fn test_four_torsion() { + for i in (0..8).filter(|i| i % 2 == 0) { + let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(2); + assert!(Q.is_valid()); + assert!(Q.is_identity()); + } + } + + #[test] + fn test_two_torsion() { + for i in (0..8).filter(|i| i % 4 == 0) { + let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(1); + assert!(Q.is_valid()); + assert!(Q.is_identity()); + } + } + + /// Test that SQRT_M1 is the positive square root of -1 + #[test] + fn test_sqrt_minus_one() { + let minus_one = FieldElement::minus_one(); + let sqrt_m1_sq = &constants::SQRT_M1 * &constants::SQRT_M1; + assert_eq!(minus_one, sqrt_m1_sq); + assert_eq!(constants::SQRT_M1.is_negative().unwrap_u8(), 0); + } + + #[test] + fn test_sqrt_constants_sign() { + let minus_one = FieldElement::minus_one(); + let (was_nonzero_square, invsqrt_m1) = minus_one.invsqrt(); + assert_eq!(was_nonzero_square.unwrap_u8(), 1u8); + let sign_test_sqrt = &invsqrt_m1 * &constants::SQRT_M1; + assert_eq!(sign_test_sqrt, minus_one); + } + + /// Test that d = -121665/121666 + #[test] + #[cfg(feature = "u32_backend")] + fn test_d_vs_ratio() { + use backend::serial::u32::field::FieldElement2625; + let a = -&FieldElement2625([121665,0,0,0,0,0,0,0,0,0]); + let b = FieldElement2625([121666,0,0,0,0,0,0,0,0,0]); + let d = &a * &b.invert(); + let d2 = &d + &d; + assert_eq!(d, constants::EDWARDS_D); + assert_eq!(d2, constants::EDWARDS_D2); + } + + /// Test that d = -121665/121666 + #[test] + #[cfg(feature = "u64_backend")] + fn test_d_vs_ratio() { + use backend::serial::u64::field::FieldElement51; + let a = -&FieldElement51([121665,0,0,0,0]); + let b = FieldElement51([121666,0,0,0,0]); + let d = &a * &b.invert(); + let d2 = &d + &d; + assert_eq!(d, constants::EDWARDS_D); + assert_eq!(d2, constants::EDWARDS_D2); + } + + #[test] + fn test_sqrt_ad_minus_one() { + let a = FieldElement::minus_one(); + let ad_minus_one = &(&a * &constants::EDWARDS_D) + &a; + let should_be_ad_minus_one = constants::SQRT_AD_MINUS_ONE.square(); + assert_eq!(should_be_ad_minus_one, ad_minus_one); + } + +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/edwards.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/edwards.rs new file mode 100644 index 0000000..7c97ca4 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/edwards.rs @@ -0,0 +1,1699 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2020 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Group operations for Curve25519, in Edwards form. +//! +//! ## Encoding and Decoding +//! +//! Encoding is done by converting to and from a `CompressedEdwardsY` +//! struct, which is a typed wrapper around `[u8; 32]`. +//! +//! ## Equality Testing +//! +//! The `EdwardsPoint` struct implements the `subtle::ConstantTimeEq` +//! trait for constant-time equality checking, and the Rust `Eq` trait +//! for variable-time equality checking. +//! +//! ## Cofactor-related functions +//! +//! The order of the group of points on the curve \\(\mathcal E\\) +//! is \\(|\mathcal E| = 8\ell \\), so its structure is \\( \mathcal +//! E = \mathcal E[8] \times \mathcal E[\ell]\\). The torsion +//! subgroup \\( \mathcal E[8] \\) consists of eight points of small +//! order. Technically, all of \\(\mathcal E\\) is torsion, but we +//! use the word only to refer to the small \\(\mathcal E[8]\\) part, not +//! the large prime-order \\(\mathcal E[\ell]\\) part. +//! +//! To test if a point is in \\( \mathcal E[8] \\), use +//! `EdwardsPoint::is_small_order()`. +//! +//! To test if a point is in \\( \mathcal E[\ell] \\), use +//! `EdwardsPoint::is_torsion_free()`. +//! +//! To multiply by the cofactor, use `EdwardsPoint::mul_by_cofactor()`. +//! +//! To avoid dealing with cofactors entirely, consider using Ristretto. +//! +//! ## Scalars +//! +//! Scalars are represented by the `Scalar` struct. To construct a scalar with a specific bit +//! pattern, see `Scalar::from_bits()`. +//! +//! ## Scalar Multiplication +//! +//! Scalar multiplication on Edwards points is provided by: +//! +//! * the `*` operator between a `Scalar` and a `EdwardsPoint`, which +//! performs constant-time variable-base scalar multiplication; +//! +//! * the `*` operator between a `Scalar` and a +//! `EdwardsBasepointTable`, which performs constant-time fixed-base +//! scalar multiplication; +//! +//! * an implementation of the +//! [`MultiscalarMul`](../traits/trait.MultiscalarMul.html) trait for +//! constant-time variable-base multiscalar multiplication; +//! +//! * an implementation of the +//! [`VartimeMultiscalarMul`](../traits/trait.VartimeMultiscalarMul.html) +//! trait for variable-time variable-base multiscalar multiplication; +//! +//! ## Implementation +//! +//! The Edwards arithmetic is implemented using the “extended twisted +//! coordinates” of Hisil, Wong, Carter, and Dawson, and the +//! corresponding complete formulas. For more details, +//! see the [`curve_models` submodule][curve_models] +//! of the internal documentation. +//! +//! ## Validity Checking +//! +//! There is no function for checking whether a point is valid. +//! Instead, the `EdwardsPoint` struct is guaranteed to hold a valid +//! point on the curve. +//! +//! We use the Rust type system to make invalid points +//! unrepresentable: `EdwardsPoint` objects can only be created via +//! successful decompression of a compressed point, or else by +//! operations on other (valid) `EdwardsPoint`s. +//! +//! [curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/backend/serial/curve_models/index.html + +// We allow non snake_case names because coordinates in projective space are +// traditionally denoted by the capitalisation of their respective +// counterparts in affine space. Yeah, you heard me, rustc, I'm gonna have my +// affine and projective cakes and eat both of them too. +#![allow(non_snake_case)] + +use core::borrow::Borrow; +use core::fmt::Debug; +use core::iter::Iterator; +use core::iter::Sum; +use core::ops::{Add, Neg, Sub}; +use core::ops::{AddAssign, SubAssign}; +use core::ops::{Mul, MulAssign}; + +use subtle::Choice; +use subtle::ConditionallyNegatable; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; + +use constants; + +use field::FieldElement; +use scalar::Scalar; + +use montgomery::MontgomeryPoint; + +use backend::serial::curve_models::AffineNielsPoint; +use backend::serial::curve_models::CompletedPoint; +use backend::serial::curve_models::ProjectiveNielsPoint; +use backend::serial::curve_models::ProjectivePoint; + +use window::LookupTable; +use window::LookupTableRadix16; +use window::LookupTableRadix32; +use window::LookupTableRadix64; +use window::LookupTableRadix128; +use window::LookupTableRadix256; + +#[allow(unused_imports)] +use prelude::*; + +use traits::BasepointTable; +use traits::ValidityCheck; +use traits::{Identity, IsIdentity}; + +#[cfg(any(feature = "alloc", feature = "std"))] +use traits::MultiscalarMul; +#[cfg(any(feature = "alloc", feature = "std"))] +use traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; + +#[cfg(not(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +)))] +use backend::serial::scalar_mul; +#[cfg(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +))] +use backend::vector::scalar_mul; + +// ------------------------------------------------------------------------ +// Compressed points +// ------------------------------------------------------------------------ + +/// In "Edwards y" / "Ed25519" format, the curve point \\((x,y)\\) is +/// determined by the \\(y\\)-coordinate and the sign of \\(x\\). +/// +/// The first 255 bits of a `CompressedEdwardsY` represent the +/// \\(y\\)-coordinate. The high bit of the 32nd byte gives the sign of \\(x\\). +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct CompressedEdwardsY(pub [u8; 32]); + +impl ConstantTimeEq for CompressedEdwardsY { + fn ct_eq(&self, other: &CompressedEdwardsY) -> Choice { + self.as_bytes().ct_eq(other.as_bytes()) + } +} + +impl Debug for CompressedEdwardsY { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "CompressedEdwardsY: {:?}", self.as_bytes()) + } +} + +impl CompressedEdwardsY { + /// View this `CompressedEdwardsY` as an array of bytes. + pub fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } + + /// Copy this `CompressedEdwardsY` to an array of bytes. + pub fn to_bytes(&self) -> [u8; 32] { + self.0 + } + + /// Attempt to decompress to an `EdwardsPoint`. + /// + /// Returns `None` if the input is not the \\(y\\)-coordinate of a + /// curve point. + pub fn decompress(&self) -> Option { + let Y = FieldElement::from_bytes(self.as_bytes()); + let Z = FieldElement::one(); + let YY = Y.square(); + let u = &YY - &Z; // u = y²-1 + let v = &(&YY * &constants::EDWARDS_D) + &Z; // v = dy²+1 + let (is_valid_y_coord, mut X) = FieldElement::sqrt_ratio_i(&u, &v); + + if is_valid_y_coord.unwrap_u8() != 1u8 { return None; } + + // FieldElement::sqrt_ratio_i always returns the nonnegative square root, + // so we negate according to the supplied sign bit. + let compressed_sign_bit = Choice::from(self.as_bytes()[31] >> 7); + X.conditional_negate(compressed_sign_bit); + + Some(EdwardsPoint{ X, Y, Z, T: &X * &Y }) + } +} + +// ------------------------------------------------------------------------ +// Serde support +// ------------------------------------------------------------------------ +// Serializes to and from `EdwardsPoint` directly, doing compression +// and decompression internally. This means that users can create +// structs containing `EdwardsPoint`s and use Serde's derived +// serializers to serialize those structures. + +#[cfg(feature = "serde")] +use serde::{self, Serialize, Deserialize, Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +#[cfg(feature = "serde")] +impl Serialize for EdwardsPoint { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + use serde::ser::SerializeTuple; + let mut tup = serializer.serialize_tuple(32)?; + for byte in self.compress().as_bytes().iter() { + tup.serialize_element(byte)?; + } + tup.end() + } +} + +#[cfg(feature = "serde")] +impl Serialize for CompressedEdwardsY { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + use serde::ser::SerializeTuple; + let mut tup = serializer.serialize_tuple(32)?; + for byte in self.as_bytes().iter() { + tup.serialize_element(byte)?; + } + tup.end() + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for EdwardsPoint { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + struct EdwardsPointVisitor; + + impl<'de> Visitor<'de> for EdwardsPointVisitor { + type Value = EdwardsPoint; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("a valid point in Edwards y + sign format") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de> + { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = seq.next_element()? + .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + CompressedEdwardsY(bytes) + .decompress() + .ok_or(serde::de::Error::custom("decompression failed")) + } + } + + deserializer.deserialize_tuple(32, EdwardsPointVisitor) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for CompressedEdwardsY { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + struct CompressedEdwardsYVisitor; + + impl<'de> Visitor<'de> for CompressedEdwardsYVisitor { + type Value = CompressedEdwardsY; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("32 bytes of data") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de> + { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = seq.next_element()? + .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + Ok(CompressedEdwardsY(bytes)) + } + } + + deserializer.deserialize_tuple(32, CompressedEdwardsYVisitor) + } +} + +// ------------------------------------------------------------------------ +// Internal point representations +// ------------------------------------------------------------------------ + +/// An `EdwardsPoint` represents a point on the Edwards form of Curve25519. +#[derive(Copy, Clone)] +#[allow(missing_docs)] +pub struct EdwardsPoint { + pub(crate) X: FieldElement, + pub(crate) Y: FieldElement, + pub(crate) Z: FieldElement, + pub(crate) T: FieldElement, +} + +// ------------------------------------------------------------------------ +// Constructors +// ------------------------------------------------------------------------ + +impl Identity for CompressedEdwardsY { + fn identity() -> CompressedEdwardsY { + CompressedEdwardsY([1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0]) + } +} + +impl Default for CompressedEdwardsY { + fn default() -> CompressedEdwardsY { + CompressedEdwardsY::identity() + } +} + +impl CompressedEdwardsY { + /// Construct a `CompressedEdwardsY` from a slice of bytes. + /// + /// # Panics + /// + /// If the input `bytes` slice does not have a length of 32. + pub fn from_slice(bytes: &[u8]) -> CompressedEdwardsY { + let mut tmp = [0u8; 32]; + + tmp.copy_from_slice(bytes); + + CompressedEdwardsY(tmp) + } +} + +impl Identity for EdwardsPoint { + fn identity() -> EdwardsPoint { + EdwardsPoint { + X: FieldElement::zero(), + Y: FieldElement::one(), + Z: FieldElement::one(), + T: FieldElement::zero(), + } + } +} + +impl Default for EdwardsPoint { + fn default() -> EdwardsPoint { + EdwardsPoint::identity() + } +} + +// ------------------------------------------------------------------------ +// Validity checks (for debugging, not CT) +// ------------------------------------------------------------------------ + +impl ValidityCheck for EdwardsPoint { + fn is_valid(&self) -> bool { + let point_on_curve = self.to_projective().is_valid(); + let on_segre_image = (&self.X * &self.Y) == (&self.Z * &self.T); + + point_on_curve && on_segre_image + } +} + +// ------------------------------------------------------------------------ +// Constant-time assignment +// ------------------------------------------------------------------------ + +impl ConditionallySelectable for EdwardsPoint { + fn conditional_select(a: &EdwardsPoint, b: &EdwardsPoint, choice: Choice) -> EdwardsPoint { + EdwardsPoint { + X: FieldElement::conditional_select(&a.X, &b.X, choice), + Y: FieldElement::conditional_select(&a.Y, &b.Y, choice), + Z: FieldElement::conditional_select(&a.Z, &b.Z, choice), + T: FieldElement::conditional_select(&a.T, &b.T, choice), + } + } +} + +// ------------------------------------------------------------------------ +// Equality +// ------------------------------------------------------------------------ + +impl ConstantTimeEq for EdwardsPoint { + fn ct_eq(&self, other: &EdwardsPoint) -> Choice { + // We would like to check that the point (X/Z, Y/Z) is equal to + // the point (X'/Z', Y'/Z') without converting into affine + // coordinates (x, y) and (x', y'), which requires two inversions. + // We have that X = xZ and X' = x'Z'. Thus, x = x' is equivalent to + // (xZ)Z' = (x'Z')Z, and similarly for the y-coordinate. + + (&self.X * &other.Z).ct_eq(&(&other.X * &self.Z)) + & (&self.Y * &other.Z).ct_eq(&(&other.Y * &self.Z)) + } +} + +impl PartialEq for EdwardsPoint { + fn eq(&self, other: &EdwardsPoint) -> bool { + self.ct_eq(other).unwrap_u8() == 1u8 + } +} + +impl Eq for EdwardsPoint {} + +// ------------------------------------------------------------------------ +// Point conversions +// ------------------------------------------------------------------------ + +impl EdwardsPoint { + /// Convert to a ProjectiveNielsPoint + pub(crate) fn to_projective_niels(&self) -> ProjectiveNielsPoint { + ProjectiveNielsPoint{ + Y_plus_X: &self.Y + &self.X, + Y_minus_X: &self.Y - &self.X, + Z: self.Z, + T2d: &self.T * &constants::EDWARDS_D2, + } + } + + /// Convert the representation of this point from extended + /// coordinates to projective coordinates. + /// + /// Free. + pub(crate) fn to_projective(&self) -> ProjectivePoint { + ProjectivePoint{ + X: self.X, + Y: self.Y, + Z: self.Z, + } + } + + /// Dehomogenize to a AffineNielsPoint. + /// Mainly for testing. + pub(crate) fn to_affine_niels(&self) -> AffineNielsPoint { + let recip = self.Z.invert(); + let x = &self.X * &recip; + let y = &self.Y * &recip; + let xy2d = &(&x * &y) * &constants::EDWARDS_D2; + AffineNielsPoint{ + y_plus_x: &y + &x, + y_minus_x: &y - &x, + xy2d + } + } + + /// Convert this `EdwardsPoint` on the Edwards model to the + /// corresponding `MontgomeryPoint` on the Montgomery model. + /// + /// This function has one exceptional case; the identity point of + /// the Edwards curve is sent to the 2-torsion point \\((0,0)\\) + /// on the Montgomery curve. + /// + /// Note that this is a one-way conversion, since the Montgomery + /// model does not retain sign information. + pub fn to_montgomery(&self) -> MontgomeryPoint { + // We have u = (1+y)/(1-y) = (Z+Y)/(Z-Y). + // + // The denominator is zero only when y=1, the identity point of + // the Edwards curve. Since 0.invert() = 0, in this case we + // compute the 2-torsion point (0,0). + let U = &self.Z + &self.Y; + let W = &self.Z - &self.Y; + let u = &U * &W.invert(); + MontgomeryPoint(u.to_bytes()) + } + + /// Compress this point to `CompressedEdwardsY` format. + pub fn compress(&self) -> CompressedEdwardsY { + let recip = self.Z.invert(); + let x = &self.X * &recip; + let y = &self.Y * &recip; + let mut s: [u8; 32]; + + s = y.to_bytes(); + s[31] ^= x.is_negative().unwrap_u8() << 7; + CompressedEdwardsY(s) + } +} + +// ------------------------------------------------------------------------ +// Doubling +// ------------------------------------------------------------------------ + +impl EdwardsPoint { + /// Add this point to itself. + pub(crate) fn double(&self) -> EdwardsPoint { + self.to_projective().double().to_extended() + } +} + +// ------------------------------------------------------------------------ +// Addition and Subtraction +// ------------------------------------------------------------------------ + +impl<'a, 'b> Add<&'b EdwardsPoint> for &'a EdwardsPoint { + type Output = EdwardsPoint; + fn add(self, other: &'b EdwardsPoint) -> EdwardsPoint { + (self + &other.to_projective_niels()).to_extended() + } +} + +define_add_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint, Output = EdwardsPoint); + +impl<'b> AddAssign<&'b EdwardsPoint> for EdwardsPoint { + fn add_assign(&mut self, _rhs: &'b EdwardsPoint) { + *self = (self as &EdwardsPoint) + _rhs; + } +} + +define_add_assign_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint); + +impl<'a, 'b> Sub<&'b EdwardsPoint> for &'a EdwardsPoint { + type Output = EdwardsPoint; + fn sub(self, other: &'b EdwardsPoint) -> EdwardsPoint { + (self - &other.to_projective_niels()).to_extended() + } +} + +define_sub_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint, Output = EdwardsPoint); + +impl<'b> SubAssign<&'b EdwardsPoint> for EdwardsPoint { + fn sub_assign(&mut self, _rhs: &'b EdwardsPoint) { + *self = (self as &EdwardsPoint) - _rhs; + } +} + +define_sub_assign_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint); + +impl Sum for EdwardsPoint +where + T: Borrow +{ + fn sum(iter: I) -> Self + where + I: Iterator + { + iter.fold(EdwardsPoint::identity(), |acc, item| acc + item.borrow()) + } +} + + +// ------------------------------------------------------------------------ +// Negation +// ------------------------------------------------------------------------ + +impl<'a> Neg for &'a EdwardsPoint { + type Output = EdwardsPoint; + + fn neg(self) -> EdwardsPoint { + EdwardsPoint{ + X: -(&self.X), + Y: self.Y, + Z: self.Z, + T: -(&self.T), + } + } +} + +impl Neg for EdwardsPoint { + type Output = EdwardsPoint; + + fn neg(self) -> EdwardsPoint { + -&self + } +} + +// ------------------------------------------------------------------------ +// Scalar multiplication +// ------------------------------------------------------------------------ + +impl<'b> MulAssign<&'b Scalar> for EdwardsPoint { + fn mul_assign(&mut self, scalar: &'b Scalar) { + let result = (self as &EdwardsPoint) * scalar; + *self = result; + } +} + +define_mul_assign_variants!(LHS = EdwardsPoint, RHS = Scalar); + +define_mul_variants!(LHS = EdwardsPoint, RHS = Scalar, Output = EdwardsPoint); +define_mul_variants!(LHS = Scalar, RHS = EdwardsPoint, Output = EdwardsPoint); + +impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsPoint { + type Output = EdwardsPoint; + /// Scalar multiplication: compute `scalar * self`. + /// + /// For scalar multiplication of a basepoint, + /// `EdwardsBasepointTable` is approximately 4x faster. + fn mul(self, scalar: &'b Scalar) -> EdwardsPoint { + scalar_mul::variable_base::mul(self, scalar) + } +} + +impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar { + type Output = EdwardsPoint; + + /// Scalar multiplication: compute `scalar * self`. + /// + /// For scalar multiplication of a basepoint, + /// `EdwardsBasepointTable` is approximately 4x faster. + fn mul(self, point: &'b EdwardsPoint) -> EdwardsPoint { + point * self + } +} + +// ------------------------------------------------------------------------ +// Multiscalar Multiplication impls +// ------------------------------------------------------------------------ + +// These use the iterator's size hint and the target settings to +// forward to a specific backend implementation. + +#[cfg(feature = "alloc")] +impl MultiscalarMul for EdwardsPoint { + type Point = EdwardsPoint; + + fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + { + // Sanity-check lengths of input iterators + let mut scalars = scalars.into_iter(); + let mut points = points.into_iter(); + + // Lower and upper bounds on iterators + let (s_lo, s_hi) = scalars.by_ref().size_hint(); + let (p_lo, p_hi) = points.by_ref().size_hint(); + + // They should all be equal + assert_eq!(s_lo, p_lo); + assert_eq!(s_hi, Some(s_lo)); + assert_eq!(p_hi, Some(p_lo)); + + // Now we know there's a single size. When we do + // size-dependent algorithm dispatch, use this as the hint. + let _size = s_lo; + + scalar_mul::straus::Straus::multiscalar_mul(scalars, points) + } +} + +#[cfg(feature = "alloc")] +impl VartimeMultiscalarMul for EdwardsPoint { + type Point = EdwardsPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + // Sanity-check lengths of input iterators + let mut scalars = scalars.into_iter(); + let mut points = points.into_iter(); + + // Lower and upper bounds on iterators + let (s_lo, s_hi) = scalars.by_ref().size_hint(); + let (p_lo, p_hi) = points.by_ref().size_hint(); + + // They should all be equal + assert_eq!(s_lo, p_lo); + assert_eq!(s_hi, Some(s_lo)); + assert_eq!(p_hi, Some(p_lo)); + + // Now we know there's a single size. + // Use this as the hint to decide which algorithm to use. + let size = s_lo; + + if size < 190 { + scalar_mul::straus::Straus::optional_multiscalar_mul(scalars, points) + } else { + scalar_mul::pippenger::Pippenger::optional_multiscalar_mul(scalars, points) + } + } +} + +/// Precomputation for variable-time multiscalar multiplication with `EdwardsPoint`s. +// This wraps the inner implementation in a facade type so that we can +// decouple stability of the inner type from the stability of the +// outer type. +#[cfg(feature = "alloc")] +pub struct VartimeEdwardsPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); + +#[cfg(feature = "alloc")] +impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation { + type Point = EdwardsPoint; + + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + Self(scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points)) + } + + fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator>, + { + self.0 + .optional_mixed_multiscalar_mul(static_scalars, dynamic_scalars, dynamic_points) + } +} + +impl EdwardsPoint { + /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. + pub fn vartime_double_scalar_mul_basepoint( + a: &Scalar, + A: &EdwardsPoint, + b: &Scalar, + ) -> EdwardsPoint { + scalar_mul::vartime_double_base::mul(a, A, b) + } +} + +macro_rules! impl_basepoint_table { + (Name = $name:ident, LookupTable = $table:ident, Point = $point:ty, Radix = $radix:expr, Additions = $adds:expr) => { + +/// A precomputed table of multiples of a basepoint, for accelerating +/// fixed-base scalar multiplication. One table, for the Ed25519 +/// basepoint, is provided in the `constants` module. +/// +/// The basepoint tables are reasonably large, so they should probably be boxed. +/// +/// The sizes for the tables and the number of additions required for one scalar +/// multiplication are as follows: +/// +/// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A +/// (this is the default size, and is used for [`ED25519_BASEPOINT_TABLE`]) +/// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A +/// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A +/// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A +/// +/// # Why 33 additions for radix-256? +/// +/// Normally, the radix-256 tables would allow for only 32 additions per scalar +/// multiplication. However, due to the fact that standardised definitions of +/// legacy protocols—such as x25519—require allowing unreduced 255-bit scalar +/// invariants, when converting such an unreduced scalar's representation to +/// radix-\\(2^{8}\\), we cannot guarantee the carry bit will fit in the last +/// coefficient (the coefficients are `i8`s). When, \\(w\\), the power-of-2 of +/// the radix, is \\(w < 8\\), we can fold the final carry onto the last +/// coefficient, \\(d\\), because \\(d < 2^{w/2}\\), so +/// $$ +/// d + carry \cdot 2^{w} = d + 1 \cdot 2^{w} < 2^{w+1} < 2^{8} +/// $$ +/// When \\(w = 8\\), we can't fit \\(carry \cdot 2^{w}\\) into an `i8`, so we +/// add the carry bit onto an additional coefficient. +#[derive(Clone)] +pub struct $name(pub(crate) [$table; 32]); + +impl BasepointTable for $name { + type Point = $point; + + /// Create a table of precomputed multiples of `basepoint`. + fn create(basepoint: &$point) -> $name { + // XXX use init_with + let mut table = $name([$table::default(); 32]); + let mut P = *basepoint; + for i in 0..32 { + // P = (2w)^i * B + table.0[i] = $table::from(&P); + P = P.mul_by_pow_2($radix + $radix); + } + table + } + + /// Get the basepoint for this table as an `EdwardsPoint`. + fn basepoint(&self) -> $point { + // self.0[0].select(1) = 1*(16^2)^0*B + // but as an `AffineNielsPoint`, so add identity to convert to extended. + (&<$point>::identity() + &self.0[0].select(1)).to_extended() + } + + /// The computation uses Pippeneger's algorithm, as described for the + /// specific case of radix-16 on page 13 of the Ed25519 paper. + /// + /// # Piggenger's Algorithm Generalised + /// + /// Write the scalar \\(a\\) in radix-\\(w\\), where \\(w\\) is a power of + /// 2, with coefficients in \\([\frac{-w}{2},\frac{w}{2})\\), i.e., + /// $$ + /// a = a\_0 + a\_1 w\^1 + \cdots + a\_{x} w\^{x}, + /// $$ + /// with + /// $$ + /// \frac{-w}{2} \leq a_i < \frac{w}{2}, \cdots, \frac{-w}{2} \leq a\_{x} \leq \frac{w}{2} + /// $$ + /// and the number of additions, \\(x\\), is given by \\(x = \lceil \frac{256}{w} \rceil\\). + /// Then + /// $$ + /// a B = a\_0 B + a\_1 w\^1 B + \cdots + a\_{x-1} w\^{x-1} B. + /// $$ + /// Grouping even and odd coefficients gives + /// $$ + /// \begin{aligned} + /// a B = \quad a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B \\\\ + /// + a\_1 w\^1 B +& a\_3 w\^3 B + \cdots + a\_{x-1} w\^{x-1} B \\\\ + /// = \quad(a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B) \\\\ + /// + w(a\_1 w\^0 B +& a\_3 w\^2 B + \cdots + a\_{x-1} w\^{x-2} B). \\\\ + /// \end{aligned} + /// $$ + /// For each \\(i = 0 \ldots 31\\), we create a lookup table of + /// $$ + /// [w\^{2i} B, \ldots, \frac{w}{2}\cdotw\^{2i} B], + /// $$ + /// and use it to select \\( y \cdot w\^{2i} \cdot B \\) in constant time. + /// + /// The radix-\\(w\\) representation requires that the scalar is bounded + /// by \\(2\^{255}\\), which is always the case. + /// + /// The above algorithm is trivially generalised to other powers-of-2 radices. + fn basepoint_mul(&self, scalar: &Scalar) -> $point { + let a = scalar.to_radix_2w($radix); + + let tables = &self.0; + let mut P = <$point>::identity(); + + for i in (0..$adds).filter(|x| x % 2 == 1) { + P = (&P + &tables[i/2].select(a[i])).to_extended(); + } + + P = P.mul_by_pow_2($radix); + + for i in (0..$adds).filter(|x| x % 2 == 0) { + P = (&P + &tables[i/2].select(a[i])).to_extended(); + } + + P + } +} + +impl<'a, 'b> Mul<&'b Scalar> for &'a $name { + type Output = $point; + + /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by + /// computing the multiple \\(aB\\) of this basepoint \\(B\\). + fn mul(self, scalar: &'b Scalar) -> $point { + // delegate to a private function so that its documentation appears in internal docs + self.basepoint_mul(scalar) + } +} + +impl<'a, 'b> Mul<&'a $name> for &'b Scalar { + type Output = $point; + + /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by + /// computing the multiple \\(aB\\) of this basepoint \\(B\\). + fn mul(self, basepoint_table: &'a $name) -> $point { + basepoint_table * self + } +} + +impl Debug for $name { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{:?}([\n", stringify!($name))?; + for i in 0..32 { + write!(f, "\t{:?},\n", &self.0[i])?; + } + write!(f, "])") + } +} + +}} // End macro_rules! impl_basepoint_table + +// The number of additions required is ceil(256/w) where w is the radix representation. +impl_basepoint_table! {Name = EdwardsBasepointTableRadix16, LookupTable = LookupTableRadix16, Point = EdwardsPoint, Radix = 4, Additions = 64} +impl_basepoint_table! {Name = EdwardsBasepointTableRadix32, LookupTable = LookupTableRadix32, Point = EdwardsPoint, Radix = 5, Additions = 52} +impl_basepoint_table! {Name = EdwardsBasepointTableRadix64, LookupTable = LookupTableRadix64, Point = EdwardsPoint, Radix = 6, Additions = 43} +impl_basepoint_table! {Name = EdwardsBasepointTableRadix128, LookupTable = LookupTableRadix128, Point = EdwardsPoint, Radix = 7, Additions = 37} +impl_basepoint_table! {Name = EdwardsBasepointTableRadix256, LookupTable = LookupTableRadix256, Point = EdwardsPoint, Radix = 8, Additions = 33} + +// ------------------------------------------------------------------------------------- +// BEGIN legacy 3.x series code for backwards compatibility with BasepointTable trait +// ------------------------------------------------------------------------------------- + +/// A precomputed table of multiples of a basepoint, for accelerating +/// fixed-base scalar multiplication. One table, for the Ed25519 +/// basepoint, is provided in the `constants` module. +/// +/// The basepoint tables are reasonably large, so they should probably be boxed. +/// +/// The sizes for the tables and the number of additions required for one scalar +/// multiplication are as follows: +/// +/// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A +/// (this is the default size, and is used for [`ED25519_BASEPOINT_TABLE`]) +/// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A +/// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A +/// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A +/// +/// # Why 33 additions for radix-256? +/// +/// Normally, the radix-256 tables would allow for only 32 additions per scalar +/// multiplication. However, due to the fact that standardised definitions of +/// legacy protocols—such as x25519—require allowing unreduced 255-bit scalar +/// invariants, when converting such an unreduced scalar's representation to +/// radix-\\(2^{8}\\), we cannot guarantee the carry bit will fit in the last +/// coefficient (the coefficients are `i8`s). When, \\(w\\), the power-of-2 of +/// the radix, is \\(w < 8\\), we can fold the final carry onto the last +/// coefficient, \\(d\\), because \\(d < 2^{w/2}\\), so +/// $$ +/// d + carry \cdot 2^{w} = d + 1 \cdot 2^{w} < 2^{w+1} < 2^{8} +/// $$ +/// When \\(w = 8\\), we can't fit \\(carry \cdot 2^{w}\\) into an `i8`, so we +/// add the carry bit onto an additional coefficient. +#[derive(Clone)] +pub struct EdwardsBasepointTable(pub(crate) [LookupTable; 32]); + +impl EdwardsBasepointTable { + /// Create a table of precomputed multiples of `basepoint`. + #[allow(warnings)] + pub fn create(basepoint: &EdwardsPoint) -> EdwardsBasepointTable { + Self(EdwardsBasepointTableRadix16::create(basepoint).0) + } + + /// The computation uses Pippenger's algorithm, as described on + /// page 13 of the Ed25519 paper. Write the scalar \\(a\\) in radix \\(16\\) with + /// coefficients in \\([-8,8)\\), i.e., + /// $$ + /// a = a\_0 + a\_1 16\^1 + \cdots + a\_{63} 16\^{63}, + /// $$ + /// with \\(-8 \leq a_i < 8\\), \\(-8 \leq a\_{63} \leq 8\\). Then + /// $$ + /// a B = a\_0 B + a\_1 16\^1 B + \cdots + a\_{63} 16\^{63} B. + /// $$ + /// Grouping even and odd coefficients gives + /// $$ + /// \begin{aligned} + /// a B = \quad a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B \\\\ + /// + a\_1 16\^1 B +& a\_3 16\^3 B + \cdots + a\_{63} 16\^{63} B \\\\ + /// = \quad(a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B) \\\\ + /// + 16(a\_1 16\^0 B +& a\_3 16\^2 B + \cdots + a\_{63} 16\^{62} B). \\\\ + /// \end{aligned} + /// $$ + /// For each \\(i = 0 \ldots 31\\), we create a lookup table of + /// $$ + /// [16\^{2i} B, \ldots, 8\cdot16\^{2i} B], + /// $$ + /// and use it to select \\( x \cdot 16\^{2i} \cdot B \\) in constant time. + /// + /// The radix-\\(16\\) representation requires that the scalar is bounded + /// by \\(2\^{255}\\), which is always the case. + #[allow(warnings)] + pub fn basepoint_mul(&self, scalar: &Scalar) -> EdwardsPoint { + let a = scalar.to_radix_16(); + + let tables = &self.0; + let mut P = EdwardsPoint::identity(); + + for i in (0..64).filter(|x| x % 2 == 1) { + P = (&P + &tables[i/2].select(a[i])).to_extended(); + } + + P = P.mul_by_pow_2(4); + + for i in (0..64).filter(|x| x % 2 == 0) { + P = (&P + &tables[i/2].select(a[i])).to_extended(); + } + + P + } + + /// Get the basepoint for this table as an `EdwardsPoint`. + #[allow(warnings)] + pub fn basepoint(&self) -> EdwardsPoint { + (&EdwardsPoint::identity() + &self.0[0].select(1)).to_extended() + } +} + +impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable { + type Output = EdwardsPoint; + + /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by + /// computing the multiple \\(aB\\) of this basepoint \\(B\\). + fn mul(self, scalar: &'b Scalar) -> EdwardsPoint { + // delegate to a private function so that its documentation appears in internal docs + self.basepoint_mul(scalar) + } +} + +impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar { + type Output = EdwardsPoint; + + /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by + /// computing the multiple \\(aB\\) of this basepoint \\(B\\). + fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> EdwardsPoint { + basepoint_table * self + } +} + +// ------------------------------------------------------------------------------------- +// END legacy 3.x series code for backwards compatibility with BasepointTable trait +// ------------------------------------------------------------------------------------- + +macro_rules! impl_basepoint_table_conversions { + (LHS = $lhs:ty, RHS = $rhs:ty) => { + impl<'a> From<&'a $lhs> for $rhs { + fn from(table: &'a $lhs) -> $rhs { + <$rhs>::create(&table.basepoint()) + } + } + + impl<'a> From<&'a $rhs> for $lhs { + fn from(table: &'a $rhs) -> $lhs { + <$lhs>::create(&table.basepoint()) + } + } + } +} + +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix32} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix64} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix128} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix256} + +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix64} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix128} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix256} + +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix128} +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix256} + +impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix128, RHS = EdwardsBasepointTableRadix256} + +impl EdwardsPoint { + /// Multiply by the cofactor: return \\([8]P\\). + pub fn mul_by_cofactor(&self) -> EdwardsPoint { + self.mul_by_pow_2(3) + } + + /// Compute \\([2\^k] P \\) by successive doublings. Requires \\( k > 0 \\). + pub(crate) fn mul_by_pow_2(&self, k: u32) -> EdwardsPoint { + debug_assert!( k > 0 ); + let mut r: CompletedPoint; + let mut s = self.to_projective(); + for _ in 0..(k-1) { + r = s.double(); s = r.to_projective(); + } + // Unroll last iteration so we can go directly to_extended() + s.double().to_extended() + } + + /// Determine if this point is of small order. + /// + /// # Return + /// + /// * `true` if `self` is in the torsion subgroup \\( \mathcal E[8] \\); + /// * `false` if `self` is not in the torsion subgroup \\( \mathcal E[8] \\). + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::constants; + /// + /// // Generator of the prime-order subgroup + /// let P = constants::ED25519_BASEPOINT_POINT; + /// // Generator of the torsion subgroup + /// let Q = constants::EIGHT_TORSION[1]; + /// + /// // P has large order + /// assert_eq!(P.is_small_order(), false); + /// + /// // Q has small order + /// assert_eq!(Q.is_small_order(), true); + /// ``` + pub fn is_small_order(&self) -> bool { + self.mul_by_cofactor().is_identity() + } + + /// Determine if this point is “torsion-free”, i.e., is contained in + /// the prime-order subgroup. + /// + /// # Return + /// + /// * `true` if `self` has zero torsion component and is in the + /// prime-order subgroup; + /// * `false` if `self` has a nonzero torsion component and is not + /// in the prime-order subgroup. + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::constants; + /// + /// // Generator of the prime-order subgroup + /// let P = constants::ED25519_BASEPOINT_POINT; + /// // Generator of the torsion subgroup + /// let Q = constants::EIGHT_TORSION[1]; + /// + /// // P is torsion-free + /// assert_eq!(P.is_torsion_free(), true); + /// + /// // P + Q is not torsion-free + /// assert_eq!((P+Q).is_torsion_free(), false); + /// ``` + pub fn is_torsion_free(&self) -> bool { + (self * constants::BASEPOINT_ORDER).is_identity() + } +} + +// ------------------------------------------------------------------------ +// Debug traits +// ------------------------------------------------------------------------ + +impl Debug for EdwardsPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "EdwardsPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", + &self.X, &self.Y, &self.Z, &self.T) + } +} + +// ------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------ + +#[cfg(test)] +mod test { + use field::FieldElement; + use scalar::Scalar; + use subtle::ConditionallySelectable; + use constants; + use super::*; + + /// X coordinate of the basepoint. + /// = 15112221349535400772501151409588531511454012693041857206046113283949847762202 + static BASE_X_COORD_BYTES: [u8; 32] = + [0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, + 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21]; + + /// Compressed Edwards Y form of 2*basepoint. + static BASE2_CMPRSSD: CompressedEdwardsY = + CompressedEdwardsY([0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0xe, + 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97, + 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, + 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22]); + + /// Compressed Edwards Y form of 16*basepoint. + static BASE16_CMPRSSD: CompressedEdwardsY = + CompressedEdwardsY([0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, + 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0, + 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, + 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70]); + + /// 4493907448824000747700850167940867464579944529806937181821189941592931634714 + pub static A_SCALAR: Scalar = Scalar{ + bytes: [ + 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, + 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d, + 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, + 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09, + ], + }; + + /// 2506056684125797857694181776241676200180934651973138769173342316833279714961 + pub static B_SCALAR: Scalar = Scalar{ + bytes: [ + 0x91, 0x26, 0x7a, 0xcf, 0x25, 0xc2, 0x09, 0x1b, + 0xa2, 0x17, 0x74, 0x7b, 0x66, 0xf0, 0xb3, 0x2e, + 0x9d, 0xf2, 0xa5, 0x67, 0x41, 0xcf, 0xda, 0xc4, + 0x56, 0xa7, 0xd4, 0xaa, 0xb8, 0x60, 0x8a, 0x05, + ], + }; + + /// A_SCALAR * basepoint, computed with ed25519.py + pub static A_TIMES_BASEPOINT: CompressedEdwardsY = CompressedEdwardsY([ + 0xea, 0x27, 0xe2, 0x60, 0x53, 0xdf, 0x1b, 0x59, + 0x56, 0xf1, 0x4d, 0x5d, 0xec, 0x3c, 0x34, 0xc3, + 0x84, 0xa2, 0x69, 0xb7, 0x4c, 0xc3, 0x80, 0x3e, + 0xa8, 0xe2, 0xe7, 0xc9, 0x42, 0x5e, 0x40, 0xa5]); + + /// A_SCALAR * (A_TIMES_BASEPOINT) + B_SCALAR * BASEPOINT + /// computed with ed25519.py + static DOUBLE_SCALAR_MULT_RESULT: CompressedEdwardsY = CompressedEdwardsY([ + 0x7d, 0xfd, 0x6c, 0x45, 0xaf, 0x6d, 0x6e, 0x0e, + 0xba, 0x20, 0x37, 0x1a, 0x23, 0x64, 0x59, 0xc4, + 0xc0, 0x46, 0x83, 0x43, 0xde, 0x70, 0x4b, 0x85, + 0x09, 0x6f, 0xfe, 0x35, 0x4f, 0x13, 0x2b, 0x42]); + + /// Test round-trip decompression for the basepoint. + #[test] + fn basepoint_decompression_compression() { + let base_X = FieldElement::from_bytes(&BASE_X_COORD_BYTES); + let bp = constants::ED25519_BASEPOINT_COMPRESSED.decompress().unwrap(); + assert!(bp.is_valid()); + // Check that decompression actually gives the correct X coordinate + assert_eq!(base_X, bp.X); + assert_eq!(bp.compress(), constants::ED25519_BASEPOINT_COMPRESSED); + } + + /// Test sign handling in decompression + #[test] + fn decompression_sign_handling() { + // Manually set the high bit of the last byte to flip the sign + let mut minus_basepoint_bytes = constants::ED25519_BASEPOINT_COMPRESSED.as_bytes().clone(); + minus_basepoint_bytes[31] |= 1 << 7; + let minus_basepoint = CompressedEdwardsY(minus_basepoint_bytes) + .decompress().unwrap(); + // Test projective coordinates exactly since we know they should + // only differ by a flipped sign. + assert_eq!(minus_basepoint.X, -(&constants::ED25519_BASEPOINT_POINT.X)); + assert_eq!(minus_basepoint.Y, constants::ED25519_BASEPOINT_POINT.Y); + assert_eq!(minus_basepoint.Z, constants::ED25519_BASEPOINT_POINT.Z); + assert_eq!(minus_basepoint.T, -(&constants::ED25519_BASEPOINT_POINT.T)); + } + + /// Test that computing 1*basepoint gives the correct basepoint. + #[test] + fn basepoint_mult_one_vs_basepoint() { + let bp = &constants::ED25519_BASEPOINT_TABLE * &Scalar::one(); + let compressed = bp.compress(); + assert_eq!(compressed, constants::ED25519_BASEPOINT_COMPRESSED); + } + + /// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint. + #[test] + fn basepoint_table_basepoint_function_correct() { + let bp = constants::ED25519_BASEPOINT_TABLE.basepoint(); + assert_eq!(bp.compress(), constants::ED25519_BASEPOINT_COMPRESSED); + } + + /// Test `impl Add for EdwardsPoint` + /// using basepoint + basepoint versus the 2*basepoint constant. + #[test] + fn basepoint_plus_basepoint_vs_basepoint2() { + let bp = constants::ED25519_BASEPOINT_POINT; + let bp_added = &bp + &bp; + assert_eq!(bp_added.compress(), BASE2_CMPRSSD); + } + + /// Test `impl Add for EdwardsPoint` + /// using the basepoint, basepoint2 constants + #[test] + fn basepoint_plus_basepoint_projective_niels_vs_basepoint2() { + let bp = constants::ED25519_BASEPOINT_POINT; + let bp_added = (&bp + &bp.to_projective_niels()).to_extended(); + assert_eq!(bp_added.compress(), BASE2_CMPRSSD); + } + + /// Test `impl Add for EdwardsPoint` + /// using the basepoint, basepoint2 constants + #[test] + fn basepoint_plus_basepoint_affine_niels_vs_basepoint2() { + let bp = constants::ED25519_BASEPOINT_POINT; + let bp_affine_niels = bp.to_affine_niels(); + let bp_added = (&bp + &bp_affine_niels).to_extended(); + assert_eq!(bp_added.compress(), BASE2_CMPRSSD); + } + + /// Check that equality of `EdwardsPoints` handles projective + /// coordinates correctly. + #[test] + fn extended_point_equality_handles_scaling() { + let mut two_bytes = [0u8; 32]; two_bytes[0] = 2; + let id1 = EdwardsPoint::identity(); + let id2 = EdwardsPoint{ + X: FieldElement::zero(), + Y: FieldElement::from_bytes(&two_bytes), + Z: FieldElement::from_bytes(&two_bytes), + T: FieldElement::zero() + }; + assert_eq!(id1.ct_eq(&id2).unwrap_u8(), 1u8); + } + + /// Sanity check for conversion to precomputed points + #[test] + fn to_affine_niels_clears_denominators() { + // construct a point as aB so it has denominators (ie. Z != 1) + let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; + let aB_affine_niels = aB.to_affine_niels(); + let also_aB = (&EdwardsPoint::identity() + &aB_affine_niels).to_extended(); + assert_eq!( aB.compress(), + also_aB.compress()); + } + + /// Test basepoint_mult versus a known scalar multiple from ed25519.py + #[test] + fn basepoint_mult_vs_ed25519py() { + let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; + assert_eq!(aB.compress(), A_TIMES_BASEPOINT); + } + + /// Test that multiplication by the basepoint order kills the basepoint + #[test] + fn basepoint_mult_by_basepoint_order() { + let B = &constants::ED25519_BASEPOINT_TABLE; + let should_be_id = B * &constants::BASEPOINT_ORDER; + assert!(should_be_id.is_identity()); + } + + /// Test precomputed basepoint mult + #[test] + fn test_precomputed_basepoint_mult() { + let aB_1 = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; + let aB_2 = &constants::ED25519_BASEPOINT_POINT * &A_SCALAR; + assert_eq!(aB_1.compress(), aB_2.compress()); + } + + /// Test scalar_mul versus a known scalar multiple from ed25519.py + #[test] + fn scalar_mul_vs_ed25519py() { + let aB = &constants::ED25519_BASEPOINT_POINT * &A_SCALAR; + assert_eq!(aB.compress(), A_TIMES_BASEPOINT); + } + + /// Test basepoint.double() versus the 2*basepoint constant. + #[test] + fn basepoint_double_vs_basepoint2() { + assert_eq!(constants::ED25519_BASEPOINT_POINT.double().compress(), + BASE2_CMPRSSD); + } + + /// Test that computing 2*basepoint is the same as basepoint.double() + #[test] + fn basepoint_mult_two_vs_basepoint2() { + let two = Scalar::from(2u64); + let bp2 = &constants::ED25519_BASEPOINT_TABLE * &two; + assert_eq!(bp2.compress(), BASE2_CMPRSSD); + } + + /// Test that all the basepoint table types compute the same results. + #[test] + fn basepoint_tables() { + let P = &constants::ED25519_BASEPOINT_POINT; + let a = A_SCALAR; + + let table_radix16 = EdwardsBasepointTableRadix16::create(&P); + let table_radix32 = EdwardsBasepointTableRadix32::create(&P); + let table_radix64 = EdwardsBasepointTableRadix64::create(&P); + let table_radix128 = EdwardsBasepointTableRadix128::create(&P); + let table_radix256 = EdwardsBasepointTableRadix256::create(&P); + + let aP = (&constants::ED25519_BASEPOINT_TABLE * &a).compress(); + let aP16 = (&table_radix16 * &a).compress(); + let aP32 = (&table_radix32 * &a).compress(); + let aP64 = (&table_radix64 * &a).compress(); + let aP128 = (&table_radix128 * &a).compress(); + let aP256 = (&table_radix256 * &a).compress(); + + assert_eq!(aP, aP16); + assert_eq!(aP16, aP32); + assert_eq!(aP32, aP64); + assert_eq!(aP64, aP128); + assert_eq!(aP128, aP256); + } + + // Check a unreduced scalar multiplication by the basepoint tables. + #[test] + fn basepoint_tables_unreduced_scalar() { + let P = &constants::ED25519_BASEPOINT_POINT; + let a = Scalar::from_bits([ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + ]); + + let table_radix16 = EdwardsBasepointTableRadix16::create(&P); + let table_radix32 = EdwardsBasepointTableRadix32::create(&P); + let table_radix64 = EdwardsBasepointTableRadix64::create(&P); + let table_radix128 = EdwardsBasepointTableRadix128::create(&P); + let table_radix256 = EdwardsBasepointTableRadix256::create(&P); + + let aP = (&constants::ED25519_BASEPOINT_TABLE * &a).compress(); + let aP16 = (&table_radix16 * &a).compress(); + let aP32 = (&table_radix32 * &a).compress(); + let aP64 = (&table_radix64 * &a).compress(); + let aP128 = (&table_radix128 * &a).compress(); + let aP256 = (&table_radix256 * &a).compress(); + + assert_eq!(aP, aP16); + assert_eq!(aP16, aP32); + assert_eq!(aP32, aP64); + assert_eq!(aP64, aP128); + assert_eq!(aP128, aP256); + } + + /// Check that converting to projective and then back to extended round-trips. + #[test] + fn basepoint_projective_extended_round_trip() { + assert_eq!(constants::ED25519_BASEPOINT_POINT + .to_projective().to_extended().compress(), + constants::ED25519_BASEPOINT_COMPRESSED); + } + + /// Test computing 16*basepoint vs mul_by_pow_2(4) + #[test] + fn basepoint16_vs_mul_by_pow_2_4() { + let bp16 = constants::ED25519_BASEPOINT_POINT.mul_by_pow_2(4); + assert_eq!(bp16.compress(), BASE16_CMPRSSD); + } + + #[test] + fn impl_sum() { + + // Test that sum works for non-empty iterators + let BASE = constants::ED25519_BASEPOINT_POINT; + + let s1 = Scalar::from(999u64); + let P1 = &BASE * &s1; + + let s2 = Scalar::from(333u64); + let P2 = &BASE * &s2; + + let vec = vec![P1.clone(), P2.clone()]; + let sum: EdwardsPoint = vec.iter().sum(); + + assert_eq!(sum, P1 + P2); + + // Test that sum works for the empty iterator + let empty_vector: Vec = vec![]; + let sum: EdwardsPoint = empty_vector.iter().sum(); + + assert_eq!(sum, EdwardsPoint::identity()); + + // Test that sum works on owning iterators + let s = Scalar::from(2u64); + let mapped = vec.iter().map(|x| x * s); + let sum: EdwardsPoint = mapped.sum(); + + assert_eq!(sum, &P1 * &s + &P2 * &s); + } + + + /// Test that the conditional assignment trait works for AffineNielsPoints. + #[test] + fn conditional_assign_for_affine_niels_point() { + let id = AffineNielsPoint::identity(); + let mut p1 = AffineNielsPoint::identity(); + let bp = constants::ED25519_BASEPOINT_POINT.to_affine_niels(); + + p1.conditional_assign(&bp, Choice::from(0)); + assert_eq!(p1, id); + p1.conditional_assign(&bp, Choice::from(1)); + assert_eq!(p1, bp); + } + + #[test] + fn is_small_order() { + // The basepoint has large prime order + assert!(!constants::ED25519_BASEPOINT_POINT.is_small_order()); + // constants::EIGHT_TORSION has all points of small order. + for torsion_point in &constants::EIGHT_TORSION { + assert!(torsion_point.is_small_order()); + } + } + + #[test] + fn compressed_identity() { + assert_eq!(EdwardsPoint::identity().compress(), + CompressedEdwardsY::identity()); + } + + #[test] + fn is_identity() { + assert!( EdwardsPoint::identity().is_identity()); + assert!(!constants::ED25519_BASEPOINT_POINT.is_identity()); + } + + /// Rust's debug builds have overflow and underflow trapping, + /// and enable `debug_assert!()`. This performs many scalar + /// multiplications to attempt to trigger possible overflows etc. + /// + /// For instance, the `u64` `Mul` implementation for + /// `FieldElements` requires the input `Limb`s to be bounded by + /// 2^54, but we cannot enforce this dynamically at runtime, or + /// statically at compile time (until Rust gets type-level + /// integers, at which point we can encode "bits of headroom" into + /// the type system and prove correctness). + #[test] + fn monte_carlo_overflow_underflow_debug_assert_test() { + let mut P = constants::ED25519_BASEPOINT_POINT; + // N.B. each scalar_mul does 1407 field mults, 1024 field squarings, + // so this does ~ 1M of each operation. + for _ in 0..1_000 { + P *= &A_SCALAR; + } + } + + #[test] + fn scalarmult_extended_point_works_both_ways() { + let G: EdwardsPoint = constants::ED25519_BASEPOINT_POINT; + let s: Scalar = A_SCALAR; + + let P1 = &G * &s; + let P2 = &s * &G; + + assert!(P1.compress().to_bytes() == P2.compress().to_bytes()); + } + + // A single iteration of a consistency check for MSM. + fn multiscalar_consistency_iter(n: usize) { + use core::iter; + let mut rng = rand::thread_rng(); + + // Construct random coefficients x0, ..., x_{n-1}, + // followed by some extra hardcoded ones. + let xs = (0..n) + .map(|_| Scalar::random(&mut rng)) + // The largest scalar allowed by the type system, 2^255-1 + .chain(iter::once(Scalar::from_bits([0xff; 32]))) + .collect::>(); + let check = xs.iter() + .map(|xi| xi * xi) + .sum::(); + + // Construct points G_i = x_i * B + let Gs = xs.iter() + .map(|xi| xi * &constants::ED25519_BASEPOINT_TABLE) + .collect::>(); + + // Compute H1 = (consttime) + let H1 = EdwardsPoint::multiscalar_mul(&xs, &Gs); + // Compute H2 = (vartime) + let H2 = EdwardsPoint::vartime_multiscalar_mul(&xs, &Gs); + // Compute H3 = = sum(xi^2) * B + let H3 = &check * &constants::ED25519_BASEPOINT_TABLE; + + assert_eq!(H1, H3); + assert_eq!(H2, H3); + } + + // Use different multiscalar sizes to hit different internal + // parameters. + + #[test] + fn multiscalar_consistency_n_100() { + let iters = 50; + for _ in 0..iters { + multiscalar_consistency_iter(100); + } + } + + #[test] + fn multiscalar_consistency_n_250() { + let iters = 50; + for _ in 0..iters { + multiscalar_consistency_iter(250); + } + } + + #[test] + fn multiscalar_consistency_n_500() { + let iters = 50; + for _ in 0..iters { + multiscalar_consistency_iter(500); + } + } + + #[test] + fn multiscalar_consistency_n_1000() { + let iters = 50; + for _ in 0..iters { + multiscalar_consistency_iter(1000); + } + } + + #[test] + fn vartime_precomputed_vs_nonprecomputed_multiscalar() { + let mut rng = rand::thread_rng(); + + let B = &::constants::ED25519_BASEPOINT_TABLE; + + let static_scalars = (0..128) + .map(|_| Scalar::random(&mut rng)) + .collect::>(); + + let dynamic_scalars = (0..128) + .map(|_| Scalar::random(&mut rng)) + .collect::>(); + + let check_scalar: Scalar = static_scalars + .iter() + .chain(dynamic_scalars.iter()) + .map(|s| s * s) + .sum(); + + let static_points = static_scalars.iter().map(|s| s * B).collect::>(); + let dynamic_points = dynamic_scalars.iter().map(|s| s * B).collect::>(); + + let precomputation = VartimeEdwardsPrecomputation::new(static_points.iter()); + + let P = precomputation.vartime_mixed_multiscalar_mul( + &static_scalars, + &dynamic_scalars, + &dynamic_points, + ); + + use traits::VartimeMultiscalarMul; + let Q = EdwardsPoint::vartime_multiscalar_mul( + static_scalars.iter().chain(dynamic_scalars.iter()), + static_points.iter().chain(dynamic_points.iter()), + ); + + let R = &check_scalar * B; + + assert_eq!(P.compress(), R.compress()); + assert_eq!(Q.compress(), R.compress()); + } + + mod vartime { + use super::super::*; + use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT}; + + /// Test double_scalar_mul_vartime vs ed25519.py + #[test] + fn double_scalar_mul_basepoint_vs_ed25519py() { + let A = A_TIMES_BASEPOINT.decompress().unwrap(); + let result = EdwardsPoint::vartime_double_scalar_mul_basepoint(&A_SCALAR, &A, &B_SCALAR); + assert_eq!(result.compress(), DOUBLE_SCALAR_MULT_RESULT); + } + + #[test] + fn multiscalar_mul_vs_ed25519py() { + let A = A_TIMES_BASEPOINT.decompress().unwrap(); + let result = EdwardsPoint::vartime_multiscalar_mul( + &[A_SCALAR, B_SCALAR], + &[A, constants::ED25519_BASEPOINT_POINT] + ); + assert_eq!(result.compress(), DOUBLE_SCALAR_MULT_RESULT); + } + + #[test] + fn multiscalar_mul_vartime_vs_consttime() { + let A = A_TIMES_BASEPOINT.decompress().unwrap(); + let result_vartime = EdwardsPoint::vartime_multiscalar_mul( + &[A_SCALAR, B_SCALAR], + &[A, constants::ED25519_BASEPOINT_POINT] + ); + let result_consttime = EdwardsPoint::multiscalar_mul( + &[A_SCALAR, B_SCALAR], + &[A, constants::ED25519_BASEPOINT_POINT] + ); + + assert_eq!(result_vartime.compress(), result_consttime.compress()); + } + } + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_basepoint_roundtrip() { + use bincode; + + let encoded = bincode::serialize(&constants::ED25519_BASEPOINT_POINT).unwrap(); + let enc_compressed = bincode::serialize(&constants::ED25519_BASEPOINT_COMPRESSED).unwrap(); + assert_eq!(encoded, enc_compressed); + + // Check that the encoding is 32 bytes exactly + assert_eq!(encoded.len(), 32); + + let dec_uncompressed: EdwardsPoint = bincode::deserialize(&encoded).unwrap(); + let dec_compressed: CompressedEdwardsY = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(dec_uncompressed, constants::ED25519_BASEPOINT_POINT); + assert_eq!(dec_compressed, constants::ED25519_BASEPOINT_COMPRESSED); + + // Check that the encoding itself matches the usual one + let raw_bytes = constants::ED25519_BASEPOINT_COMPRESSED.as_bytes(); + let bp: EdwardsPoint = bincode::deserialize(raw_bytes).unwrap(); + assert_eq!(bp, constants::ED25519_BASEPOINT_POINT); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/field.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/field.rs new file mode 100644 index 0000000..109cff2 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/field.rs @@ -0,0 +1,476 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis agora lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence + +//! Field arithmetic modulo \\(p = 2\^{255} - 19\\). +//! +//! The `curve25519_dalek::field` module provides a type alias +//! `curve25519_dalek::field::FieldElement` to a field element type +//! defined in the `backend` module; either `FieldElement51` or +//! `FieldElement2625`. +//! +//! Field operations defined in terms of machine +//! operations, such as field multiplication or squaring, are defined in +//! the backend implementation. +//! +//! Field operations defined in terms of other field operations, such as +//! field inversion or square roots, are defined here. + +use core::cmp::{Eq, PartialEq}; + +use subtle::ConditionallySelectable; +use subtle::ConditionallyNegatable; +use subtle::Choice; +use subtle::ConstantTimeEq; + +use constants; +use backend; + +#[cfg(feature = "fiat_u32_backend")] +pub use backend::serial::fiat_u32::field::*; +#[cfg(feature = "fiat_u64_backend")] +pub use backend::serial::fiat_u64::field::*; +/// A `FieldElement` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// The `FieldElement` type is an alias for one of the platform-specific +/// implementations. +/// Using formally-verified field arithmetic from fiat-crypto +#[cfg(feature = "fiat_u32_backend")] +pub type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; +#[cfg(feature = "fiat_u64_backend")] +pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51; + +#[cfg(feature = "u64_backend")] +pub use backend::serial::u64::field::*; +/// A `FieldElement` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// The `FieldElement` type is an alias for one of the platform-specific +/// implementations. +#[cfg(feature = "u64_backend")] +pub type FieldElement = backend::serial::u64::field::FieldElement51; + +#[cfg(feature = "u32_backend")] +pub use backend::serial::u32::field::*; +/// A `FieldElement` represents an element of the field +/// \\( \mathbb Z / (2\^{255} - 19)\\). +/// +/// The `FieldElement` type is an alias for one of the platform-specific +/// implementations. +#[cfg(feature = "u32_backend")] +pub type FieldElement = backend::serial::u32::field::FieldElement2625; + +impl Eq for FieldElement {} + +impl PartialEq for FieldElement { + fn eq(&self, other: &FieldElement) -> bool { + self.ct_eq(other).unwrap_u8() == 1u8 + } +} + +impl ConstantTimeEq for FieldElement { + /// Test equality between two `FieldElement`s. Since the + /// internal representation is not canonical, the field elements + /// are normalized to wire format before comparison. + fn ct_eq(&self, other: &FieldElement) -> Choice { + self.to_bytes().ct_eq(&other.to_bytes()) + } +} + +impl FieldElement { + /// Determine if this `FieldElement` is negative, in the sense + /// used in the ed25519 paper: `x` is negative if the low bit is + /// set. + /// + /// # Return + /// + /// If negative, return `Choice(1)`. Otherwise, return `Choice(0)`. + pub fn is_negative(&self) -> Choice { + let bytes = self.to_bytes(); + (bytes[0] & 1).into() + } + + /// Determine if this `FieldElement` is zero. + /// + /// # Return + /// + /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. + pub fn is_zero(&self) -> Choice { + let zero = [0u8; 32]; + let bytes = self.to_bytes(); + + bytes.ct_eq(&zero) + } + + /// Compute (self^(2^250-1), self^11), used as a helper function + /// within invert() and pow22523(). + fn pow22501(&self) -> (FieldElement, FieldElement) { + // Instead of managing which temporary variables are used + // for what, we define as many as we need and leave stack + // allocation to the compiler + // + // Each temporary variable t_i is of the form (self)^e_i. + // Squaring t_i corresponds to multiplying e_i by 2, + // so the pow2k function shifts e_i left by k places. + // Multiplying t_i and t_j corresponds to adding e_i + e_j. + // + // Temporary t_i Nonzero bits of e_i + // + let t0 = self.square(); // 1 e_0 = 2^1 + let t1 = t0.square().square(); // 3 e_1 = 2^3 + let t2 = self * &t1; // 3,0 e_2 = 2^3 + 2^0 + let t3 = &t0 * &t2; // 3,1,0 + let t4 = t3.square(); // 4,2,1 + let t5 = &t2 * &t4; // 4,3,2,1,0 + let t6 = t5.pow2k(5); // 9,8,7,6,5 + let t7 = &t6 * &t5; // 9,8,7,6,5,4,3,2,1,0 + let t8 = t7.pow2k(10); // 19..10 + let t9 = &t8 * &t7; // 19..0 + let t10 = t9.pow2k(20); // 39..20 + let t11 = &t10 * &t9; // 39..0 + let t12 = t11.pow2k(10); // 49..10 + let t13 = &t12 * &t7; // 49..0 + let t14 = t13.pow2k(50); // 99..50 + let t15 = &t14 * &t13; // 99..0 + let t16 = t15.pow2k(100); // 199..100 + let t17 = &t16 * &t15; // 199..0 + let t18 = t17.pow2k(50); // 249..50 + let t19 = &t18 * &t13; // 249..0 + + (t19, t3) + } + + /// Given a slice of public `FieldElements`, replace each with its inverse. + /// + /// All input `FieldElements` **MUST** be nonzero. + #[cfg(feature = "alloc")] + pub fn batch_invert(inputs: &mut [FieldElement]) { + // Montgomery’s Trick and Fast Implementation of Masked AES + // Genelle, Prouff and Quisquater + // Section 3.2 + + let n = inputs.len(); + let mut scratch = vec![FieldElement::one(); n]; + + // Keep an accumulator of all of the previous products + let mut acc = FieldElement::one(); + + // Pass through the input vector, recording the previous + // products in the scratch space + for (input, scratch) in inputs.iter().zip(scratch.iter_mut()) { + *scratch = acc; + acc = &acc * input; + } + + // acc is nonzero iff all inputs are nonzero + assert_eq!(acc.is_zero().unwrap_u8(), 0); + + // Compute the inverse of all products + acc = acc.invert(); + + // Pass through the vector backwards to compute the inverses + // in place + for (input, scratch) in inputs.iter_mut().rev().zip(scratch.into_iter().rev()) { + let tmp = &acc * input; + *input = &acc * &scratch; + acc = tmp; + } + } + + /// Given a nonzero field element, compute its inverse. + /// + /// The inverse is computed as self^(p-2), since + /// x^(p-2)x = x^(p-1) = 1 (mod p). + /// + /// This function returns zero on input zero. + pub fn invert(&self) -> FieldElement { + // The bits of p-2 = 2^255 -19 -2 are 11010111111...11. + // + // nonzero bits of exponent + let (t19, t3) = self.pow22501(); // t19: 249..0 ; t3: 3,1,0 + let t20 = t19.pow2k(5); // 254..5 + let t21 = &t20 * &t3; // 254..5,3,1,0 + + t21 + } + + /// Raise this field element to the power (p-5)/8 = 2^252 -3. + fn pow_p58(&self) -> FieldElement { + // The bits of (p-5)/8 are 101111.....11. + // + // nonzero bits of exponent + let (t19, _) = self.pow22501(); // 249..0 + let t20 = t19.pow2k(2); // 251..2 + let t21 = self * &t20; // 251..2,0 + + t21 + } + + /// Given `FieldElements` `u` and `v`, compute either `sqrt(u/v)` + /// or `sqrt(i*u/v)` in constant time. + /// + /// This function always returns the nonnegative square root. + /// + /// # Return + /// + /// - `(Choice(1), +sqrt(u/v)) ` if `v` is nonzero and `u/v` is square; + /// - `(Choice(1), zero) ` if `u` is zero; + /// - `(Choice(0), zero) ` if `v` is zero and `u` is nonzero; + /// - `(Choice(0), +sqrt(i*u/v))` if `u/v` is nonsquare (so `i*u/v` is square). + /// + pub fn sqrt_ratio_i(u: &FieldElement, v: &FieldElement) -> (Choice, FieldElement) { + // Using the same trick as in ed25519 decoding, we merge the + // inversion, the square root, and the square test as follows. + // + // To compute sqrt(α), we can compute β = α^((p+3)/8). + // Then β^2 = ±α, so multiplying β by sqrt(-1) if necessary + // gives sqrt(α). + // + // To compute 1/sqrt(α), we observe that + // 1/β = α^(p-1 - (p+3)/8) = α^((7p-11)/8) + // = α^3 * (α^7)^((p-5)/8). + // + // We can therefore compute sqrt(u/v) = sqrt(u)/sqrt(v) + // by first computing + // r = u^((p+3)/8) v^(p-1-(p+3)/8) + // = u u^((p-5)/8) v^3 (v^7)^((p-5)/8) + // = (uv^3) (uv^7)^((p-5)/8). + // + // If v is nonzero and u/v is square, then r^2 = ±u/v, + // so vr^2 = ±u. + // If vr^2 = u, then sqrt(u/v) = r. + // If vr^2 = -u, then sqrt(u/v) = r*sqrt(-1). + // + // If v is zero, r is also zero. + + let v3 = &v.square() * v; + let v7 = &v3.square() * v; + let mut r = &(u * &v3) * &(u * &v7).pow_p58(); + let check = v * &r.square(); + + let i = &constants::SQRT_M1; + + let correct_sign_sqrt = check.ct_eq( u); + let flipped_sign_sqrt = check.ct_eq( &(-u)); + let flipped_sign_sqrt_i = check.ct_eq(&(&(-u)*i)); + + let r_prime = &constants::SQRT_M1 * &r; + r.conditional_assign(&r_prime, flipped_sign_sqrt | flipped_sign_sqrt_i); + + // Choose the nonnegative square root. + let r_is_negative = r.is_negative(); + r.conditional_negate(r_is_negative); + + let was_nonzero_square = correct_sign_sqrt | flipped_sign_sqrt; + + (was_nonzero_square, r) + } + + /// Attempt to compute `sqrt(1/self)` in constant time. + /// + /// Convenience wrapper around `sqrt_ratio_i`. + /// + /// This function always returns the nonnegative square root. + /// + /// # Return + /// + /// - `(Choice(1), +sqrt(1/self)) ` if `self` is a nonzero square; + /// - `(Choice(0), zero) ` if `self` is zero; + /// - `(Choice(0), +sqrt(i/self)) ` if `self` is a nonzero nonsquare; + /// + pub fn invsqrt(&self) -> (Choice, FieldElement) { + FieldElement::sqrt_ratio_i(&FieldElement::one(), self) + } +} + +#[cfg(test)] +mod test { + use field::*; + use subtle::ConditionallyNegatable; + + /// Random element a of GF(2^255-19), from Sage + /// a = 1070314506888354081329385823235218444233221\ + /// 2228051251926706380353716438957572 + static A_BYTES: [u8; 32] = + [ 0x04, 0xfe, 0xdf, 0x98, 0xa7, 0xfa, 0x0a, 0x68, + 0x84, 0x92, 0xbd, 0x59, 0x08, 0x07, 0xa7, 0x03, + 0x9e, 0xd1, 0xf6, 0xf2, 0xe1, 0xd9, 0xe2, 0xa4, + 0xa4, 0x51, 0x47, 0x36, 0xf3, 0xc3, 0xa9, 0x17]; + + /// Byte representation of a**2 + static ASQ_BYTES: [u8; 32] = + [ 0x75, 0x97, 0x24, 0x9e, 0xe6, 0x06, 0xfe, 0xab, + 0x24, 0x04, 0x56, 0x68, 0x07, 0x91, 0x2d, 0x5d, + 0x0b, 0x0f, 0x3f, 0x1c, 0xb2, 0x6e, 0xf2, 0xe2, + 0x63, 0x9c, 0x12, 0xba, 0x73, 0x0b, 0xe3, 0x62]; + + /// Byte representation of 1/a + static AINV_BYTES: [u8; 32] = + [0x96, 0x1b, 0xcd, 0x8d, 0x4d, 0x5e, 0xa2, 0x3a, + 0xe9, 0x36, 0x37, 0x93, 0xdb, 0x7b, 0x4d, 0x70, + 0xb8, 0x0d, 0xc0, 0x55, 0xd0, 0x4c, 0x1d, 0x7b, + 0x90, 0x71, 0xd8, 0xe9, 0xb6, 0x18, 0xe6, 0x30]; + + /// Byte representation of a^((p-5)/8) + static AP58_BYTES: [u8; 32] = + [0x6a, 0x4f, 0x24, 0x89, 0x1f, 0x57, 0x60, 0x36, + 0xd0, 0xbe, 0x12, 0x3c, 0x8f, 0xf5, 0xb1, 0x59, + 0xe0, 0xf0, 0xb8, 0x1b, 0x20, 0xd2, 0xb5, 0x1f, + 0x15, 0x21, 0xf9, 0xe3, 0xe1, 0x61, 0x21, 0x55]; + + #[test] + fn a_mul_a_vs_a_squared_constant() { + let a = FieldElement::from_bytes(&A_BYTES); + let asq = FieldElement::from_bytes(&ASQ_BYTES); + assert_eq!(asq, &a * &a); + } + + #[test] + fn a_square_vs_a_squared_constant() { + let a = FieldElement::from_bytes(&A_BYTES); + let asq = FieldElement::from_bytes(&ASQ_BYTES); + assert_eq!(asq, a.square()); + } + + #[test] + fn a_square2_vs_a_squared_constant() { + let a = FieldElement::from_bytes(&A_BYTES); + let asq = FieldElement::from_bytes(&ASQ_BYTES); + assert_eq!(a.square2(), &asq+&asq); + } + + #[test] + fn a_invert_vs_inverse_of_a_constant() { + let a = FieldElement::from_bytes(&A_BYTES); + let ainv = FieldElement::from_bytes(&AINV_BYTES); + let should_be_inverse = a.invert(); + assert_eq!(ainv, should_be_inverse); + assert_eq!(FieldElement::one(), &a * &should_be_inverse); + } + + #[test] + fn batch_invert_a_matches_nonbatched() { + let a = FieldElement::from_bytes(&A_BYTES); + let ap58 = FieldElement::from_bytes(&AP58_BYTES); + let asq = FieldElement::from_bytes(&ASQ_BYTES); + let ainv = FieldElement::from_bytes(&AINV_BYTES); + let a2 = &a + &a; + let a_list = vec![a, ap58, asq, ainv, a2]; + let mut ainv_list = a_list.clone(); + FieldElement::batch_invert(&mut ainv_list[..]); + for i in 0..5 { + assert_eq!(a_list[i].invert(), ainv_list[i]); + } + } + + #[test] + fn sqrt_ratio_behavior() { + let zero = FieldElement::zero(); + let one = FieldElement::one(); + let i = constants::SQRT_M1; + let two = &one + &one; // 2 is nonsquare mod p. + let four = &two + &two; // 4 is square mod p. + + // 0/0 should return (1, 0) since u is 0 + let (choice, sqrt) = FieldElement::sqrt_ratio_i(&zero, &zero); + assert_eq!(choice.unwrap_u8(), 1); + assert_eq!(sqrt, zero); + assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + + // 1/0 should return (0, 0) since v is 0, u is nonzero + let (choice, sqrt) = FieldElement::sqrt_ratio_i(&one, &zero); + assert_eq!(choice.unwrap_u8(), 0); + assert_eq!(sqrt, zero); + assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + + // 2/1 is nonsquare, so we expect (0, sqrt(i*2)) + let (choice, sqrt) = FieldElement::sqrt_ratio_i(&two, &one); + assert_eq!(choice.unwrap_u8(), 0); + assert_eq!(sqrt.square(), &two * &i); + assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + + // 4/1 is square, so we expect (1, sqrt(4)) + let (choice, sqrt) = FieldElement::sqrt_ratio_i(&four, &one); + assert_eq!(choice.unwrap_u8(), 1); + assert_eq!(sqrt.square(), four); + assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + + // 1/4 is square, so we expect (1, 1/sqrt(4)) + let (choice, sqrt) = FieldElement::sqrt_ratio_i(&one, &four); + assert_eq!(choice.unwrap_u8(), 1); + assert_eq!(&sqrt.square() * &four, one); + assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + } + + #[test] + fn a_p58_vs_ap58_constant() { + let a = FieldElement::from_bytes(&A_BYTES); + let ap58 = FieldElement::from_bytes(&AP58_BYTES); + assert_eq!(ap58, a.pow_p58()); + } + + #[test] + fn equality() { + let a = FieldElement::from_bytes(&A_BYTES); + let ainv = FieldElement::from_bytes(&AINV_BYTES); + assert!(a == a); + assert!(a != ainv); + } + + /// Notice that the last element has the high bit set, which + /// should be ignored + static B_BYTES: [u8;32] = + [113, 191, 169, 143, 91, 234, 121, 15, + 241, 131, 217, 36, 230, 101, 92, 234, + 8, 208, 170, 251, 97, 127, 70, 210, + 58, 23, 166, 87, 240, 169, 184, 178]; + + #[test] + fn from_bytes_highbit_is_ignored() { + let mut cleared_bytes = B_BYTES; + cleared_bytes[31] &= 127u8; + let with_highbit_set = FieldElement::from_bytes(&B_BYTES); + let without_highbit_set = FieldElement::from_bytes(&cleared_bytes); + assert_eq!(without_highbit_set, with_highbit_set); + } + + #[test] + fn conditional_negate() { + let one = FieldElement::one(); + let minus_one = FieldElement::minus_one(); + let mut x = one; + x.conditional_negate(Choice::from(1)); + assert_eq!(x, minus_one); + x.conditional_negate(Choice::from(0)); + assert_eq!(x, minus_one); + x.conditional_negate(Choice::from(1)); + assert_eq!(x, one); + } + + #[test] + fn encoding_is_canonical() { + // Encode 1 wrongly as 1 + (2^255 - 19) = 2^255 - 18 + let one_encoded_wrongly_bytes: [u8;32] = [0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]; + // Decode to a field element + let one = FieldElement::from_bytes(&one_encoded_wrongly_bytes); + // .. then check that the encoding is correct + let one_bytes = one.to_bytes(); + assert_eq!(one_bytes[0], 1); + for i in 1..32 { + assert_eq!(one_bytes[i], 0); + } + } + + #[test] + fn batch_invert_empty() { + FieldElement::batch_invert(&mut []); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/lib.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/lib.rs new file mode 100644 index 0000000..13f9393 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/lib.rs @@ -0,0 +1,101 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +#![no_std] +#![cfg_attr(feature = "nightly", feature(test))] +#![cfg_attr(feature = "nightly", feature(external_doc))] +#![cfg_attr(feature = "nightly", feature(doc_cfg))] +#![cfg_attr(feature = "simd_backend", feature(stdsimd))] +// Refuse to compile if documentation is missing, but only on nightly. +// +// This means that missing docs will still fail CI, but means we can use +// README.md as the crate documentation. +#![cfg_attr(feature = "nightly", deny(missing_docs))] + +#![cfg_attr(feature = "nightly", doc(include = "../README.md"))] +#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] +#![doc(html_root_url = "https://docs.rs/curve25519-dalek/3.1.0")] + +//! Note that docs will only build on nightly Rust until +//! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732). + +//------------------------------------------------------------------------ +// External dependencies: +//------------------------------------------------------------------------ + +#[cfg(all(feature = "alloc", not(feature = "std")))] +#[macro_use] +extern crate alloc; + +#[cfg(feature = "std")] +#[macro_use] +extern crate std; + +#[cfg(all(feature = "nightly", feature = "packed_simd"))] +extern crate packed_simd; + +extern crate byteorder; +pub extern crate digest; +extern crate rand_core; +extern crate zeroize; + +#[cfg(any(feature = "fiat_u64_backend", feature = "fiat_u32_backend"))] +extern crate fiat_crypto; + +// Used for traits related to constant-time code. +extern crate subtle; + +#[cfg(all(test, feature = "serde"))] +extern crate bincode; +#[cfg(feature = "serde")] +extern crate serde; + +// Internal macros. Must come first! +#[macro_use] +pub(crate) mod macros; + +//------------------------------------------------------------------------ +// curve25519-dalek public modules +//------------------------------------------------------------------------ + +// Scalar arithmetic mod l = 2^252 + ..., the order of the Ristretto group +pub mod scalar; + +// Point operations on the Montgomery form of Curve25519 +pub mod montgomery; + +// Point operations on the Edwards form of Curve25519 +pub mod edwards; + +// Group operations on the Ristretto group +pub mod ristretto; + +// Useful constants, like the Ed25519 basepoint +pub mod constants; + +// External (and internal) traits. +pub mod traits; + +//------------------------------------------------------------------------ +// curve25519-dalek internal modules +//------------------------------------------------------------------------ + +// Finite field arithmetic mod p = 2^255 - 19 +pub(crate) mod field; + +// Arithmetic backends (using u32, u64, etc) live here +pub(crate) mod backend; + +// Crate-local prelude (for alloc-dependent features like `Vec`) +pub(crate) mod prelude; + +// Generic code for window lookups +pub(crate) mod window; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/macros.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/macros.rs new file mode 100644 index 0000000..84a2ce1 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/macros.rs @@ -0,0 +1,124 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis agora lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Internal macros. + +/// Define borrow and non-borrow variants of `Add`. +macro_rules! define_add_variants { + (LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => { + impl<'b> Add<&'b $rhs> for $lhs { + type Output = $out; + fn add(self, rhs: &'b $rhs) -> $out { + &self + rhs + } + } + + impl<'a> Add<$rhs> for &'a $lhs { + type Output = $out; + fn add(self, rhs: $rhs) -> $out { + self + &rhs + } + } + + impl Add<$rhs> for $lhs { + type Output = $out; + fn add(self, rhs: $rhs) -> $out { + &self + &rhs + } + } + } +} + +/// Define non-borrow variants of `AddAssign`. +macro_rules! define_add_assign_variants { + (LHS = $lhs:ty, RHS = $rhs:ty) => { + impl AddAssign<$rhs> for $lhs { + fn add_assign(&mut self, rhs: $rhs) { + *self += &rhs; + } + } + } +} + +/// Define borrow and non-borrow variants of `Sub`. +macro_rules! define_sub_variants { + (LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => { + impl<'b> Sub<&'b $rhs> for $lhs { + type Output = $out; + fn sub(self, rhs: &'b $rhs) -> $out { + &self - rhs + } + } + + impl<'a> Sub<$rhs> for &'a $lhs { + type Output = $out; + fn sub(self, rhs: $rhs) -> $out { + self - &rhs + } + } + + impl Sub<$rhs> for $lhs { + type Output = $out; + fn sub(self, rhs: $rhs) -> $out { + &self - &rhs + } + } + } +} + +/// Define non-borrow variants of `SubAssign`. +macro_rules! define_sub_assign_variants { + (LHS = $lhs:ty, RHS = $rhs:ty) => { + impl SubAssign<$rhs> for $lhs { + fn sub_assign(&mut self, rhs: $rhs) { + *self -= &rhs; + } + } + } +} + +/// Define borrow and non-borrow variants of `Mul`. +macro_rules! define_mul_variants { + (LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => { + impl<'b> Mul<&'b $rhs> for $lhs { + type Output = $out; + fn mul(self, rhs: &'b $rhs) -> $out { + &self * rhs + } + } + + impl<'a> Mul<$rhs> for &'a $lhs { + type Output = $out; + fn mul(self, rhs: $rhs) -> $out { + self * &rhs + } + } + + impl Mul<$rhs> for $lhs { + type Output = $out; + fn mul(self, rhs: $rhs) -> $out { + &self * &rhs + } + } + } +} + +/// Define non-borrow variants of `MulAssign`. +macro_rules! define_mul_assign_variants { + (LHS = $lhs:ty, RHS = $rhs:ty) => { + impl MulAssign<$rhs> for $lhs { + fn mul_assign(&mut self, rhs: $rhs) { + *self *= &rhs; + } + } + } +} + diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/montgomery.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/montgomery.rs new file mode 100644 index 0000000..de0f8b7 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/montgomery.rs @@ -0,0 +1,459 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Scalar multiplication on the Montgomery form of Curve25519. +//! +//! To avoid notational confusion with the Edwards code, we use +//! variables \\( u, v \\) for the Montgomery curve, so that “Montgomery +//! \\(u\\)” here corresponds to “Montgomery \\(x\\)” elsewhere. +//! +//! Montgomery arithmetic works not on the curve itself, but on the +//! \\(u\\)-line, which discards sign information and unifies the curve +//! and its quadratic twist. See [_Montgomery curves and their +//! arithmetic_][costello-smith] by Costello and Smith for more details. +//! +//! The `MontgomeryPoint` struct contains the affine \\(u\\)-coordinate +//! \\(u\_0(P)\\) of a point \\(P\\) on either the curve or the twist. +//! Here the map \\(u\_0 : \mathcal M \rightarrow \mathbb F\_p \\) is +//! defined by \\(u\_0((u,v)) = u\\); \\(u\_0(\mathcal O) = 0\\). See +//! section 5.4 of Costello-Smith for more details. +//! +//! # Scalar Multiplication +//! +//! Scalar multiplication on `MontgomeryPoint`s is provided by the `*` +//! operator, which implements the Montgomery ladder. +//! +//! # Edwards Conversion +//! +//! The \\(2\\)-to-\\(1\\) map from the Edwards model to the Montgomery +//! \\(u\\)-line is provided by `EdwardsPoint::to_montgomery()`. +//! +//! To lift a `MontgomeryPoint` to an `EdwardsPoint`, use +//! `MontgomeryPoint::to_edwards()`, which takes a sign parameter. +//! This function rejects `MontgomeryPoints` which correspond to points +//! on the twist. +//! +//! [costello-smith]: https://eprint.iacr.org/2017/212.pdf + +// We allow non snake_case names because coordinates in projective space are +// traditionally denoted by the capitalisation of their respective +// counterparts in affine space. Yeah, you heard me, rustc, I'm gonna have my +// affine and projective cakes and eat both of them too. +#![allow(non_snake_case)] + +use core::ops::{Mul, MulAssign}; + +use constants::{APLUS2_OVER_FOUR, MONTGOMERY_A, MONTGOMERY_A_NEG}; +use edwards::{CompressedEdwardsY, EdwardsPoint}; +use field::FieldElement; +use scalar::Scalar; + +use traits::Identity; + +use subtle::Choice; +use subtle::ConstantTimeEq; +use subtle::{ConditionallyNegatable, ConditionallySelectable}; + +use zeroize::Zeroize; + +/// Holds the \\(u\\)-coordinate of a point on the Montgomery form of +/// Curve25519 or its twist. +#[derive(Copy, Clone, Debug, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct MontgomeryPoint(pub [u8; 32]); + +/// Equality of `MontgomeryPoint`s is defined mod p. +impl ConstantTimeEq for MontgomeryPoint { + fn ct_eq(&self, other: &MontgomeryPoint) -> Choice { + let self_fe = FieldElement::from_bytes(&self.0); + let other_fe = FieldElement::from_bytes(&other.0); + + self_fe.ct_eq(&other_fe) + } +} + +impl Default for MontgomeryPoint { + fn default() -> MontgomeryPoint { + MontgomeryPoint([0u8; 32]) + } +} + +impl PartialEq for MontgomeryPoint { + fn eq(&self, other: &MontgomeryPoint) -> bool { + self.ct_eq(other).unwrap_u8() == 1u8 + } +} + +impl Eq for MontgomeryPoint {} + +impl Zeroize for MontgomeryPoint { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl MontgomeryPoint { + /// View this `MontgomeryPoint` as an array of bytes. + pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { + &self.0 + } + + /// Convert this `MontgomeryPoint` to an array of bytes. + pub fn to_bytes(&self) -> [u8; 32] { + self.0 + } + + /// Attempt to convert to an `EdwardsPoint`, using the supplied + /// choice of sign for the `EdwardsPoint`. + /// + /// # Inputs + /// + /// * `sign`: a `u8` donating the desired sign of the resulting + /// `EdwardsPoint`. `0` denotes positive and `1` negative. + /// + /// # Return + /// + /// * `Some(EdwardsPoint)` if `self` is the \\(u\\)-coordinate of a + /// point on (the Montgomery form of) Curve25519; + /// + /// * `None` if `self` is the \\(u\\)-coordinate of a point on the + /// twist of (the Montgomery form of) Curve25519; + /// + pub fn to_edwards(&self, sign: u8) -> Option { + // To decompress the Montgomery u coordinate to an + // `EdwardsPoint`, we apply the birational map to obtain the + // Edwards y coordinate, then do Edwards decompression. + // + // The birational map is y = (u-1)/(u+1). + // + // The exceptional points are the zeros of the denominator, + // i.e., u = -1. + // + // But when u = -1, v^2 = u*(u^2+486662*u+1) = 486660. + // + // Since this is nonsquare mod p, u = -1 corresponds to a point + // on the twist, not the curve, so we can reject it early. + + let u = FieldElement::from_bytes(&self.0); + + if u == FieldElement::minus_one() { return None; } + + let one = FieldElement::one(); + + let y = &(&u - &one) * &(&u + &one).invert(); + + let mut y_bytes = y.to_bytes(); + y_bytes[31] ^= sign << 7; + + CompressedEdwardsY(y_bytes).decompress() + } +} + +/// Perform the Elligator2 mapping to a Montgomery point. +/// +/// See https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.7.1 +// +// TODO Determine how much of the hash-to-group API should be exposed after the CFRG +// draft gets into a more polished/accepted state. +#[allow(unused)] +pub(crate) fn elligator_encode(r_0: &FieldElement) -> MontgomeryPoint { + let one = FieldElement::one(); + let d_1 = &one + &r_0.square2(); /* 2r^2 */ + + let d = &MONTGOMERY_A_NEG * &(d_1.invert()); /* A/(1+2r^2) */ + + let d_sq = &d.square(); + let au = &MONTGOMERY_A * &d; + + let inner = &(d_sq + &au) + &one; + let eps = &d * &inner; /* eps = d^3 + Ad^2 + d */ + + let (eps_is_sq, _eps) = FieldElement::sqrt_ratio_i(&eps, &one); + + let zero = FieldElement::zero(); + let Atemp = FieldElement::conditional_select(&MONTGOMERY_A, &zero, eps_is_sq); /* 0, or A if nonsquare*/ + let mut u = &d + &Atemp; /* d, or d+A if nonsquare */ + u.conditional_negate(!eps_is_sq); /* d, or -d-A if nonsquare */ + + MontgomeryPoint(u.to_bytes()) +} + +/// A `ProjectivePoint` holds a point on the projective line +/// \\( \mathbb P(\mathbb F\_p) \\), which we identify with the Kummer +/// line of the Montgomery curve. +#[derive(Copy, Clone, Debug)] +struct ProjectivePoint { + pub U: FieldElement, + pub W: FieldElement, +} + +impl Identity for ProjectivePoint { + fn identity() -> ProjectivePoint { + ProjectivePoint { + U: FieldElement::one(), + W: FieldElement::zero(), + } + } +} + +impl Default for ProjectivePoint { + fn default() -> ProjectivePoint { + ProjectivePoint::identity() + } +} + +impl ConditionallySelectable for ProjectivePoint { + fn conditional_select( + a: &ProjectivePoint, + b: &ProjectivePoint, + choice: Choice, + ) -> ProjectivePoint { + ProjectivePoint { + U: FieldElement::conditional_select(&a.U, &b.U, choice), + W: FieldElement::conditional_select(&a.W, &b.W, choice), + } + } +} + +impl ProjectivePoint { + /// Dehomogenize this point to affine coordinates. + /// + /// # Return + /// + /// * \\( u = U / W \\) if \\( W \neq 0 \\); + /// * \\( 0 \\) if \\( W \eq 0 \\); + pub fn to_affine(&self) -> MontgomeryPoint { + let u = &self.U * &self.W.invert(); + MontgomeryPoint(u.to_bytes()) + } +} + +/// Perform the double-and-add step of the Montgomery ladder. +/// +/// Given projective points +/// \\( (U\_P : W\_P) = u(P) \\), +/// \\( (U\_Q : W\_Q) = u(Q) \\), +/// and the affine difference +/// \\( u\_{P-Q} = u(P-Q) \\), set +/// $$ +/// (U\_P : W\_P) \gets u([2]P) +/// $$ +/// and +/// $$ +/// (U\_Q : W\_Q) \gets u(P + Q). +/// $$ +fn differential_add_and_double( + P: &mut ProjectivePoint, + Q: &mut ProjectivePoint, + affine_PmQ: &FieldElement, +) { + let t0 = &P.U + &P.W; + let t1 = &P.U - &P.W; + let t2 = &Q.U + &Q.W; + let t3 = &Q.U - &Q.W; + + let t4 = t0.square(); // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2 + let t5 = t1.square(); // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2 + + let t6 = &t4 - &t5; // 4 U_P W_P + + let t7 = &t0 * &t3; // (U_P + W_P) (U_Q - W_Q) = U_P U_Q + W_P U_Q - U_P W_Q - W_P W_Q + let t8 = &t1 * &t2; // (U_P - W_P) (U_Q + W_Q) = U_P U_Q - W_P U_Q + U_P W_Q - W_P W_Q + + let t9 = &t7 + &t8; // 2 (U_P U_Q - W_P W_Q) + let t10 = &t7 - &t8; // 2 (W_P U_Q - U_P W_Q) + + let t11 = t9.square(); // 4 (U_P U_Q - W_P W_Q)^2 + let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2 + + let t13 = &APLUS2_OVER_FOUR * &t6; // (A + 2) U_P U_Q + + let t14 = &t4 * &t5; // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2 + let t15 = &t13 + &t5; // (U_P - W_P)^2 + (A + 2) U_P W_P + + let t16 = &t6 * &t15; // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P) + + let t17 = affine_PmQ * &t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2 + let t18 = t11; // W_D * 4 (U_P U_Q - W_P W_Q)^2 + + P.U = t14; // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2 + P.W = t16; // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P) + Q.U = t18; // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2 + Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 +} + +define_mul_assign_variants!(LHS = MontgomeryPoint, RHS = Scalar); + +define_mul_variants!(LHS = MontgomeryPoint, RHS = Scalar, Output = MontgomeryPoint); +define_mul_variants!(LHS = Scalar, RHS = MontgomeryPoint, Output = MontgomeryPoint); + +/// Multiply this `MontgomeryPoint` by a `Scalar`. +impl<'a, 'b> Mul<&'b Scalar> for &'a MontgomeryPoint { + type Output = MontgomeryPoint; + + /// Given `self` \\( = u\_0(P) \\), and a `Scalar` \\(n\\), return \\( u\_0([n]P) \\). + fn mul(self, scalar: &'b Scalar) -> MontgomeryPoint { + // Algorithm 8 of Costello-Smith 2017 + let affine_u = FieldElement::from_bytes(&self.0); + let mut x0 = ProjectivePoint::identity(); + let mut x1 = ProjectivePoint { + U: affine_u, + W: FieldElement::one(), + }; + + let bits: [i8; 256] = scalar.bits(); + + for i in (0..255).rev() { + let choice: u8 = (bits[i + 1] ^ bits[i]) as u8; + + debug_assert!(choice == 0 || choice == 1); + + ProjectivePoint::conditional_swap(&mut x0, &mut x1, choice.into()); + differential_add_and_double(&mut x0, &mut x1, &affine_u); + } + ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(bits[0] as u8)); + + x0.to_affine() + } +} + +impl<'b> MulAssign<&'b Scalar> for MontgomeryPoint { + fn mul_assign(&mut self, scalar: &'b Scalar) { + *self = (self as &MontgomeryPoint) * scalar; + } +} + +impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar { + type Output = MontgomeryPoint; + + fn mul(self, point: &'b MontgomeryPoint) -> MontgomeryPoint { + point * self + } +} + +// ------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------ + +#[cfg(test)] +mod test { + use super::*; + use constants; + use core::convert::TryInto; + + use rand_core::OsRng; + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_basepoint_roundtrip() { + use bincode; + + let encoded = bincode::serialize(&constants::X25519_BASEPOINT).unwrap(); + let decoded: MontgomeryPoint = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(encoded.len(), 32); + assert_eq!(decoded, constants::X25519_BASEPOINT); + + let raw_bytes = constants::X25519_BASEPOINT.as_bytes(); + let bp: MontgomeryPoint = bincode::deserialize(raw_bytes).unwrap(); + assert_eq!(bp, constants::X25519_BASEPOINT); + } + + /// Test Montgomery -> Edwards on the X/Ed25519 basepoint + #[test] + fn basepoint_montgomery_to_edwards() { + // sign bit = 0 => basepoint + assert_eq!( + constants::ED25519_BASEPOINT_POINT, + constants::X25519_BASEPOINT.to_edwards(0).unwrap() + ); + // sign bit = 1 => minus basepoint + assert_eq!( + - constants::ED25519_BASEPOINT_POINT, + constants::X25519_BASEPOINT.to_edwards(1).unwrap() + ); + } + + /// Test Edwards -> Montgomery on the X/Ed25519 basepoint + #[test] + fn basepoint_edwards_to_montgomery() { + assert_eq!( + constants::ED25519_BASEPOINT_POINT.to_montgomery(), + constants::X25519_BASEPOINT + ); + } + + /// Check that Montgomery -> Edwards fails for points on the twist. + #[test] + fn montgomery_to_edwards_rejects_twist() { + let one = FieldElement::one(); + + // u = 2 corresponds to a point on the twist. + let two = MontgomeryPoint((&one+&one).to_bytes()); + + assert!(two.to_edwards(0).is_none()); + + // u = -1 corresponds to a point on the twist, but should be + // checked explicitly because it's an exceptional point for the + // birational map. For instance, libsignal will accept it. + let minus_one = MontgomeryPoint((-&one).to_bytes()); + + assert!(minus_one.to_edwards(0).is_none()); + } + + #[test] + fn eq_defined_mod_p() { + let mut u18_bytes = [0u8; 32]; u18_bytes[0] = 18; + let u18 = MontgomeryPoint(u18_bytes); + let u18_unred = MontgomeryPoint([255; 32]); + + assert_eq!(u18, u18_unred); + } + + #[test] + fn montgomery_ladder_matches_edwards_scalarmult() { + let mut csprng: OsRng = OsRng; + + let s: Scalar = Scalar::random(&mut csprng); + let p_edwards: EdwardsPoint = &constants::ED25519_BASEPOINT_TABLE * &s; + let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); + + let expected = s * p_edwards; + let result = s * p_montgomery; + + assert_eq!(result, expected.to_montgomery()) + } + + const ELLIGATOR_CORRECT_OUTPUT: [u8; 32] = [ + 0x5f, 0x35, 0x20, 0x00, 0x1c, 0x6c, 0x99, 0x36, 0xa3, 0x12, 0x06, 0xaf, 0xe7, 0xc7, 0xac, + 0x22, 0x4e, 0x88, 0x61, 0x61, 0x9b, 0xf9, 0x88, 0x72, 0x44, 0x49, 0x15, 0x89, 0x9d, 0x95, + 0xf4, 0x6e, + ]; + + #[test] + #[cfg(feature = "std")] // Vec + fn montgomery_elligator_correct() { + let bytes: std::vec::Vec = (0u8..32u8).collect(); + let bits_in: [u8; 32] = (&bytes[..]).try_into().expect("Range invariant broken"); + + let fe = FieldElement::from_bytes(&bits_in); + let eg = elligator_encode(&fe); + assert_eq!(eg.to_bytes(), ELLIGATOR_CORRECT_OUTPUT); + } + + #[test] + fn montgomery_elligator_zero_zero() { + let zero = [0u8; 32]; + let fe = FieldElement::from_bytes(&zero); + let eg = elligator_encode(&fe); + assert_eq!(eg.to_bytes(), zero); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/prelude.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/prelude.rs new file mode 100644 index 0000000..5c0a611 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/prelude.rs @@ -0,0 +1,19 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Crate-local prelude (for alloc-dependent features like `Vec`) + +// TODO: switch to alloc::prelude +#[cfg(all(feature = "alloc", not(feature = "std")))] +pub use alloc::vec::Vec; + +#[cfg(feature = "std")] +pub use std::vec::Vec; diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/ristretto.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/ristretto.rs new file mode 100644 index 0000000..d284b5b --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/ristretto.rs @@ -0,0 +1,1366 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2020 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +// We allow non snake_case names because coordinates in projective space are +// traditionally denoted by the capitalisation of their respective +// counterparts in affine space. Yeah, you heard me, rustc, I'm gonna have my +// affine and projective cakes and eat both of them too. +#![allow(non_snake_case)] + +//! An implementation of [Ristretto][ristretto_main], which provides a +//! prime-order group. +//! +//! # The Ristretto Group +//! +//! Ristretto is a modification of Mike Hamburg's Decaf scheme to work +//! with cofactor-\\(8\\) curves, such as Curve25519. +//! +//! The introduction of the Decaf paper, [_Decaf: +//! Eliminating cofactors through point +//! compression_](https://eprint.iacr.org/2015/673.pdf), notes that while +//! most cryptographic systems require a group of prime order, most +//! concrete implementations using elliptic curve groups fall short – +//! they either provide a group of prime order, but with incomplete or +//! variable-time addition formulae (for instance, most Weierstrass +//! models), or else they provide a fast and safe implementation of a +//! group whose order is not quite a prime \\(q\\), but \\(hq\\) for a +//! small cofactor \\(h\\) (for instance, Edwards curves, which have +//! cofactor at least \\(4\\)). +//! +//! This abstraction mismatch is commonly “handled” by pushing the +//! complexity upwards, adding ad-hoc protocol modifications. But +//! these modifications require careful analysis and are a recurring +//! source of [vulnerabilities][cryptonote] and [design +//! complications][ed25519_hkd]. +//! +//! Instead, Decaf (and Ristretto) use a quotient group to implement a +//! prime-order group using a non-prime-order curve. This provides +//! the correct abstraction for cryptographic systems, while retaining +//! the speed and safety benefits of an Edwards curve. +//! +//! Decaf is named “after the procedure which divides the effect of +//! coffee by \\(4\\)”. However, Curve25519 has a cofactor of +//! \\(8\\). To eliminate its cofactor, Ristretto restricts further; +//! this [additional restriction][ristretto_coffee] gives the +//! _Ristretto_ encoding. +//! +//! More details on why Ristretto is necessary can be found in the +//! [Why Ristretto?][why_ristretto] section of the Ristretto website. +//! +//! Ristretto +//! points are provided in `curve25519-dalek` by the `RistrettoPoint` +//! struct. +//! +//! ## Encoding and Decoding +//! +//! Encoding is done by converting to and from a `CompressedRistretto` +//! struct, which is a typed wrapper around `[u8; 32]`. +//! +//! The encoding is not batchable, but it is possible to +//! double-and-encode in a batch using +//! `RistrettoPoint::double_and_compress_batch`. +//! +//! ## Equality Testing +//! +//! Testing equality of points on an Edwards curve in projective +//! coordinates requires an expensive inversion. By contrast, equality +//! checking in the Ristretto group can be done in projective +//! coordinates without requiring an inversion, so it is much faster. +//! +//! The `RistrettoPoint` struct implements the +//! `subtle::ConstantTimeEq` trait for constant-time equality +//! checking, and the Rust `Eq` trait for variable-time equality +//! checking. +//! +//! ## Scalars +//! +//! Scalars are represented by the `Scalar` struct. Each scalar has a +//! canonical representative mod the group order. To attempt to load +//! a supposedly-canonical scalar, use +//! `Scalar::from_canonical_bytes()`. To check whether a +//! representative is canonical, use `Scalar::is_canonical()`. +//! +//! ## Scalar Multiplication +//! +//! Scalar multiplication on Ristretto points is provided by: +//! +//! * the `*` operator between a `Scalar` and a `RistrettoPoint`, which +//! performs constant-time variable-base scalar multiplication; +//! +//! * the `*` operator between a `Scalar` and a +//! `RistrettoBasepointTable`, which performs constant-time fixed-base +//! scalar multiplication; +//! +//! * an implementation of the +//! [`MultiscalarMul`](../traits/trait.MultiscalarMul.html) trait for +//! constant-time variable-base multiscalar multiplication; +//! +//! * an implementation of the +//! [`VartimeMultiscalarMul`](../traits/trait.VartimeMultiscalarMul.html) +//! trait for variable-time variable-base multiscalar multiplication; +//! +//! ## Random Points and Hashing to Ristretto +//! +//! The Ristretto group comes equipped with an Elligator map. This is +//! used to implement +//! +//! * `RistrettoPoint::random()`, which generates random points from an +//! RNG; +//! +//! * `RistrettoPoint::from_hash()` and +//! `RistrettoPoint::hash_from_bytes()`, which perform hashing to the +//! group. +//! +//! The Elligator map itself is not currently exposed. +//! +//! ## Implementation +//! +//! The Decaf suggestion is to use a quotient group, such as \\(\mathcal +//! E / \mathcal E[4]\\) or \\(2 \mathcal E / \mathcal E[2] \\), to +//! implement a prime-order group using a non-prime-order curve. +//! +//! This requires only changing +//! +//! 1. the function for equality checking (so that two representatives +//! of the same coset are considered equal); +//! 2. the function for encoding (so that two representatives of the +//! same coset are encoded as identical bitstrings); +//! 3. the function for decoding (so that only the canonical encoding of +//! a coset is accepted). +//! +//! Internally, each coset is represented by a curve point; two points +//! \\( P, Q \\) may represent the same coset in the same way that two +//! points with different \\(X,Y,Z\\) coordinates may represent the +//! same point. The group operations are carried out with no overhead +//! using Edwards formulas. +//! +//! Notes on the details of the encoding can be found in the +//! [Details][ristretto_notes] section of the Ristretto website. +//! +//! [cryptonote]: +//! https://moderncrypto.org/mail-archive/curves/2017/000898.html +//! [ed25519_hkd]: +//! https://moderncrypto.org/mail-archive/curves/2017/000858.html +//! [ristretto_coffee]: +//! https://en.wikipedia.org/wiki/Ristretto +//! [ristretto_notes]: +//! https://ristretto.group/details/index.html +//! [why_ristretto]: +//! https://ristretto.group/why_ristretto.html +//! [ristretto_main]: +//! https://ristretto.group/ + +use core::borrow::Borrow; +use core::fmt::Debug; +use core::iter::Sum; +use core::ops::{Add, Neg, Sub}; +use core::ops::{AddAssign, SubAssign}; +use core::ops::{Mul, MulAssign}; + +use rand_core::{CryptoRng, RngCore}; + +use digest::generic_array::typenum::U64; +use digest::Digest; + +use constants; +use field::FieldElement; + +use subtle::Choice; +use subtle::ConditionallySelectable; +use subtle::ConditionallyNegatable; +use subtle::ConstantTimeEq; + +use edwards::EdwardsBasepointTable; +use edwards::EdwardsPoint; + +#[allow(unused_imports)] +use prelude::*; + +use scalar::Scalar; + +use traits::Identity; +#[cfg(any(feature = "alloc", feature = "std"))] +use traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; + +#[cfg(not(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +)))] +use backend::serial::scalar_mul; +#[cfg(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") +))] +use backend::vector::scalar_mul; + +// ------------------------------------------------------------------------ +// Compressed points +// ------------------------------------------------------------------------ + +/// A Ristretto point, in compressed wire format. +/// +/// The Ristretto encoding is canonical, so two points are equal if and +/// only if their encodings are equal. +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct CompressedRistretto(pub [u8; 32]); + +impl ConstantTimeEq for CompressedRistretto { + fn ct_eq(&self, other: &CompressedRistretto) -> Choice { + self.as_bytes().ct_eq(other.as_bytes()) + } +} + +impl CompressedRistretto { + /// Copy the bytes of this `CompressedRistretto`. + pub fn to_bytes(&self) -> [u8; 32] { + self.0 + } + + /// View this `CompressedRistretto` as an array of bytes. + pub fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } + + /// Construct a `CompressedRistretto` from a slice of bytes. + /// + /// # Panics + /// + /// If the input `bytes` slice does not have a length of 32. + pub fn from_slice(bytes: &[u8]) -> CompressedRistretto { + let mut tmp = [0u8; 32]; + + tmp.copy_from_slice(bytes); + + CompressedRistretto(tmp) + } + + /// Attempt to decompress to an `RistrettoPoint`. + /// + /// # Return + /// + /// - `Some(RistrettoPoint)` if `self` was the canonical encoding of a point; + /// + /// - `None` if `self` was not the canonical encoding of a point. + pub fn decompress(&self) -> Option { + // Step 1. Check s for validity: + // 1.a) s must be 32 bytes (we get this from the type system) + // 1.b) s < p + // 1.c) s is nonnegative + // + // Our decoding routine ignores the high bit, so the only + // possible failure for 1.b) is if someone encodes s in 0..18 + // as s+p in 2^255-19..2^255-1. We can check this by + // converting back to bytes, and checking that we get the + // original input, since our encoding routine is canonical. + + let s = FieldElement::from_bytes(self.as_bytes()); + let s_bytes_check = s.to_bytes(); + let s_encoding_is_canonical = + &s_bytes_check[..].ct_eq(self.as_bytes()); + let s_is_negative = s.is_negative(); + + if s_encoding_is_canonical.unwrap_u8() == 0u8 || s_is_negative.unwrap_u8() == 1u8 { + return None; + } + + // Step 2. Compute (X:Y:Z:T). + let one = FieldElement::one(); + let ss = s.square(); + let u1 = &one - &ss; // 1 + as² + let u2 = &one + &ss; // 1 - as² where a=-1 + let u2_sqr = u2.square(); // (1 - as²)² + + // v == ad(1+as²)² - (1-as²)² where d=-121665/121666 + let v = &(&(-&constants::EDWARDS_D) * &u1.square()) - &u2_sqr; + + let (ok, I) = (&v * &u2_sqr).invsqrt(); // 1/sqrt(v*u_2²) + + let Dx = &I * &u2; // 1/sqrt(v) + let Dy = &I * &(&Dx * &v); // 1/u2 + + // x == | 2s/sqrt(v) | == + sqrt(4s²/(ad(1+as²)² - (1-as²)²)) + let mut x = &(&s + &s) * &Dx; + let x_neg = x.is_negative(); + x.conditional_negate(x_neg); + + // y == (1-as²)/(1+as²) + let y = &u1 * &Dy; + + // t == ((1+as²) sqrt(4s²/(ad(1+as²)² - (1-as²)²)))/(1-as²) + let t = &x * &y; + + if ok.unwrap_u8() == 0u8 || t.is_negative().unwrap_u8() == 1u8 || y.is_zero().unwrap_u8() == 1u8 { + None + } else { + Some(RistrettoPoint(EdwardsPoint{X: x, Y: y, Z: one, T: t})) + } + } +} + +impl Identity for CompressedRistretto { + fn identity() -> CompressedRistretto { + CompressedRistretto([0u8; 32]) + } +} + +impl Default for CompressedRistretto { + fn default() -> CompressedRistretto { + CompressedRistretto::identity() + } +} + +// ------------------------------------------------------------------------ +// Serde support +// ------------------------------------------------------------------------ +// Serializes to and from `RistrettoPoint` directly, doing compression +// and decompression internally. This means that users can create +// structs containing `RistrettoPoint`s and use Serde's derived +// serializers to serialize those structures. + +#[cfg(feature = "serde")] +use serde::{self, Serialize, Deserialize, Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +#[cfg(feature = "serde")] +impl Serialize for RistrettoPoint { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + use serde::ser::SerializeTuple; + let mut tup = serializer.serialize_tuple(32)?; + for byte in self.compress().as_bytes().iter() { + tup.serialize_element(byte)?; + } + tup.end() + } +} + +#[cfg(feature = "serde")] +impl Serialize for CompressedRistretto { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + use serde::ser::SerializeTuple; + let mut tup = serializer.serialize_tuple(32)?; + for byte in self.as_bytes().iter() { + tup.serialize_element(byte)?; + } + tup.end() + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for RistrettoPoint { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + struct RistrettoPointVisitor; + + impl<'de> Visitor<'de> for RistrettoPointVisitor { + type Value = RistrettoPoint; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("a valid point in Ristretto format") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de> + { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = seq.next_element()? + .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + CompressedRistretto(bytes) + .decompress() + .ok_or(serde::de::Error::custom("decompression failed")) + } + } + + deserializer.deserialize_tuple(32, RistrettoPointVisitor) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for CompressedRistretto { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + struct CompressedRistrettoVisitor; + + impl<'de> Visitor<'de> for CompressedRistrettoVisitor { + type Value = CompressedRistretto; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("32 bytes of data") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de> + { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = seq.next_element()? + .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + Ok(CompressedRistretto(bytes)) + } + } + + deserializer.deserialize_tuple(32, CompressedRistrettoVisitor) + } +} + +// ------------------------------------------------------------------------ +// Internal point representations +// ------------------------------------------------------------------------ + +/// A `RistrettoPoint` represents a point in the Ristretto group for +/// Curve25519. Ristretto, a variant of Decaf, constructs a +/// prime-order group as a quotient group of a subgroup of (the +/// Edwards form of) Curve25519. +/// +/// Internally, a `RistrettoPoint` is implemented as a wrapper type +/// around `EdwardsPoint`, with custom equality, compression, and +/// decompression routines to account for the quotient. This means that +/// operations on `RistrettoPoint`s are exactly as fast as operations on +/// `EdwardsPoint`s. +/// +#[derive(Copy, Clone)] +pub struct RistrettoPoint(pub(crate) EdwardsPoint); + +impl RistrettoPoint { + /// Compress this point using the Ristretto encoding. + pub fn compress(&self) -> CompressedRistretto { + let mut X = self.0.X; + let mut Y = self.0.Y; + let Z = &self.0.Z; + let T = &self.0.T; + + let u1 = &(Z + &Y) * &(Z - &Y); + let u2 = &X * &Y; + // Ignore return value since this is always square + let (_, invsqrt) = (&u1 * &u2.square()).invsqrt(); + let i1 = &invsqrt * &u1; + let i2 = &invsqrt * &u2; + let z_inv = &i1 * &(&i2 * T); + let mut den_inv = i2; + + let iX = &X * &constants::SQRT_M1; + let iY = &Y * &constants::SQRT_M1; + let ristretto_magic = &constants::INVSQRT_A_MINUS_D; + let enchanted_denominator = &i1 * ristretto_magic; + + let rotate = (T * &z_inv).is_negative(); + + X.conditional_assign(&iY, rotate); + Y.conditional_assign(&iX, rotate); + den_inv.conditional_assign(&enchanted_denominator, rotate); + + Y.conditional_negate((&X * &z_inv).is_negative()); + + let mut s = &den_inv * &(Z - &Y); + let s_is_negative = s.is_negative(); + s.conditional_negate(s_is_negative); + + CompressedRistretto(s.to_bytes()) + } + + /// Double-and-compress a batch of points. The Ristretto encoding + /// is not batchable, since it requires an inverse square root. + /// + /// However, given input points \\( P\_1, \ldots, P\_n, \\) + /// it is possible to compute the encodings of their doubles \\( + /// \mathrm{enc}( [2]P\_1), \ldots, \mathrm{enc}( [2]P\_n ) \\) + /// in a batch. + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # use curve25519_dalek::ristretto::RistrettoPoint; + /// extern crate rand_core; + /// use rand_core::OsRng; + /// + /// # // Need fn main() here in comment so the doctest compiles + /// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests + /// # fn main() { + /// let mut rng = OsRng; + /// let points: Vec = + /// (0..32).map(|_| RistrettoPoint::random(&mut rng)).collect(); + /// + /// let compressed = RistrettoPoint::double_and_compress_batch(&points); + /// + /// for (P, P2_compressed) in points.iter().zip(compressed.iter()) { + /// assert_eq!(*P2_compressed, (P + P).compress()); + /// } + /// # } + /// ``` + #[cfg(feature = "alloc")] + pub fn double_and_compress_batch<'a, I>(points: I) -> Vec + where I: IntoIterator + { + #[derive(Copy, Clone, Debug)] + struct BatchCompressState { + e: FieldElement, + f: FieldElement, + g: FieldElement, + h: FieldElement, + eg: FieldElement, + fh: FieldElement, + } + + impl BatchCompressState { + fn efgh(&self) -> FieldElement { + &self.eg * &self.fh + } + } + + impl<'a> From<&'a RistrettoPoint> for BatchCompressState { + fn from(P: &'a RistrettoPoint) -> BatchCompressState { + let XX = P.0.X.square(); + let YY = P.0.Y.square(); + let ZZ = P.0.Z.square(); + let dTT = &P.0.T.square() * &constants::EDWARDS_D; + + let e = &P.0.X * &(&P.0.Y + &P.0.Y); // = 2*X*Y + let f = &ZZ + &dTT; // = Z^2 + d*T^2 + let g = &YY + &XX; // = Y^2 - a*X^2 + let h = &ZZ - &dTT; // = Z^2 - d*T^2 + + let eg = &e * &g; + let fh = &f * &h; + + BatchCompressState{ e, f, g, h, eg, fh } + } + } + + let states: Vec = points.into_iter().map(BatchCompressState::from).collect(); + + let mut invs: Vec = states.iter().map(|state| state.efgh()).collect(); + + FieldElement::batch_invert(&mut invs[..]); + + states.iter().zip(invs.iter()).map(|(state, inv): (&BatchCompressState, &FieldElement)| { + let Zinv = &state.eg * &inv; + let Tinv = &state.fh * &inv; + + let mut magic = constants::INVSQRT_A_MINUS_D; + + let negcheck1 = (&state.eg * &Zinv).is_negative(); + + let mut e = state.e; + let mut g = state.g; + let mut h = state.h; + + let minus_e = -&e; + let f_times_sqrta = &state.f * &constants::SQRT_M1; + + e.conditional_assign(&state.g, negcheck1); + g.conditional_assign(&minus_e, negcheck1); + h.conditional_assign(&f_times_sqrta, negcheck1); + + magic.conditional_assign(&constants::SQRT_M1, negcheck1); + + let negcheck2 = (&(&h * &e) * &Zinv).is_negative(); + + g.conditional_negate(negcheck2); + + let mut s = &(&h - &g) * &(&magic * &(&g * &Tinv)); + + let s_is_negative = s.is_negative(); + s.conditional_negate(s_is_negative); + + CompressedRistretto(s.to_bytes()) + }).collect() + } + + + /// Return the coset self + E[4], for debugging. + fn coset4(&self) -> [EdwardsPoint; 4] { + [ self.0 + , &self.0 + &constants::EIGHT_TORSION[2] + , &self.0 + &constants::EIGHT_TORSION[4] + , &self.0 + &constants::EIGHT_TORSION[6] + ] + } + + /// Computes the Ristretto Elligator map. + /// + /// # Note + /// + /// This method is not public because it's just used for hashing + /// to a point -- proper elligator support is deferred for now. + pub(crate) fn elligator_ristretto_flavor(r_0: &FieldElement) -> RistrettoPoint { + let i = &constants::SQRT_M1; + let d = &constants::EDWARDS_D; + let one_minus_d_sq = &constants::ONE_MINUS_EDWARDS_D_SQUARED; + let d_minus_one_sq = &constants::EDWARDS_D_MINUS_ONE_SQUARED; + let mut c = constants::MINUS_ONE; + + let one = FieldElement::one(); + + let r = i * &r_0.square(); + let N_s = &(&r + &one) * &one_minus_d_sq; + let D = &(&c - &(d * &r)) * &(&r + d); + + let (Ns_D_is_sq, mut s) = FieldElement::sqrt_ratio_i(&N_s, &D); + let mut s_prime = &s * r_0; + let s_prime_is_pos = !s_prime.is_negative(); + s_prime.conditional_negate(s_prime_is_pos); + + s.conditional_assign(&s_prime, !Ns_D_is_sq); + c.conditional_assign(&r, !Ns_D_is_sq); + + let N_t = &(&(&c * &(&r - &one)) * &d_minus_one_sq) - &D; + let s_sq = s.square(); + + use backend::serial::curve_models::CompletedPoint; + + // The conversion from W_i is exactly the conversion from P1xP1. + RistrettoPoint(CompletedPoint{ + X: &(&s + &s) * &D, + Z: &N_t * &constants::SQRT_AD_MINUS_ONE, + Y: &FieldElement::one() - &s_sq, + T: &FieldElement::one() + &s_sq, + }.to_extended()) + } + + /// Return a `RistrettoPoint` chosen uniformly at random using a user-provided RNG. + /// + /// # Inputs + /// + /// * `rng`: any RNG which implements the `RngCore + CryptoRng` interface. + /// + /// # Returns + /// + /// A random element of the Ristretto group. + /// + /// # Implementation + /// + /// Uses the Ristretto-flavoured Elligator 2 map, so that the + /// discrete log of the output point with respect to any other + /// point should be unknown. The map is applied twice and the + /// results are added, to ensure a uniform distribution. + pub fn random(rng: &mut R) -> Self { + let mut uniform_bytes = [0u8; 64]; + rng.fill_bytes(&mut uniform_bytes); + + RistrettoPoint::from_uniform_bytes(&uniform_bytes) + } + + /// Hash a slice of bytes into a `RistrettoPoint`. + /// + /// Takes a type parameter `D`, which is any `Digest` producing 64 + /// bytes of output. + /// + /// Convenience wrapper around `from_hash`. + /// + /// # Implementation + /// + /// Uses the Ristretto-flavoured Elligator 2 map, so that the + /// discrete log of the output point with respect to any other + /// point should be unknown. The map is applied twice and the + /// results are added, to ensure a uniform distribution. + /// + /// # Example + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # use curve25519_dalek::ristretto::RistrettoPoint; + /// extern crate sha2; + /// use sha2::Sha512; + /// + /// # // Need fn main() here in comment so the doctest compiles + /// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests + /// # fn main() { + /// let msg = "To really appreciate architecture, you may even need to commit a murder"; + /// let P = RistrettoPoint::hash_from_bytes::(msg.as_bytes()); + /// # } + /// ``` + /// + pub fn hash_from_bytes(input: &[u8]) -> RistrettoPoint + where D: Digest + Default + { + let mut hash = D::default(); + hash.update(input); + RistrettoPoint::from_hash(hash) + } + + /// Construct a `RistrettoPoint` from an existing `Digest` instance. + /// + /// Use this instead of `hash_from_bytes` if it is more convenient + /// to stream data into the `Digest` than to pass a single byte + /// slice. + pub fn from_hash(hash: D) -> RistrettoPoint + where D: Digest + Default + { + // dealing with generic arrays is clumsy, until const generics land + let output = hash.finalize(); + let mut output_bytes = [0u8; 64]; + output_bytes.copy_from_slice(&output.as_slice()); + + RistrettoPoint::from_uniform_bytes(&output_bytes) + } + + /// Construct a `RistrettoPoint` from 64 bytes of data. + /// + /// If the input bytes are uniformly distributed, the resulting + /// point will be uniformly distributed over the group, and its + /// discrete log with respect to other points should be unknown. + /// + /// # Implementation + /// + /// This function splits the input array into two 32-byte halves, + /// takes the low 255 bits of each half mod p, applies the + /// Ristretto-flavored Elligator map to each, and adds the results. + pub fn from_uniform_bytes(bytes: &[u8; 64]) -> RistrettoPoint { + let mut r_1_bytes = [0u8; 32]; + r_1_bytes.copy_from_slice(&bytes[0..32]); + let r_1 = FieldElement::from_bytes(&r_1_bytes); + let R_1 = RistrettoPoint::elligator_ristretto_flavor(&r_1); + + let mut r_2_bytes = [0u8; 32]; + r_2_bytes.copy_from_slice(&bytes[32..64]); + let r_2 = FieldElement::from_bytes(&r_2_bytes); + let R_2 = RistrettoPoint::elligator_ristretto_flavor(&r_2); + + // Applying Elligator twice and adding the results ensures a + // uniform distribution. + &R_1 + &R_2 + } +} + +impl Identity for RistrettoPoint { + fn identity() -> RistrettoPoint { + RistrettoPoint(EdwardsPoint::identity()) + } +} + +impl Default for RistrettoPoint { + fn default() -> RistrettoPoint { + RistrettoPoint::identity() + } +} + +// ------------------------------------------------------------------------ +// Equality +// ------------------------------------------------------------------------ + +impl PartialEq for RistrettoPoint { + fn eq(&self, other: &RistrettoPoint) -> bool { + self.ct_eq(other).unwrap_u8() == 1u8 + } +} + +impl ConstantTimeEq for RistrettoPoint { + /// Test equality between two `RistrettoPoint`s. + /// + /// # Returns + /// + /// * `Choice(1)` if the two `RistrettoPoint`s are equal; + /// * `Choice(0)` otherwise. + fn ct_eq(&self, other: &RistrettoPoint) -> Choice { + let X1Y2 = &self.0.X * &other.0.Y; + let Y1X2 = &self.0.Y * &other.0.X; + let X1X2 = &self.0.X * &other.0.X; + let Y1Y2 = &self.0.Y * &other.0.Y; + + X1Y2.ct_eq(&Y1X2) | X1X2.ct_eq(&Y1Y2) + } +} + +impl Eq for RistrettoPoint {} + +// ------------------------------------------------------------------------ +// Arithmetic +// ------------------------------------------------------------------------ + +impl<'a, 'b> Add<&'b RistrettoPoint> for &'a RistrettoPoint { + type Output = RistrettoPoint; + + fn add(self, other: &'b RistrettoPoint) -> RistrettoPoint { + RistrettoPoint(&self.0 + &other.0) + } +} + +define_add_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint, Output = RistrettoPoint); + +impl<'b> AddAssign<&'b RistrettoPoint> for RistrettoPoint { + fn add_assign(&mut self, _rhs: &RistrettoPoint) { + *self = (self as &RistrettoPoint) + _rhs; + } +} + +define_add_assign_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint); + +impl<'a, 'b> Sub<&'b RistrettoPoint> for &'a RistrettoPoint { + type Output = RistrettoPoint; + + fn sub(self, other: &'b RistrettoPoint) -> RistrettoPoint { + RistrettoPoint(&self.0 - &other.0) + } +} + +define_sub_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint, Output = RistrettoPoint); + +impl<'b> SubAssign<&'b RistrettoPoint> for RistrettoPoint { + fn sub_assign(&mut self, _rhs: &RistrettoPoint) { + *self = (self as &RistrettoPoint) - _rhs; + } +} + +define_sub_assign_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint); + +impl Sum for RistrettoPoint +where + T: Borrow +{ + fn sum(iter: I) -> Self + where + I: Iterator + { + iter.fold(RistrettoPoint::identity(), |acc, item| acc + item.borrow()) + } +} + +impl<'a> Neg for &'a RistrettoPoint { + type Output = RistrettoPoint; + + fn neg(self) -> RistrettoPoint { + RistrettoPoint(-&self.0) + } +} + +impl Neg for RistrettoPoint { + type Output = RistrettoPoint; + + fn neg(self) -> RistrettoPoint { + -&self + } +} + +impl<'b> MulAssign<&'b Scalar> for RistrettoPoint { + fn mul_assign(&mut self, scalar: &'b Scalar) { + let result = (self as &RistrettoPoint) * scalar; + *self = result; + } +} + +impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoPoint { + type Output = RistrettoPoint; + /// Scalar multiplication: compute `scalar * self`. + fn mul(self, scalar: &'b Scalar) -> RistrettoPoint { + RistrettoPoint(self.0 * scalar) + } +} + +impl<'a, 'b> Mul<&'b RistrettoPoint> for &'a Scalar { + type Output = RistrettoPoint; + + /// Scalar multiplication: compute `self * scalar`. + fn mul(self, point: &'b RistrettoPoint) -> RistrettoPoint { + RistrettoPoint(self * point.0) + } +} + +define_mul_assign_variants!(LHS = RistrettoPoint, RHS = Scalar); + +define_mul_variants!(LHS = RistrettoPoint, RHS = Scalar, Output = RistrettoPoint); +define_mul_variants!(LHS = Scalar, RHS = RistrettoPoint, Output = RistrettoPoint); + +// ------------------------------------------------------------------------ +// Multiscalar Multiplication impls +// ------------------------------------------------------------------------ + +// These use iterator combinators to unwrap the underlying points and +// forward to the EdwardsPoint implementations. + +#[cfg(feature = "alloc")] +impl MultiscalarMul for RistrettoPoint { + type Point = RistrettoPoint; + + fn multiscalar_mul(scalars: I, points: J) -> RistrettoPoint + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + { + let extended_points = points.into_iter().map(|P| P.borrow().0); + RistrettoPoint( + EdwardsPoint::multiscalar_mul(scalars, extended_points) + ) + } +} + +#[cfg(feature = "alloc")] +impl VartimeMultiscalarMul for RistrettoPoint { + type Point = RistrettoPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + let extended_points = points.into_iter().map(|opt_P| opt_P.map(|P| P.borrow().0)); + + EdwardsPoint::optional_multiscalar_mul(scalars, extended_points).map(RistrettoPoint) + } +} + +/// Precomputation for variable-time multiscalar multiplication with `RistrettoPoint`s. +// This wraps the inner implementation in a facade type so that we can +// decouple stability of the inner type from the stability of the +// outer type. +#[cfg(feature = "alloc")] +pub struct VartimeRistrettoPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); + +#[cfg(feature = "alloc")] +impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation { + type Point = RistrettoPoint; + + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + Self( + scalar_mul::precomputed_straus::VartimePrecomputedStraus::new( + static_points.into_iter().map(|P| P.borrow().0), + ), + ) + } + + fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator>, + { + self.0 + .optional_mixed_multiscalar_mul( + static_scalars, + dynamic_scalars, + dynamic_points.into_iter().map(|P_opt| P_opt.map(|P| P.0)), + ) + .map(RistrettoPoint) + } +} + +impl RistrettoPoint { + /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the + /// Ristretto basepoint. + pub fn vartime_double_scalar_mul_basepoint( + a: &Scalar, + A: &RistrettoPoint, + b: &Scalar, + ) -> RistrettoPoint { + RistrettoPoint( + EdwardsPoint::vartime_double_scalar_mul_basepoint(a, &A.0, b) + ) + } +} + +/// A precomputed table of multiples of a basepoint, used to accelerate +/// scalar multiplication. +/// +/// A precomputed table of multiples of the Ristretto basepoint is +/// available in the `constants` module: +/// ``` +/// use curve25519_dalek::constants; +/// use curve25519_dalek::scalar::Scalar; +/// +/// let a = Scalar::from(87329482u64); +/// let P = &a * &constants::RISTRETTO_BASEPOINT_TABLE; +/// ``` +#[derive(Clone)] +pub struct RistrettoBasepointTable(pub(crate) EdwardsBasepointTable); + +impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable { + type Output = RistrettoPoint; + + fn mul(self, scalar: &'b Scalar) -> RistrettoPoint { + RistrettoPoint(&self.0 * scalar) + } +} + +impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar { + type Output = RistrettoPoint; + + fn mul(self, basepoint_table: &'a RistrettoBasepointTable) -> RistrettoPoint { + RistrettoPoint(self * &basepoint_table.0) + } +} + +impl RistrettoBasepointTable { + /// Create a precomputed table of multiples of the given `basepoint`. + pub fn create(basepoint: &RistrettoPoint) -> RistrettoBasepointTable { + RistrettoBasepointTable(EdwardsBasepointTable::create(&basepoint.0)) + } + + /// Get the basepoint for this table as a `RistrettoPoint`. + pub fn basepoint(&self) -> RistrettoPoint { + RistrettoPoint(self.0.basepoint()) + } +} + +// ------------------------------------------------------------------------ +// Constant-time conditional selection +// ------------------------------------------------------------------------ + +impl ConditionallySelectable for RistrettoPoint { + /// Conditionally select between `self` and `other`. + /// + /// # Example + /// + /// ``` + /// # extern crate subtle; + /// # extern crate curve25519_dalek; + /// # + /// use subtle::ConditionallySelectable; + /// use subtle::Choice; + /// # + /// # use curve25519_dalek::traits::Identity; + /// # use curve25519_dalek::ristretto::RistrettoPoint; + /// # use curve25519_dalek::constants; + /// # fn main() { + /// + /// let A = RistrettoPoint::identity(); + /// let B = constants::RISTRETTO_BASEPOINT_POINT; + /// + /// let mut P = A; + /// + /// P = RistrettoPoint::conditional_select(&A, &B, Choice::from(0)); + /// assert_eq!(P, A); + /// P = RistrettoPoint::conditional_select(&A, &B, Choice::from(1)); + /// assert_eq!(P, B); + /// # } + /// ``` + fn conditional_select( + a: &RistrettoPoint, + b: &RistrettoPoint, + choice: Choice, + ) -> RistrettoPoint { + RistrettoPoint(EdwardsPoint::conditional_select(&a.0, &b.0, choice)) + } +} + +// ------------------------------------------------------------------------ +// Debug traits +// ------------------------------------------------------------------------ + +impl Debug for CompressedRistretto { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "CompressedRistretto: {:?}", self.as_bytes()) + } +} + +impl Debug for RistrettoPoint { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + let coset = self.coset4(); + write!(f, "RistrettoPoint: coset \n{:?}\n{:?}\n{:?}\n{:?}", + coset[0], coset[1], coset[2], coset[3]) + } +} + +// ------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------ + +#[cfg(test)] +mod test { + use rand_core::OsRng; + + use scalar::Scalar; + use constants; + use edwards::CompressedEdwardsY; + use traits::{Identity}; + use super::*; + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_basepoint_roundtrip() { + use bincode; + + let encoded = bincode::serialize(&constants::RISTRETTO_BASEPOINT_POINT).unwrap(); + let enc_compressed = bincode::serialize(&constants::RISTRETTO_BASEPOINT_COMPRESSED).unwrap(); + assert_eq!(encoded, enc_compressed); + + // Check that the encoding is 32 bytes exactly + assert_eq!(encoded.len(), 32); + + let dec_uncompressed: RistrettoPoint = bincode::deserialize(&encoded).unwrap(); + let dec_compressed: CompressedRistretto = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(dec_uncompressed, constants::RISTRETTO_BASEPOINT_POINT); + assert_eq!(dec_compressed, constants::RISTRETTO_BASEPOINT_COMPRESSED); + + // Check that the encoding itself matches the usual one + let raw_bytes = constants::RISTRETTO_BASEPOINT_COMPRESSED.as_bytes(); + let bp: RistrettoPoint = bincode::deserialize(raw_bytes).unwrap(); + assert_eq!(bp, constants::RISTRETTO_BASEPOINT_POINT); + } + + #[test] + fn scalarmult_ristrettopoint_works_both_ways() { + let P = constants::RISTRETTO_BASEPOINT_POINT; + let s = Scalar::from(999u64); + + let P1 = &P * &s; + let P2 = &s * &P; + + assert!(P1.compress().as_bytes() == P2.compress().as_bytes()); + } + + #[test] + fn impl_sum() { + + // Test that sum works for non-empty iterators + let BASE = constants::RISTRETTO_BASEPOINT_POINT; + + let s1 = Scalar::from(999u64); + let P1 = &BASE * &s1; + + let s2 = Scalar::from(333u64); + let P2 = &BASE * &s2; + + let vec = vec![P1.clone(), P2.clone()]; + let sum: RistrettoPoint = vec.iter().sum(); + + assert_eq!(sum, P1 + P2); + + // Test that sum works for the empty iterator + let empty_vector: Vec = vec![]; + let sum: RistrettoPoint = empty_vector.iter().sum(); + + assert_eq!(sum, RistrettoPoint::identity()); + + // Test that sum works on owning iterators + let s = Scalar::from(2u64); + let mapped = vec.iter().map(|x| x * s); + let sum: RistrettoPoint = mapped.sum(); + + assert_eq!(sum, &P1 * &s + &P2 * &s); + } + + #[test] + fn decompress_negative_s_fails() { + // constants::d is neg, so decompression should fail as |d| != d. + let bad_compressed = CompressedRistretto(constants::EDWARDS_D.to_bytes()); + assert!(bad_compressed.decompress().is_none()); + } + + #[test] + fn decompress_id() { + let compressed_id = CompressedRistretto::identity(); + let id = compressed_id.decompress().unwrap(); + let mut identity_in_coset = false; + for P in &id.coset4() { + if P.compress() == CompressedEdwardsY::identity() { + identity_in_coset = true; + } + } + assert!(identity_in_coset); + } + + #[test] + fn compress_id() { + let id = RistrettoPoint::identity(); + assert_eq!(id.compress(), CompressedRistretto::identity()); + } + + #[test] + fn basepoint_roundtrip() { + let bp_compressed_ristretto = constants::RISTRETTO_BASEPOINT_POINT.compress(); + let bp_recaf = bp_compressed_ristretto.decompress().unwrap().0; + // Check that bp_recaf differs from bp by a point of order 4 + let diff = &constants::RISTRETTO_BASEPOINT_POINT.0 - &bp_recaf; + let diff4 = diff.mul_by_pow_2(2); + assert_eq!(diff4.compress(), CompressedEdwardsY::identity()); + } + + #[test] + fn encodings_of_small_multiples_of_basepoint() { + // Table of encodings of i*basepoint + // Generated using ristretto.sage + let compressed = [ + CompressedRistretto([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + CompressedRistretto([226, 242, 174, 10, 106, 188, 78, 113, 168, 132, 169, 97, 197, 0, 81, 95, 88, 227, 11, 106, 165, 130, 221, 141, 182, 166, 89, 69, 224, 141, 45, 118]), + CompressedRistretto([106, 73, 50, 16, 247, 73, 156, 209, 127, 236, 181, 16, 174, 12, 234, 35, 161, 16, 232, 213, 185, 1, 248, 172, 173, 211, 9, 92, 115, 163, 185, 25]), + CompressedRistretto([148, 116, 31, 93, 93, 82, 117, 94, 206, 79, 35, 240, 68, 238, 39, 213, 209, 234, 30, 43, 209, 150, 180, 98, 22, 107, 22, 21, 42, 157, 2, 89]), + CompressedRistretto([218, 128, 134, 39, 115, 53, 139, 70, 111, 250, 223, 224, 179, 41, 58, 179, 217, 253, 83, 197, 234, 108, 149, 83, 88, 245, 104, 50, 45, 175, 106, 87]), + CompressedRistretto([232, 130, 177, 49, 1, 107, 82, 193, 211, 51, 112, 128, 24, 124, 247, 104, 66, 62, 252, 203, 181, 23, 187, 73, 90, 184, 18, 196, 22, 15, 244, 78]), + CompressedRistretto([246, 71, 70, 211, 201, 43, 19, 5, 14, 216, 216, 2, 54, 167, 240, 0, 124, 59, 63, 150, 47, 91, 167, 147, 209, 154, 96, 30, 187, 29, 244, 3]), + CompressedRistretto([68, 245, 53, 32, 146, 110, 200, 31, 189, 90, 56, 120, 69, 190, 183, 223, 133, 169, 106, 36, 236, 225, 135, 56, 189, 207, 166, 167, 130, 42, 23, 109]), + CompressedRistretto([144, 50, 147, 216, 242, 40, 126, 190, 16, 226, 55, 77, 193, 165, 62, 11, 200, 135, 229, 146, 105, 159, 2, 208, 119, 213, 38, 60, 221, 85, 96, 28]), + CompressedRistretto([2, 98, 42, 206, 143, 115, 3, 163, 28, 175, 198, 63, 143, 196, 143, 220, 22, 225, 200, 200, 210, 52, 178, 240, 214, 104, 82, 130, 169, 7, 96, 49]), + CompressedRistretto([32, 112, 111, 215, 136, 178, 114, 10, 30, 210, 165, 218, 212, 149, 43, 1, 244, 19, 188, 240, 231, 86, 77, 232, 205, 200, 22, 104, 158, 45, 185, 95]), + CompressedRistretto([188, 232, 63, 139, 165, 221, 47, 165, 114, 134, 76, 36, 186, 24, 16, 249, 82, 43, 198, 0, 74, 254, 149, 135, 122, 199, 50, 65, 202, 253, 171, 66]), + CompressedRistretto([228, 84, 158, 225, 107, 154, 160, 48, 153, 202, 32, 140, 103, 173, 175, 202, 250, 76, 63, 62, 78, 83, 3, 222, 96, 38, 227, 202, 143, 248, 68, 96]), + CompressedRistretto([170, 82, 224, 0, 223, 46, 22, 245, 95, 177, 3, 47, 195, 59, 196, 39, 66, 218, 214, 189, 90, 143, 192, 190, 1, 103, 67, 108, 89, 72, 80, 31]), + CompressedRistretto([70, 55, 107, 128, 244, 9, 178, 157, 194, 181, 246, 240, 197, 37, 145, 153, 8, 150, 229, 113, 111, 65, 71, 124, 211, 0, 133, 171, 127, 16, 48, 30]), + CompressedRistretto([224, 196, 24, 247, 200, 217, 196, 205, 215, 57, 91, 147, 234, 18, 79, 58, 217, 144, 33, 187, 104, 29, 252, 51, 2, 169, 217, 154, 46, 83, 230, 78]), + ]; + let mut bp = RistrettoPoint::identity(); + for i in 0..16 { + assert_eq!(bp.compress(), compressed[i]); + bp = &bp + &constants::RISTRETTO_BASEPOINT_POINT; + } + } + + #[test] + fn four_torsion_basepoint() { + let bp = constants::RISTRETTO_BASEPOINT_POINT; + let bp_coset = bp.coset4(); + for i in 0..4 { + assert_eq!(bp, RistrettoPoint(bp_coset[i])); + } + } + + #[test] + fn four_torsion_random() { + let mut rng = OsRng; + let B = &constants::RISTRETTO_BASEPOINT_TABLE; + let P = B * &Scalar::random(&mut rng); + let P_coset = P.coset4(); + for i in 0..4 { + assert_eq!(P, RistrettoPoint(P_coset[i])); + } + } + + #[test] + fn elligator_vs_ristretto_sage() { + // Test vectors extracted from ristretto.sage. + // + // Notice that all of the byte sequences have bit 255 set to 0; this is because + // ristretto.sage does not mask the high bit of a field element. When the high bit is set, + // the ristretto.sage elligator implementation gives different results, since it takes a + // different field element as input. + let bytes: [[u8;32]; 16] = [ + [184, 249, 135, 49, 253, 123, 89, 113, 67, 160, 6, 239, 7, 105, 211, 41, 192, 249, 185, 57, 9, 102, 70, 198, 15, 127, 7, 26, 160, 102, 134, 71], + [229, 14, 241, 227, 75, 9, 118, 60, 128, 153, 226, 21, 183, 217, 91, 136, 98, 0, 231, 156, 124, 77, 82, 139, 142, 134, 164, 169, 169, 62, 250, 52], + [115, 109, 36, 220, 180, 223, 99, 6, 204, 169, 19, 29, 169, 68, 84, 23, 21, 109, 189, 149, 127, 205, 91, 102, 172, 35, 112, 35, 134, 69, 186, 34], + [16, 49, 96, 107, 171, 199, 164, 9, 129, 16, 64, 62, 241, 63, 132, 173, 209, 160, 112, 215, 105, 50, 157, 81, 253, 105, 1, 154, 229, 25, 120, 83], + [156, 131, 161, 162, 236, 251, 5, 187, 167, 171, 17, 178, 148, 210, 90, 207, 86, 21, 79, 161, 167, 215, 234, 1, 136, 242, 182, 248, 38, 85, 79, 86], + [251, 177, 124, 54, 18, 101, 75, 235, 245, 186, 19, 46, 133, 157, 229, 64, 10, 136, 181, 185, 78, 144, 254, 167, 137, 49, 107, 10, 61, 10, 21, 25], + [232, 193, 20, 68, 240, 77, 186, 77, 183, 40, 44, 86, 150, 31, 198, 212, 76, 81, 3, 217, 197, 8, 126, 128, 126, 152, 164, 208, 153, 44, 189, 77], + [173, 229, 149, 177, 37, 230, 30, 69, 61, 56, 172, 190, 219, 115, 167, 194, 71, 134, 59, 75, 28, 244, 118, 26, 162, 97, 64, 16, 15, 189, 30, 64], + [106, 71, 61, 107, 250, 117, 42, 151, 91, 202, 212, 100, 52, 188, 190, 21, 125, 218, 31, 18, 253, 241, 160, 133, 57, 242, 3, 164, 189, 68, 111, 75], + [112, 204, 182, 90, 220, 198, 120, 73, 173, 107, 193, 17, 227, 40, 162, 36, 150, 141, 235, 55, 172, 183, 12, 39, 194, 136, 43, 153, 244, 118, 91, 89], + [111, 24, 203, 123, 254, 189, 11, 162, 51, 196, 163, 136, 204, 143, 10, 222, 33, 112, 81, 205, 34, 35, 8, 66, 90, 6, 164, 58, 170, 177, 34, 25], + [225, 183, 30, 52, 236, 82, 6, 183, 109, 25, 227, 181, 25, 82, 41, 193, 80, 77, 161, 80, 242, 203, 79, 204, 136, 245, 131, 110, 237, 106, 3, 58], + [207, 246, 38, 56, 30, 86, 176, 90, 27, 200, 61, 42, 221, 27, 56, 210, 79, 178, 189, 120, 68, 193, 120, 167, 77, 185, 53, 197, 124, 128, 191, 126], + [1, 136, 215, 80, 240, 46, 63, 147, 16, 244, 230, 207, 82, 189, 74, 50, 106, 169, 138, 86, 30, 131, 214, 202, 166, 125, 251, 228, 98, 24, 36, 21], + [210, 207, 228, 56, 155, 116, 207, 54, 84, 195, 251, 215, 249, 199, 116, 75, 109, 239, 196, 251, 194, 246, 252, 228, 70, 146, 156, 35, 25, 39, 241, 4], + [34, 116, 123, 9, 8, 40, 93, 189, 9, 103, 57, 103, 66, 227, 3, 2, 157, 107, 134, 219, 202, 74, 230, 154, 78, 107, 219, 195, 214, 14, 84, 80], + ]; + let encoded_images: [CompressedRistretto; 16] = [ + CompressedRistretto([176, 157, 237, 97, 66, 29, 140, 166, 168, 94, 26, 157, 212, 216, 229, 160, 195, 246, 232, 239, 169, 112, 63, 193, 64, 32, 152, 69, 11, 190, 246, 86]), + CompressedRistretto([234, 141, 77, 203, 181, 225, 250, 74, 171, 62, 15, 118, 78, 212, 150, 19, 131, 14, 188, 238, 194, 244, 141, 138, 166, 162, 83, 122, 228, 201, 19, 26]), + CompressedRistretto([232, 231, 51, 92, 5, 168, 80, 36, 173, 179, 104, 68, 186, 149, 68, 40, 140, 170, 27, 103, 99, 140, 21, 242, 43, 62, 250, 134, 208, 255, 61, 89]), + CompressedRistretto([208, 120, 140, 129, 177, 179, 237, 159, 252, 160, 28, 13, 206, 5, 211, 241, 192, 218, 1, 97, 130, 241, 20, 169, 119, 46, 246, 29, 79, 80, 77, 84]), + CompressedRistretto([202, 11, 236, 145, 58, 12, 181, 157, 209, 6, 213, 88, 75, 147, 11, 119, 191, 139, 47, 142, 33, 36, 153, 193, 223, 183, 178, 8, 205, 120, 248, 110]), + CompressedRistretto([26, 66, 231, 67, 203, 175, 116, 130, 32, 136, 62, 253, 215, 46, 5, 214, 166, 248, 108, 237, 216, 71, 244, 173, 72, 133, 82, 6, 143, 240, 104, 41]), + CompressedRistretto([40, 157, 102, 96, 201, 223, 200, 197, 150, 181, 106, 83, 103, 126, 143, 33, 145, 230, 78, 6, 171, 146, 210, 143, 112, 5, 245, 23, 183, 138, 18, 120]), + CompressedRistretto([220, 37, 27, 203, 239, 196, 176, 131, 37, 66, 188, 243, 185, 250, 113, 23, 167, 211, 154, 243, 168, 215, 54, 171, 159, 36, 195, 81, 13, 150, 43, 43]), + CompressedRistretto([232, 121, 176, 222, 183, 196, 159, 90, 238, 193, 105, 52, 101, 167, 244, 170, 121, 114, 196, 6, 67, 152, 80, 185, 221, 7, 83, 105, 176, 208, 224, 121]), + CompressedRistretto([226, 181, 183, 52, 241, 163, 61, 179, 221, 207, 220, 73, 245, 242, 25, 236, 67, 84, 179, 222, 167, 62, 167, 182, 32, 9, 92, 30, 165, 127, 204, 68]), + CompressedRistretto([226, 119, 16, 242, 200, 139, 240, 87, 11, 222, 92, 146, 156, 243, 46, 119, 65, 59, 1, 248, 92, 183, 50, 175, 87, 40, 206, 53, 208, 220, 148, 13]), + CompressedRistretto([70, 240, 79, 112, 54, 157, 228, 146, 74, 122, 216, 88, 232, 62, 158, 13, 14, 146, 115, 117, 176, 222, 90, 225, 244, 23, 94, 190, 150, 7, 136, 96]), + CompressedRistretto([22, 71, 241, 103, 45, 193, 195, 144, 183, 101, 154, 50, 39, 68, 49, 110, 51, 44, 62, 0, 229, 113, 72, 81, 168, 29, 73, 106, 102, 40, 132, 24]), + CompressedRistretto([196, 133, 107, 11, 130, 105, 74, 33, 204, 171, 133, 221, 174, 193, 241, 36, 38, 179, 196, 107, 219, 185, 181, 253, 228, 47, 155, 42, 231, 73, 41, 78]), + CompressedRistretto([58, 255, 225, 197, 115, 208, 160, 143, 39, 197, 82, 69, 143, 235, 92, 170, 74, 40, 57, 11, 171, 227, 26, 185, 217, 207, 90, 185, 197, 190, 35, 60]), + CompressedRistretto([88, 43, 92, 118, 223, 136, 105, 145, 238, 186, 115, 8, 214, 112, 153, 253, 38, 108, 205, 230, 157, 130, 11, 66, 101, 85, 253, 110, 110, 14, 148, 112]), + ]; + for i in 0..16 { + let r_0 = FieldElement::from_bytes(&bytes[i]); + let Q = RistrettoPoint::elligator_ristretto_flavor(&r_0); + assert_eq!(Q.compress(), encoded_images[i]); + } + } + + #[test] + fn random_roundtrip() { + let mut rng = OsRng; + let B = &constants::RISTRETTO_BASEPOINT_TABLE; + for _ in 0..100 { + let P = B * &Scalar::random(&mut rng); + let compressed_P = P.compress(); + let Q = compressed_P.decompress().unwrap(); + assert_eq!(P, Q); + } + } + + #[test] + fn double_and_compress_1024_random_points() { + let mut rng = OsRng; + + let points: Vec = + (0..1024).map(|_| RistrettoPoint::random(&mut rng)).collect(); + + let compressed = RistrettoPoint::double_and_compress_batch(&points); + + for (P, P2_compressed) in points.iter().zip(compressed.iter()) { + assert_eq!(*P2_compressed, (P + P).compress()); + } + } + + #[test] + fn vartime_precomputed_vs_nonprecomputed_multiscalar() { + let mut rng = rand::thread_rng(); + + let B = &::constants::RISTRETTO_BASEPOINT_TABLE; + + let static_scalars = (0..128) + .map(|_| Scalar::random(&mut rng)) + .collect::>(); + + let dynamic_scalars = (0..128) + .map(|_| Scalar::random(&mut rng)) + .collect::>(); + + let check_scalar: Scalar = static_scalars + .iter() + .chain(dynamic_scalars.iter()) + .map(|s| s * s) + .sum(); + + let static_points = static_scalars.iter().map(|s| s * B).collect::>(); + let dynamic_points = dynamic_scalars.iter().map(|s| s * B).collect::>(); + + let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter()); + + let P = precomputation.vartime_mixed_multiscalar_mul( + &static_scalars, + &dynamic_scalars, + &dynamic_points, + ); + + use traits::VartimeMultiscalarMul; + let Q = RistrettoPoint::vartime_multiscalar_mul( + static_scalars.iter().chain(dynamic_scalars.iter()), + static_points.iter().chain(dynamic_points.iter()), + ); + + let R = &check_scalar * B; + + assert_eq!(P.compress(), R.compress()); + assert_eq!(Q.compress(), R.compress()); + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/scalar.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/scalar.rs new file mode 100644 index 0000000..00de740 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/scalar.rs @@ -0,0 +1,1754 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// Portions Copyright 2017 Brian Smith +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft +// - Henry de Valence +// - Brian Smith + +//! Arithmetic on scalars (integers mod the group order). +//! +//! Both the Ristretto group and the Ed25519 basepoint have prime order +//! \\( \ell = 2\^{252} + 27742317777372353535851937790883648493 \\). +//! +//! This code is intended to be useful with both the Ristretto group +//! (where everything is done modulo \\( \ell \\)), and the X/Ed25519 +//! setting, which mandates specific bit-twiddles that are not +//! well-defined modulo \\( \ell \\). +//! +//! All arithmetic on `Scalars` is done modulo \\( \ell \\). +//! +//! # Constructing a scalar +//! +//! To create a [`Scalar`](struct.Scalar.html) from a supposedly canonical encoding, use +//! [`Scalar::from_canonical_bytes`](struct.Scalar.html#method.from_canonical_bytes). +//! +//! This function does input validation, ensuring that the input bytes +//! are the canonical encoding of a `Scalar`. +//! If they are, we'll get +//! `Some(Scalar)` in return: +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let one_as_bytes: [u8; 32] = Scalar::one().to_bytes(); +//! let a: Option = Scalar::from_canonical_bytes(one_as_bytes); +//! +//! assert!(a.is_some()); +//! ``` +//! +//! However, if we give it bytes representing a scalar larger than \\( \ell \\) +//! (in this case, \\( \ell + 2 \\)), we'll get `None` back: +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let l_plus_two_bytes: [u8; 32] = [ +//! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, +//! 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, +//! ]; +//! let a: Option = Scalar::from_canonical_bytes(l_plus_two_bytes); +//! +//! assert!(a.is_none()); +//! ``` +//! +//! Another way to create a `Scalar` is by reducing a \\(256\\)-bit integer mod +//! \\( \ell \\), for which one may use the +//! [`Scalar::from_bytes_mod_order`](struct.Scalar.html#method.from_bytes_mod_order) +//! method. In the case of the second example above, this would reduce the +//! resultant scalar \\( \mod \ell \\), producing \\( 2 \\): +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let l_plus_two_bytes: [u8; 32] = [ +//! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, +//! 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, +//! ]; +//! let a: Scalar = Scalar::from_bytes_mod_order(l_plus_two_bytes); +//! +//! let two: Scalar = Scalar::one() + Scalar::one(); +//! +//! assert!(a == two); +//! ``` +//! +//! There is also a constructor that reduces a \\(512\\)-bit integer, +//! [`Scalar::from_bytes_mod_order_wide`](struct.Scalar.html#method.from_bytes_mod_order_wide). +//! +//! To construct a `Scalar` as the hash of some input data, use +//! [`Scalar::hash_from_bytes`](struct.Scalar.html#method.hash_from_bytes), +//! which takes a buffer, or +//! [`Scalar::from_hash`](struct.Scalar.html#method.from_hash), +//! which allows an IUF API. +//! +//! ``` +//! # extern crate curve25519_dalek; +//! # extern crate sha2; +//! # +//! # fn main() { +//! use sha2::{Digest, Sha512}; +//! use curve25519_dalek::scalar::Scalar; +//! +//! // Hashing a single byte slice +//! let a = Scalar::hash_from_bytes::(b"Abolish ICE"); +//! +//! // Streaming data into a hash object +//! let mut hasher = Sha512::default(); +//! hasher.update(b"Abolish "); +//! hasher.update(b"ICE"); +//! let a2 = Scalar::from_hash(hasher); +//! +//! assert_eq!(a, a2); +//! # } +//! ``` +//! +//! Finally, to create a `Scalar` with a specific bit-pattern +//! (e.g., for compatibility with X/Ed25519 +//! ["clamping"](https://github.com/isislovecruft/ed25519-dalek/blob/f790bd2ce/src/ed25519.rs#L349)), +//! use [`Scalar::from_bits`](struct.Scalar.html#method.from_bits). This +//! constructs a scalar with exactly the bit pattern given, without any +//! assurances as to reduction modulo the group order: +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let l_plus_two_bytes: [u8; 32] = [ +//! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, +//! 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, +//! ]; +//! let a: Scalar = Scalar::from_bits(l_plus_two_bytes); +//! +//! let two: Scalar = Scalar::one() + Scalar::one(); +//! +//! assert!(a != two); // the scalar is not reduced (mod l)… +//! assert!(! a.is_canonical()); // …and therefore is not canonical. +//! assert!(a.reduce() == two); // if we were to reduce it manually, it would be. +//! ``` +//! +//! The resulting `Scalar` has exactly the specified bit pattern, +//! **except for the highest bit, which will be set to 0**. + +use core::borrow::Borrow; +use core::cmp::{Eq, PartialEq}; +use core::fmt::Debug; +use core::iter::{Product, Sum}; +use core::ops::Index; +use core::ops::Neg; +use core::ops::{Add, AddAssign}; +use core::ops::{Mul, MulAssign}; +use core::ops::{Sub, SubAssign}; + +#[allow(unused_imports)] +use prelude::*; + +use rand_core::{CryptoRng, RngCore}; + +use digest::generic_array::typenum::U64; +use digest::Digest; + +use subtle::Choice; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; + +use zeroize::Zeroize; + +use backend; +use constants; + +/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. +/// +/// This is a type alias for one of the scalar types in the `backend` +/// module. +#[cfg(feature = "fiat_u32_backend")] +type UnpackedScalar = backend::serial::fiat_u32::scalar::Scalar29; +#[cfg(feature = "fiat_u64_backend")] +type UnpackedScalar = backend::serial::fiat_u64::scalar::Scalar52; + +/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. +/// +/// This is a type alias for one of the scalar types in the `backend` +/// module. +#[cfg(feature = "u64_backend")] +type UnpackedScalar = backend::serial::u64::scalar::Scalar52; + +/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. +/// +/// This is a type alias for one of the scalar types in the `backend` +/// module. +#[cfg(feature = "u32_backend")] +type UnpackedScalar = backend::serial::u32::scalar::Scalar29; + + +/// The `Scalar` struct holds an integer \\(s < 2\^{255} \\) which +/// represents an element of \\(\mathbb Z / \ell\\). +#[derive(Copy, Clone, Hash)] +pub struct Scalar { + /// `bytes` is a little-endian byte encoding of an integer representing a scalar modulo the + /// group order. + /// + /// # Invariant + /// + /// The integer representing this scalar must be bounded above by \\(2\^{255}\\), or + /// equivalently the high bit of `bytes[31]` must be zero. + /// + /// This ensures that there is room for a carry bit when computing a NAF representation. + // + // XXX This is pub(crate) so we can write literal constants. If const fns were stable, we could + // make the Scalar constructors const fns and use those instead. + pub(crate) bytes: [u8; 32], +} + +impl Scalar { + /// Construct a `Scalar` by reducing a 256-bit little-endian integer + /// modulo the group order \\( \ell \\). + pub fn from_bytes_mod_order(bytes: [u8; 32]) -> Scalar { + // Temporarily allow s_unreduced.bytes > 2^255 ... + let s_unreduced = Scalar{bytes}; + + // Then reduce mod the group order and return the reduced representative. + let s = s_unreduced.reduce(); + debug_assert_eq!(0u8, s[31] >> 7); + + s + } + + /// Construct a `Scalar` by reducing a 512-bit little-endian integer + /// modulo the group order \\( \ell \\). + pub fn from_bytes_mod_order_wide(input: &[u8; 64]) -> Scalar { + UnpackedScalar::from_bytes_wide(input).pack() + } + + /// Attempt to construct a `Scalar` from a canonical byte representation. + /// + /// # Return + /// + /// - `Some(s)`, where `s` is the `Scalar` corresponding to `bytes`, + /// if `bytes` is a canonical byte representation; + /// - `None` if `bytes` is not a canonical byte representation. + pub fn from_canonical_bytes(bytes: [u8; 32]) -> Option { + // Check that the high bit is not set + if (bytes[31] >> 7) != 0u8 { return None; } + let candidate = Scalar::from_bits(bytes); + + if candidate.is_canonical() { + Some(candidate) + } else { + None + } + } + + /// Construct a `Scalar` from the low 255 bits of a 256-bit integer. + /// + /// This function is intended for applications like X25519 which + /// require specific bit-patterns when performing scalar + /// multiplication. + pub const fn from_bits(bytes: [u8; 32]) -> Scalar { + let mut s = Scalar{bytes}; + // Ensure that s < 2^255 by masking the high bit + s.bytes[31] &= 0b0111_1111; + + s + } +} + +impl Debug for Scalar { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "Scalar{{\n\tbytes: {:?},\n}}", &self.bytes) + } +} + +impl Eq for Scalar {} +impl PartialEq for Scalar { + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).unwrap_u8() == 1u8 + } +} + +impl ConstantTimeEq for Scalar { + fn ct_eq(&self, other: &Self) -> Choice { + self.bytes.ct_eq(&other.bytes) + } +} + +impl Index for Scalar { + type Output = u8; + + /// Index the bytes of the representative for this `Scalar`. Mutation is not permitted. + fn index(&self, _index: usize) -> &u8 { + &(self.bytes[_index]) + } +} + +impl<'b> MulAssign<&'b Scalar> for Scalar { + fn mul_assign(&mut self, _rhs: &'b Scalar) { + *self = UnpackedScalar::mul(&self.unpack(), &_rhs.unpack()).pack(); + } +} + +define_mul_assign_variants!(LHS = Scalar, RHS = Scalar); + +impl<'a, 'b> Mul<&'b Scalar> for &'a Scalar { + type Output = Scalar; + fn mul(self, _rhs: &'b Scalar) -> Scalar { + UnpackedScalar::mul(&self.unpack(), &_rhs.unpack()).pack() + } +} + +define_mul_variants!(LHS = Scalar, RHS = Scalar, Output = Scalar); + +impl<'b> AddAssign<&'b Scalar> for Scalar { + fn add_assign(&mut self, _rhs: &'b Scalar) { + *self = *self + _rhs; + } +} + +define_add_assign_variants!(LHS = Scalar, RHS = Scalar); + +impl<'a, 'b> Add<&'b Scalar> for &'a Scalar { + type Output = Scalar; + #[allow(non_snake_case)] + fn add(self, _rhs: &'b Scalar) -> Scalar { + // The UnpackedScalar::add function produces reduced outputs + // if the inputs are reduced. However, these inputs may not + // be reduced -- they might come from Scalar::from_bits. So + // after computing the sum, we explicitly reduce it mod l + // before repacking. + let sum = UnpackedScalar::add(&self.unpack(), &_rhs.unpack()); + let sum_R = UnpackedScalar::mul_internal(&sum, &constants::R); + let sum_mod_l = UnpackedScalar::montgomery_reduce(&sum_R); + sum_mod_l.pack() + } +} + +define_add_variants!(LHS = Scalar, RHS = Scalar, Output = Scalar); + +impl<'b> SubAssign<&'b Scalar> for Scalar { + fn sub_assign(&mut self, _rhs: &'b Scalar) { + *self = *self - _rhs; + } +} + +define_sub_assign_variants!(LHS = Scalar, RHS = Scalar); + +impl<'a, 'b> Sub<&'b Scalar> for &'a Scalar { + type Output = Scalar; + #[allow(non_snake_case)] + fn sub(self, rhs: &'b Scalar) -> Scalar { + // The UnpackedScalar::sub function requires reduced inputs + // and produces reduced output. However, these inputs may not + // be reduced -- they might come from Scalar::from_bits. So + // we explicitly reduce the inputs. + let self_R = UnpackedScalar::mul_internal(&self.unpack(), &constants::R); + let self_mod_l = UnpackedScalar::montgomery_reduce(&self_R); + let rhs_R = UnpackedScalar::mul_internal(&rhs.unpack(), &constants::R); + let rhs_mod_l = UnpackedScalar::montgomery_reduce(&rhs_R); + + UnpackedScalar::sub(&self_mod_l, &rhs_mod_l).pack() + } +} + +define_sub_variants!(LHS = Scalar, RHS = Scalar, Output = Scalar); + +impl<'a> Neg for &'a Scalar { + type Output = Scalar; + #[allow(non_snake_case)] + fn neg(self) -> Scalar { + let self_R = UnpackedScalar::mul_internal(&self.unpack(), &constants::R); + let self_mod_l = UnpackedScalar::montgomery_reduce(&self_R); + UnpackedScalar::sub(&UnpackedScalar::zero(), &self_mod_l).pack() + } +} + +impl<'a> Neg for Scalar { + type Output = Scalar; + fn neg(self) -> Scalar { + -&self + } +} + +impl ConditionallySelectable for Scalar { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = u8::conditional_select(&a.bytes[i], &b.bytes[i], choice); + } + Scalar { bytes } + } +} + +#[cfg(feature = "serde")] +use serde::{self, Serialize, Deserialize, Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +#[cfg(feature = "serde")] +impl Serialize for Scalar { + fn serialize(&self, serializer: S) -> Result + where S: Serializer + { + use serde::ser::SerializeTuple; + let mut tup = serializer.serialize_tuple(32)?; + for byte in self.as_bytes().iter() { + tup.serialize_element(byte)?; + } + tup.end() + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Scalar { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + struct ScalarVisitor; + + impl<'de> Visitor<'de> for ScalarVisitor { + type Value = Scalar; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("a valid point in Edwards y + sign format") + } + + fn visit_seq(self, mut seq: A) -> Result + where A: serde::de::SeqAccess<'de> + { + let mut bytes = [0u8; 32]; + for i in 0..32 { + bytes[i] = seq.next_element()? + .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + Scalar::from_canonical_bytes(bytes) + .ok_or(serde::de::Error::custom( + &"scalar was not canonically encoded" + )) + } + } + + deserializer.deserialize_tuple(32, ScalarVisitor) + } +} + +impl Product for Scalar +where + T: Borrow +{ + fn product(iter: I) -> Self + where + I: Iterator + { + iter.fold(Scalar::one(), |acc, item| acc * item.borrow()) + } +} + +impl Sum for Scalar +where + T: Borrow +{ + fn sum(iter: I) -> Self + where + I: Iterator + { + iter.fold(Scalar::zero(), |acc, item| acc + item.borrow()) + } +} + +impl Default for Scalar { + fn default() -> Scalar { + Scalar::zero() + } +} + +impl From for Scalar { + fn from(x: u8) -> Scalar { + let mut s_bytes = [0u8; 32]; + s_bytes[0] = x; + Scalar{ bytes: s_bytes } + } +} + +impl From for Scalar { + fn from(x: u16) -> Scalar { + use byteorder::{ByteOrder, LittleEndian}; + let mut s_bytes = [0u8; 32]; + LittleEndian::write_u16(&mut s_bytes, x); + Scalar{ bytes: s_bytes } + } +} + +impl From for Scalar { + fn from(x: u32) -> Scalar { + use byteorder::{ByteOrder, LittleEndian}; + let mut s_bytes = [0u8; 32]; + LittleEndian::write_u32(&mut s_bytes, x); + Scalar{ bytes: s_bytes } + } +} + +impl From for Scalar { + /// Construct a scalar from the given `u64`. + /// + /// # Inputs + /// + /// An `u64` to convert to a `Scalar`. + /// + /// # Returns + /// + /// A `Scalar` corresponding to the input `u64`. + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::scalar::Scalar; + /// + /// let fourtytwo = Scalar::from(42u64); + /// let six = Scalar::from(6u64); + /// let seven = Scalar::from(7u64); + /// + /// assert!(fourtytwo == six * seven); + /// ``` + fn from(x: u64) -> Scalar { + use byteorder::{ByteOrder, LittleEndian}; + let mut s_bytes = [0u8; 32]; + LittleEndian::write_u64(&mut s_bytes, x); + Scalar{ bytes: s_bytes } + } +} + +impl From for Scalar { + fn from(x: u128) -> Scalar { + use byteorder::{ByteOrder, LittleEndian}; + let mut s_bytes = [0u8; 32]; + LittleEndian::write_u128(&mut s_bytes, x); + Scalar{ bytes: s_bytes } + } +} + +impl Zeroize for Scalar { + fn zeroize(&mut self) { + self.bytes.zeroize(); + } +} + +impl Scalar { + /// Return a `Scalar` chosen uniformly at random using a user-provided RNG. + /// + /// # Inputs + /// + /// * `rng`: any RNG which implements the `RngCore + CryptoRng` interface. + /// + /// # Returns + /// + /// A random scalar within ℤ/lℤ. + /// + /// # Example + /// + /// ``` + /// extern crate rand_core; + /// # extern crate curve25519_dalek; + /// # + /// # fn main() { + /// use curve25519_dalek::scalar::Scalar; + /// + /// use rand_core::OsRng; + /// + /// let mut csprng = OsRng; + /// let a: Scalar = Scalar::random(&mut csprng); + /// # } + pub fn random(rng: &mut R) -> Self { + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + Scalar::from_bytes_mod_order_wide(&scalar_bytes) + } + + /// Hash a slice of bytes into a scalar. + /// + /// Takes a type parameter `D`, which is any `Digest` producing 64 + /// bytes (512 bits) of output. + /// + /// Convenience wrapper around `from_hash`. + /// + /// # Example + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # use curve25519_dalek::scalar::Scalar; + /// extern crate sha2; + /// + /// use sha2::Sha512; + /// + /// # // Need fn main() here in comment so the doctest compiles + /// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests + /// # fn main() { + /// let msg = "To really appreciate architecture, you may even need to commit a murder"; + /// let s = Scalar::hash_from_bytes::(msg.as_bytes()); + /// # } + /// ``` + pub fn hash_from_bytes(input: &[u8]) -> Scalar + where D: Digest + Default + { + let mut hash = D::default(); + hash.update(input); + Scalar::from_hash(hash) + } + + /// Construct a scalar from an existing `Digest` instance. + /// + /// Use this instead of `hash_from_bytes` if it is more convenient + /// to stream data into the `Digest` than to pass a single byte + /// slice. + /// + /// # Example + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # use curve25519_dalek::scalar::Scalar; + /// extern crate sha2; + /// + /// use sha2::Digest; + /// use sha2::Sha512; + /// + /// # fn main() { + /// let mut h = Sha512::new() + /// .chain("To really appreciate architecture, you may even need to commit a murder.") + /// .chain("While the programs used for The Manhattan Transcripts are of the most extreme") + /// .chain("nature, they also parallel the most common formula plot: the archetype of") + /// .chain("murder. Other phantasms were occasionally used to underline the fact that") + /// .chain("perhaps all architecture, rather than being about functional standards, is") + /// .chain("about love and death."); + /// + /// let s = Scalar::from_hash(h); + /// + /// println!("{:?}", s.to_bytes()); + /// assert!(s == Scalar::from_bits([ 21, 88, 208, 252, 63, 122, 210, 152, + /// 154, 38, 15, 23, 16, 167, 80, 150, + /// 192, 221, 77, 226, 62, 25, 224, 148, + /// 239, 48, 176, 10, 185, 69, 168, 11, ])); + /// # } + /// ``` + pub fn from_hash(hash: D) -> Scalar + where D: Digest + { + let mut output = [0u8; 64]; + output.copy_from_slice(hash.finalize().as_slice()); + Scalar::from_bytes_mod_order_wide(&output) + } + + /// Convert this `Scalar` to its underlying sequence of bytes. + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::scalar::Scalar; + /// + /// let s: Scalar = Scalar::zero(); + /// + /// assert!(s.to_bytes() == [0u8; 32]); + /// ``` + pub fn to_bytes(&self) -> [u8; 32] { + self.bytes + } + + /// View the little-endian byte encoding of the integer representing this Scalar. + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::scalar::Scalar; + /// + /// let s: Scalar = Scalar::zero(); + /// + /// assert!(s.as_bytes() == &[0u8; 32]); + /// ``` + pub fn as_bytes(&self) -> &[u8; 32] { + &self.bytes + } + + /// Construct the scalar \\( 0 \\). + pub fn zero() -> Self { + Scalar { bytes: [0u8; 32]} + } + + /// Construct the scalar \\( 1 \\). + pub fn one() -> Self { + Scalar { + bytes: [ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + } + } + + /// Given a nonzero `Scalar`, compute its multiplicative inverse. + /// + /// # Warning + /// + /// `self` **MUST** be nonzero. If you cannot + /// *prove* that this is the case, you **SHOULD NOT USE THIS + /// FUNCTION**. + /// + /// # Returns + /// + /// The multiplicative inverse of the this `Scalar`. + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::scalar::Scalar; + /// + /// // x = 2238329342913194256032495932344128051776374960164957527413114840482143558222 + /// let X: Scalar = Scalar::from_bytes_mod_order([ + /// 0x4e, 0x5a, 0xb4, 0x34, 0x5d, 0x47, 0x08, 0x84, + /// 0x59, 0x13, 0xb4, 0x64, 0x1b, 0xc2, 0x7d, 0x52, + /// 0x52, 0xa5, 0x85, 0x10, 0x1b, 0xcc, 0x42, 0x44, + /// 0xd4, 0x49, 0xf4, 0xa8, 0x79, 0xd9, 0xf2, 0x04, + /// ]); + /// // 1/x = 6859937278830797291664592131120606308688036382723378951768035303146619657244 + /// let XINV: Scalar = Scalar::from_bytes_mod_order([ + /// 0x1c, 0xdc, 0x17, 0xfc, 0xe0, 0xe9, 0xa5, 0xbb, + /// 0xd9, 0x24, 0x7e, 0x56, 0xbb, 0x01, 0x63, 0x47, + /// 0xbb, 0xba, 0x31, 0xed, 0xd5, 0xa9, 0xbb, 0x96, + /// 0xd5, 0x0b, 0xcd, 0x7a, 0x3f, 0x96, 0x2a, 0x0f, + /// ]); + /// + /// let inv_X: Scalar = X.invert(); + /// assert!(XINV == inv_X); + /// let should_be_one: Scalar = &inv_X * &X; + /// assert!(should_be_one == Scalar::one()); + /// ``` + pub fn invert(&self) -> Scalar { + self.unpack().invert().pack() + } + + /// Given a slice of nonzero (possibly secret) `Scalar`s, + /// compute their inverses in a batch. + /// + /// # Return + /// + /// Each element of `inputs` is replaced by its inverse. + /// + /// The product of all inverses is returned. + /// + /// # Warning + /// + /// All input `Scalars` **MUST** be nonzero. If you cannot + /// *prove* that this is the case, you **SHOULD NOT USE THIS + /// FUNCTION**. + /// + /// # Example + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # use curve25519_dalek::scalar::Scalar; + /// # fn main() { + /// let mut scalars = [ + /// Scalar::from(3u64), + /// Scalar::from(5u64), + /// Scalar::from(7u64), + /// Scalar::from(11u64), + /// ]; + /// + /// let allinv = Scalar::batch_invert(&mut scalars); + /// + /// assert_eq!(allinv, Scalar::from(3*5*7*11u64).invert()); + /// assert_eq!(scalars[0], Scalar::from(3u64).invert()); + /// assert_eq!(scalars[1], Scalar::from(5u64).invert()); + /// assert_eq!(scalars[2], Scalar::from(7u64).invert()); + /// assert_eq!(scalars[3], Scalar::from(11u64).invert()); + /// # } + /// ``` + #[cfg(feature = "alloc")] + pub fn batch_invert(inputs: &mut [Scalar]) -> Scalar { + // This code is essentially identical to the FieldElement + // implementation, and is documented there. Unfortunately, + // it's not easy to write it generically, since here we want + // to use `UnpackedScalar`s internally, and `Scalar`s + // externally, but there's no corresponding distinction for + // field elements. + + use zeroize::Zeroizing; + + let n = inputs.len(); + let one: UnpackedScalar = Scalar::one().unpack().to_montgomery(); + + // Place scratch storage in a Zeroizing wrapper to wipe it when + // we pass out of scope. + let scratch_vec = vec![one; n]; + let mut scratch = Zeroizing::new(scratch_vec); + + // Keep an accumulator of all of the previous products + let mut acc = Scalar::one().unpack().to_montgomery(); + + // Pass through the input vector, recording the previous + // products in the scratch space + for (input, scratch) in inputs.iter_mut().zip(scratch.iter_mut()) { + *scratch = acc; + + // Avoid unnecessary Montgomery multiplication in second pass by + // keeping inputs in Montgomery form + let tmp = input.unpack().to_montgomery(); + *input = tmp.pack(); + acc = UnpackedScalar::montgomery_mul(&acc, &tmp); + } + + // acc is nonzero iff all inputs are nonzero + debug_assert!(acc.pack() != Scalar::zero()); + + // Compute the inverse of all products + acc = acc.montgomery_invert().from_montgomery(); + + // We need to return the product of all inverses later + let ret = acc.pack(); + + // Pass through the vector backwards to compute the inverses + // in place + for (input, scratch) in inputs.iter_mut().rev().zip(scratch.iter().rev()) { + let tmp = UnpackedScalar::montgomery_mul(&acc, &input.unpack()); + *input = UnpackedScalar::montgomery_mul(&acc, &scratch).pack(); + acc = tmp; + } + + ret + } + + /// Get the bits of the scalar. + pub(crate) fn bits(&self) -> [i8; 256] { + let mut bits = [0i8; 256]; + for i in 0..256 { + // As i runs from 0..256, the bottom 3 bits index the bit, + // while the upper bits index the byte. + bits[i] = ((self.bytes[i>>3] >> (i&7)) & 1u8) as i8; + } + bits + } + + /// Compute a width-\\(w\\) "Non-Adjacent Form" of this scalar. + /// + /// A width-\\(w\\) NAF of a positive integer \\(k\\) is an expression + /// $$ + /// k = \sum_{i=0}\^m n\_i 2\^i, + /// $$ + /// where each nonzero + /// coefficient \\(n\_i\\) is odd and bounded by \\(|n\_i| < 2\^{w-1}\\), + /// \\(n\_{m-1}\\) is nonzero, and at most one of any \\(w\\) consecutive + /// coefficients is nonzero. (Hankerson, Menezes, Vanstone; def 3.32). + /// + /// The length of the NAF is at most one more than the length of + /// the binary representation of \\(k\\). This is why the + /// `Scalar` type maintains an invariant that the top bit is + /// \\(0\\), so that the NAF of a scalar has at most 256 digits. + /// + /// Intuitively, this is like a binary expansion, except that we + /// allow some coefficients to grow in magnitude up to + /// \\(2\^{w-1}\\) so that the nonzero coefficients are as sparse + /// as possible. + /// + /// When doing scalar multiplication, we can then use a lookup + /// table of precomputed multiples of a point to add the nonzero + /// terms \\( k_i P \\). Using signed digits cuts the table size + /// in half, and using odd digits cuts the table size in half + /// again. + /// + /// To compute a \\(w\\)-NAF, we use a modification of Algorithm 3.35 of HMV: + /// + /// 1. \\( i \gets 0 \\) + /// 2. While \\( k \ge 1 \\): + /// 1. If \\(k\\) is odd, \\( n_i \gets k \operatorname{mods} 2^w \\), \\( k \gets k - n_i \\). + /// 2. If \\(k\\) is even, \\( n_i \gets 0 \\). + /// 3. \\( k \gets k / 2 \\), \\( i \gets i + 1 \\). + /// 3. Return \\( n_0, n_1, ... , \\) + /// + /// Here \\( \bar x = x \operatorname{mods} 2^w \\) means the + /// \\( \bar x \\) with \\( \bar x \equiv x \pmod{2^w} \\) and + /// \\( -2^{w-1} \leq \bar x < 2^w \\). + /// + /// We implement this by scanning across the bits of \\(k\\) from + /// least-significant bit to most-significant-bit. + /// Write the bits of \\(k\\) as + /// $$ + /// k = \sum\_{i=0}\^m k\_i 2^i, + /// $$ + /// and split the sum as + /// $$ + /// k = \sum\_{i=0}^{w-1} k\_i 2^i + 2^w \sum\_{i=0} k\_{i+w} 2^i + /// $$ + /// where the first part is \\( k \mod 2^w \\). + /// + /// If \\( k \mod 2^w\\) is odd, and \\( k \mod 2^w < 2^{w-1} \\), then we emit + /// \\( n_0 = k \mod 2^w \\). Instead of computing + /// \\( k - n_0 \\), we just advance \\(w\\) bits and reindex. + /// + /// If \\( k \mod 2^w\\) is odd, and \\( k \mod 2^w \ge 2^{w-1} \\), then + /// \\( n_0 = k \operatorname{mods} 2^w = k \mod 2^w - 2^w \\). + /// The quantity \\( k - n_0 \\) is + /// $$ + /// \begin{aligned} + /// k - n_0 &= \sum\_{i=0}^{w-1} k\_i 2^i + 2^w \sum\_{i=0} k\_{i+w} 2^i + /// - \sum\_{i=0}^{w-1} k\_i 2^i + 2^w \\\\ + /// &= 2^w + 2^w \sum\_{i=0} k\_{i+w} 2^i + /// \end{aligned} + /// $$ + /// so instead of computing the subtraction, we can set a carry + /// bit, advance \\(w\\) bits, and reindex. + /// + /// If \\( k \mod 2^w\\) is even, we emit \\(0\\), advance 1 bit + /// and reindex. In fact, by setting all digits to \\(0\\) + /// initially, we don't need to emit anything. + pub(crate) fn non_adjacent_form(&self, w: usize) -> [i8; 256] { + // required by the NAF definition + debug_assert!( w >= 2 ); + // required so that the NAF digits fit in i8 + debug_assert!( w <= 8 ); + + use byteorder::{ByteOrder, LittleEndian}; + + let mut naf = [0i8; 256]; + + let mut x_u64 = [0u64; 5]; + LittleEndian::read_u64_into(&self.bytes, &mut x_u64[0..4]); + + let width = 1 << w; + let window_mask = width - 1; + + let mut pos = 0; + let mut carry = 0; + while pos < 256 { + // Construct a buffer of bits of the scalar, starting at bit `pos` + let u64_idx = pos / 64; + let bit_idx = pos % 64; + let bit_buf: u64; + if bit_idx < 64 - w { + // This window's bits are contained in a single u64 + bit_buf = x_u64[u64_idx] >> bit_idx; + } else { + // Combine the current u64's bits with the bits from the next u64 + bit_buf = (x_u64[u64_idx] >> bit_idx) | (x_u64[1+u64_idx] << (64 - bit_idx)); + } + + // Add the carry into the current window + let window = carry + (bit_buf & window_mask); + + if window & 1 == 0 { + // If the window value is even, preserve the carry and continue. + // Why is the carry preserved? + // If carry == 0 and window & 1 == 0, then the next carry should be 0 + // If carry == 1 and window & 1 == 0, then bit_buf & 1 == 1 so the next carry should be 1 + pos += 1; + continue; + } + + if window < width/2 { + carry = 0; + naf[pos] = window as i8; + } else { + carry = 1; + naf[pos] = (window as i8).wrapping_sub(width as i8); + } + + pos += w; + } + + naf + } + + /// Write this scalar in radix 16, with coefficients in \\([-8,8)\\), + /// i.e., compute \\(a\_i\\) such that + /// $$ + /// a = a\_0 + a\_1 16\^1 + \cdots + a_{63} 16\^{63}, + /// $$ + /// with \\(-8 \leq a_i < 8\\) for \\(0 \leq i < 63\\) and \\(-8 \leq a_{63} \leq 8\\). + pub(crate) fn to_radix_16(&self) -> [i8; 64] { + debug_assert!(self[31] <= 127); + let mut output = [0i8; 64]; + + // Step 1: change radix. + // Convert from radix 256 (bytes) to radix 16 (nibbles) + #[inline(always)] + fn bot_half(x: u8) -> u8 { (x >> 0) & 15 } + #[inline(always)] + fn top_half(x: u8) -> u8 { (x >> 4) & 15 } + + for i in 0..32 { + output[2*i ] = bot_half(self[i]) as i8; + output[2*i+1] = top_half(self[i]) as i8; + } + // Precondition note: since self[31] <= 127, output[63] <= 7 + + // Step 2: recenter coefficients from [0,16) to [-8,8) + for i in 0..63 { + let carry = (output[i] + 8) >> 4; + output[i ] -= carry << 4; + output[i+1] += carry; + } + // Precondition note: output[63] is not recentered. It + // increases by carry <= 1. Thus output[63] <= 8. + + output + } + + /// Returns a size hint indicating how many entries of the return + /// value of `to_radix_2w` are nonzero. + pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize { + debug_assert!(w >= 4); + debug_assert!(w <= 8); + + let digits_count = match w { + 4 => (256 + w - 1)/w as usize, + 5 => (256 + w - 1)/w as usize, + 6 => (256 + w - 1)/w as usize, + 7 => (256 + w - 1)/w as usize, + // See comment in to_radix_2w on handling the terminal carry. + 8 => (256 + w - 1)/w + 1 as usize, + _ => panic!("invalid radix parameter"), + }; + + debug_assert!(digits_count <= 64); + digits_count + } + + /// Creates a representation of a Scalar in radix 32, 64, 128 or 256 for use with the Pippenger algorithm. + /// For lower radix, use `to_radix_16`, which is used by the Straus multi-scalar multiplication. + /// Higher radixes are not supported to save cache space. Radix 256 is near-optimal even for very + /// large inputs. + /// + /// Radix below 32 or above 256 is prohibited. + /// This method returns digits in a fixed-sized array, excess digits are zeroes. + /// + /// ## Scalar representation + /// + /// Radix \\(2\^w\\), with \\(n = ceil(256/w)\\) coefficients in \\([-(2\^w)/2,(2\^w)/2)\\), + /// i.e., scalar is represented using digits \\(a\_i\\) such that + /// $$ + /// a = a\_0 + a\_1 2\^1w + \cdots + a_{n-1} 2\^{w*(n-1)}, + /// $$ + /// with \\(-2\^w/2 \leq a_i < 2\^w/2\\) for \\(0 \leq i < (n-1)\\) and \\(-2\^w/2 \leq a_{n-1} \leq 2\^w/2\\). + /// + pub(crate) fn to_radix_2w(&self, w: usize) -> [i8; 64] { + debug_assert!(w >= 4); + debug_assert!(w <= 8); + + if w == 4 { + return self.to_radix_16(); + } + + use byteorder::{ByteOrder, LittleEndian}; + + // Scalar formatted as four `u64`s with carry bit packed into the highest bit. + let mut scalar64x4 = [0u64; 4]; + LittleEndian::read_u64_into(&self.bytes, &mut scalar64x4[0..4]); + + let radix: u64 = 1 << w; + let window_mask: u64 = radix - 1; + + let mut carry = 0u64; + let mut digits = [0i8; 64]; + let digits_count = (256 + w - 1)/w as usize; + for i in 0..digits_count { + // Construct a buffer of bits of the scalar, starting at `bit_offset`. + let bit_offset = i*w; + let u64_idx = bit_offset / 64; + let bit_idx = bit_offset % 64; + + // Read the bits from the scalar + let bit_buf: u64; + if bit_idx < 64 - w || u64_idx == 3 { + // This window's bits are contained in a single u64, + // or it's the last u64 anyway. + bit_buf = scalar64x4[u64_idx] >> bit_idx; + } else { + // Combine the current u64's bits with the bits from the next u64 + bit_buf = (scalar64x4[u64_idx] >> bit_idx) | (scalar64x4[1+u64_idx] << (64 - bit_idx)); + } + + // Read the actual coefficient value from the window + let coef = carry + (bit_buf & window_mask); // coef = [0, 2^r) + + // Recenter coefficients from [0,2^w) to [-2^w/2, 2^w/2) + carry = (coef + (radix/2) as u64) >> w; + digits[i] = ((coef as i64) - (carry << w) as i64) as i8; + } + + // When w < 8, we can fold the final carry onto the last digit d, + // because d < 2^w/2 so d + carry*2^w = d + 1*2^w < 2^(w+1) < 2^8. + // + // When w = 8, we can't fit carry*2^w into an i8. This should + // not happen anyways, because the final carry will be 0 for + // reduced scalars, but the Scalar invariant allows 255-bit scalars. + // To handle this, we expand the size_hint by 1 when w=8, + // and accumulate the final carry onto another digit. + match w { + 8 => digits[digits_count] += carry as i8, + _ => digits[digits_count-1] += (carry << w) as i8, + } + + digits + } + + /// Unpack this `Scalar` to an `UnpackedScalar` for faster arithmetic. + pub(crate) fn unpack(&self) -> UnpackedScalar { + UnpackedScalar::from_bytes(&self.bytes) + } + + /// Reduce this `Scalar` modulo \\(\ell\\). + #[allow(non_snake_case)] + pub fn reduce(&self) -> Scalar { + let x = self.unpack(); + let xR = UnpackedScalar::mul_internal(&x, &constants::R); + let x_mod_l = UnpackedScalar::montgomery_reduce(&xR); + x_mod_l.pack() + } + + /// Check whether this `Scalar` is the canonical representative mod \\(\ell\\). + /// + /// This is intended for uses like input validation, where variable-time code is acceptable. + /// + /// ``` + /// # extern crate curve25519_dalek; + /// # extern crate subtle; + /// # use curve25519_dalek::scalar::Scalar; + /// # use subtle::ConditionallySelectable; + /// # fn main() { + /// // 2^255 - 1, since `from_bits` clears the high bit + /// let _2_255_minus_1 = Scalar::from_bits([0xff;32]); + /// assert!(!_2_255_minus_1.is_canonical()); + /// + /// let reduced = _2_255_minus_1.reduce(); + /// assert!(reduced.is_canonical()); + /// # } + /// ``` + pub fn is_canonical(&self) -> bool { + *self == self.reduce() + } +} + +impl UnpackedScalar { + /// Pack the limbs of this `UnpackedScalar` into a `Scalar`. + fn pack(&self) -> Scalar { + Scalar{ bytes: self.to_bytes() } + } + + /// Inverts an UnpackedScalar in Montgomery form. + pub fn montgomery_invert(&self) -> UnpackedScalar { + // Uses the addition chain from + // https://briansmith.org/ecc-inversion-addition-chains-01#curve25519_scalar_inversion + let _1 = self; + let _10 = _1.montgomery_square(); + let _100 = _10.montgomery_square(); + let _11 = UnpackedScalar::montgomery_mul(&_10, &_1); + let _101 = UnpackedScalar::montgomery_mul(&_10, &_11); + let _111 = UnpackedScalar::montgomery_mul(&_10, &_101); + let _1001 = UnpackedScalar::montgomery_mul(&_10, &_111); + let _1011 = UnpackedScalar::montgomery_mul(&_10, &_1001); + let _1111 = UnpackedScalar::montgomery_mul(&_100, &_1011); + + // _10000 + let mut y = UnpackedScalar::montgomery_mul(&_1111, &_1); + + #[inline] + fn square_multiply(y: &mut UnpackedScalar, squarings: usize, x: &UnpackedScalar) { + for _ in 0..squarings { + *y = y.montgomery_square(); + } + *y = UnpackedScalar::montgomery_mul(y, x); + } + + square_multiply(&mut y, 123 + 3, &_101); + square_multiply(&mut y, 2 + 2, &_11); + square_multiply(&mut y, 1 + 4, &_1111); + square_multiply(&mut y, 1 + 4, &_1111); + square_multiply(&mut y, 4, &_1001); + square_multiply(&mut y, 2, &_11); + square_multiply(&mut y, 1 + 4, &_1111); + square_multiply(&mut y, 1 + 3, &_101); + square_multiply(&mut y, 3 + 3, &_101); + square_multiply(&mut y, 3, &_111); + square_multiply(&mut y, 1 + 4, &_1111); + square_multiply(&mut y, 2 + 3, &_111); + square_multiply(&mut y, 2 + 2, &_11); + square_multiply(&mut y, 1 + 4, &_1011); + square_multiply(&mut y, 2 + 4, &_1011); + square_multiply(&mut y, 6 + 4, &_1001); + square_multiply(&mut y, 2 + 2, &_11); + square_multiply(&mut y, 3 + 2, &_11); + square_multiply(&mut y, 3 + 2, &_11); + square_multiply(&mut y, 1 + 4, &_1001); + square_multiply(&mut y, 1 + 3, &_111); + square_multiply(&mut y, 2 + 4, &_1111); + square_multiply(&mut y, 1 + 4, &_1011); + square_multiply(&mut y, 3, &_101); + square_multiply(&mut y, 2 + 4, &_1111); + square_multiply(&mut y, 3, &_101); + square_multiply(&mut y, 1 + 2, &_11); + + y + } + + /// Inverts an UnpackedScalar not in Montgomery form. + pub fn invert(&self) -> UnpackedScalar { + self.to_montgomery().montgomery_invert().from_montgomery() + } +} + +#[cfg(test)] +mod test { + use super::*; + use constants; + + /// x = 2238329342913194256032495932344128051776374960164957527413114840482143558222 + pub static X: Scalar = Scalar{ + bytes: [ + 0x4e, 0x5a, 0xb4, 0x34, 0x5d, 0x47, 0x08, 0x84, + 0x59, 0x13, 0xb4, 0x64, 0x1b, 0xc2, 0x7d, 0x52, + 0x52, 0xa5, 0x85, 0x10, 0x1b, 0xcc, 0x42, 0x44, + 0xd4, 0x49, 0xf4, 0xa8, 0x79, 0xd9, 0xf2, 0x04, + ], + }; + /// 1/x = 6859937278830797291664592131120606308688036382723378951768035303146619657244 + pub static XINV: Scalar = Scalar{ + bytes: [ + 0x1c, 0xdc, 0x17, 0xfc, 0xe0, 0xe9, 0xa5, 0xbb, + 0xd9, 0x24, 0x7e, 0x56, 0xbb, 0x01, 0x63, 0x47, + 0xbb, 0xba, 0x31, 0xed, 0xd5, 0xa9, 0xbb, 0x96, + 0xd5, 0x0b, 0xcd, 0x7a, 0x3f, 0x96, 0x2a, 0x0f, + ], + }; + /// y = 2592331292931086675770238855846338635550719849568364935475441891787804997264 + pub static Y: Scalar = Scalar{ + bytes: [ + 0x90, 0x76, 0x33, 0xfe, 0x1c, 0x4b, 0x66, 0xa4, + 0xa2, 0x8d, 0x2d, 0xd7, 0x67, 0x83, 0x86, 0xc3, + 0x53, 0xd0, 0xde, 0x54, 0x55, 0xd4, 0xfc, 0x9d, + 0xe8, 0xef, 0x7a, 0xc3, 0x1f, 0x35, 0xbb, 0x05, + ], + }; + + /// x*y = 5690045403673944803228348699031245560686958845067437804563560795922180092780 + static X_TIMES_Y: Scalar = Scalar{ + bytes: [ + 0x6c, 0x33, 0x74, 0xa1, 0x89, 0x4f, 0x62, 0x21, + 0x0a, 0xaa, 0x2f, 0xe1, 0x86, 0xa6, 0xf9, 0x2c, + 0xe0, 0xaa, 0x75, 0xc2, 0x77, 0x95, 0x81, 0xc2, + 0x95, 0xfc, 0x08, 0x17, 0x9a, 0x73, 0x94, 0x0c, + ], + }; + + /// sage: l = 2^252 + 27742317777372353535851937790883648493 + /// sage: big = 2^256 - 1 + /// sage: repr((big % l).digits(256)) + static CANONICAL_2_256_MINUS_1: Scalar = Scalar{ + bytes: [ + 28, 149, 152, 141, 116, 49, 236, 214, + 112, 207, 125, 115, 244, 91, 239, 198, + 254, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 15, + ], + }; + + static A_SCALAR: Scalar = Scalar{ + bytes: [ + 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, + 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d, + 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, + 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09, + ], + }; + + static A_NAF: [i8; 256] = + [0,13,0,0,0,0,0,0,0,7,0,0,0,0,0,0,-9,0,0,0,0,-11,0,0,0,0,3,0,0,0,0,1, + 0,0,0,0,9,0,0,0,0,-5,0,0,0,0,0,0,3,0,0,0,0,11,0,0,0,0,11,0,0,0,0,0, + -9,0,0,0,0,0,-3,0,0,0,0,9,0,0,0,0,0,1,0,0,0,0,0,0,-1,0,0,0,0,0,9,0, + 0,0,0,-15,0,0,0,0,-7,0,0,0,0,-9,0,0,0,0,0,5,0,0,0,0,13,0,0,0,0,0,-3,0, + 0,0,0,-11,0,0,0,0,-7,0,0,0,0,-13,0,0,0,0,11,0,0,0,0,-9,0,0,0,0,0,1,0,0, + 0,0,0,-15,0,0,0,0,1,0,0,0,0,7,0,0,0,0,0,0,0,0,5,0,0,0,0,0,13,0,0,0, + 0,0,0,11,0,0,0,0,0,15,0,0,0,0,0,-9,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,7, + 0,0,0,0,0,-15,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,15,0,0,0,0,0,1,0,0,0,0]; + + static LARGEST_ED25519_S: Scalar = Scalar { + bytes: [ + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + ], + }; + + static CANONICAL_LARGEST_ED25519_S_PLUS_ONE: Scalar = Scalar { + bytes: [ + 0x7e, 0x34, 0x47, 0x75, 0x47, 0x4a, 0x7f, 0x97, + 0x23, 0xb6, 0x3a, 0x8b, 0xe9, 0x2a, 0xe7, 0x6d, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + ], + }; + + static CANONICAL_LARGEST_ED25519_S_MINUS_ONE: Scalar = Scalar { + bytes: [ + 0x7c, 0x34, 0x47, 0x75, 0x47, 0x4a, 0x7f, 0x97, + 0x23, 0xb6, 0x3a, 0x8b, 0xe9, 0x2a, 0xe7, 0x6d, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + ], + }; + + #[test] + fn fuzzer_testcase_reduction() { + // LE bytes of 24519928653854221733733552434404946937899825954937634815 + let a_bytes = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + // LE bytes of 4975441334397345751130612518500927154628011511324180036903450236863266160640 + let b_bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 210, 210, 210, 255, 255, 255, 255, 10]; + // LE bytes of 6432735165214683820902750800207468552549813371247423777071615116673864412038 + let c_bytes = [134, 171, 119, 216, 180, 128, 178, 62, 171, 132, 32, 62, 34, 119, 104, 193, 47, 215, 181, 250, 14, 207, 172, 93, 75, 207, 211, 103, 144, 204, 56, 14]; + + let a = Scalar::from_bytes_mod_order(a_bytes); + let b = Scalar::from_bytes_mod_order(b_bytes); + let c = Scalar::from_bytes_mod_order(c_bytes); + + let mut tmp = [0u8; 64]; + + // also_a = (a mod l) + tmp[0..32].copy_from_slice(&a_bytes[..]); + let also_a = Scalar::from_bytes_mod_order_wide(&tmp); + + // also_b = (b mod l) + tmp[0..32].copy_from_slice(&b_bytes[..]); + let also_b = Scalar::from_bytes_mod_order_wide(&tmp); + + let expected_c = &a * &b; + let also_expected_c = &also_a * &also_b; + + assert_eq!(c, expected_c); + assert_eq!(c, also_expected_c); + } + + #[test] + fn non_adjacent_form_test_vector() { + let naf = A_SCALAR.non_adjacent_form(5); + for i in 0..256 { + assert_eq!(naf[i], A_NAF[i]); + } + } + + fn non_adjacent_form_iter(w: usize, x: &Scalar) { + let naf = x.non_adjacent_form(w); + + // Reconstruct the scalar from the computed NAF + let mut y = Scalar::zero(); + for i in (0..256).rev() { + y += y; + let digit = if naf[i] < 0 { + -Scalar::from((-naf[i]) as u64) + } else { + Scalar::from(naf[i] as u64) + }; + y += digit; + } + + assert_eq!(*x, y); + } + + #[test] + fn non_adjacent_form_random() { + let mut rng = rand::thread_rng(); + for _ in 0..1_000 { + let x = Scalar::random(&mut rng); + for w in &[5, 6, 7, 8] { + non_adjacent_form_iter(*w, &x); + } + } + } + + #[test] + fn from_u64() { + let val: u64 = 0xdeadbeefdeadbeef; + let s = Scalar::from(val); + assert_eq!(s[7], 0xde); + assert_eq!(s[6], 0xad); + assert_eq!(s[5], 0xbe); + assert_eq!(s[4], 0xef); + assert_eq!(s[3], 0xde); + assert_eq!(s[2], 0xad); + assert_eq!(s[1], 0xbe); + assert_eq!(s[0], 0xef); + } + + #[test] + fn scalar_mul_by_one() { + let test_scalar = &X * &Scalar::one(); + for i in 0..32 { + assert!(test_scalar[i] == X[i]); + } + } + + #[test] + fn add_reduces() { + // Check that the addition works + assert_eq!( + (LARGEST_ED25519_S + Scalar::one()).reduce(), + CANONICAL_LARGEST_ED25519_S_PLUS_ONE + ); + // Check that the addition reduces + assert_eq!( + LARGEST_ED25519_S + Scalar::one(), + CANONICAL_LARGEST_ED25519_S_PLUS_ONE + ); + } + + #[test] + fn sub_reduces() { + // Check that the subtraction works + assert_eq!( + (LARGEST_ED25519_S - Scalar::one()).reduce(), + CANONICAL_LARGEST_ED25519_S_MINUS_ONE + ); + // Check that the subtraction reduces + assert_eq!( + LARGEST_ED25519_S - Scalar::one(), + CANONICAL_LARGEST_ED25519_S_MINUS_ONE + ); + } + + #[test] + fn quarkslab_scalar_overflow_does_not_occur() { + // Check that manually-constructing large Scalars with + // from_bits cannot produce incorrect results. + // + // The from_bits function is required to implement X/Ed25519, + // while all other methods of constructing a Scalar produce + // reduced Scalars. However, this "invariant loophole" allows + // constructing large scalars which are not reduced mod l. + // + // This issue was discovered independently by both Jack + // "str4d" Grigg (issue #238), who noted that reduction was + // not performed on addition, and Laurent Grémy & Nicolas + // Surbayrole of Quarkslab, who noted that it was possible to + // cause an overflow and compute incorrect results. + // + // This test is adapted from the one suggested by Quarkslab. + + let large_bytes = [ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + ]; + + let a = Scalar::from_bytes_mod_order(large_bytes); + let b = Scalar::from_bits(large_bytes); + + assert_eq!(a, b.reduce()); + + let a_3 = a + a + a; + let b_3 = b + b + b; + + assert_eq!(a_3, b_3); + + let neg_a = -a; + let neg_b = -b; + + assert_eq!(neg_a, neg_b); + + let minus_a_3 = Scalar::zero() - a - a - a; + let minus_b_3 = Scalar::zero() - b - b - b; + + assert_eq!(minus_a_3, minus_b_3); + assert_eq!(minus_a_3, -a_3); + assert_eq!(minus_b_3, -b_3); + } + + #[test] + fn impl_add() { + let two = Scalar::from(2u64); + let one = Scalar::one(); + let should_be_two = &one + &one; + assert_eq!(should_be_two, two); + } + + #[allow(non_snake_case)] + #[test] + fn impl_mul() { + let should_be_X_times_Y = &X * &Y; + assert_eq!(should_be_X_times_Y, X_TIMES_Y); + } + + #[allow(non_snake_case)] + #[test] + fn impl_product() { + // Test that product works for non-empty iterators + let X_Y_vector = vec![X, Y]; + let should_be_X_times_Y: Scalar = X_Y_vector.iter().product(); + assert_eq!(should_be_X_times_Y, X_TIMES_Y); + + // Test that product works for the empty iterator + let one = Scalar::one(); + let empty_vector = vec![]; + let should_be_one: Scalar = empty_vector.iter().product(); + assert_eq!(should_be_one, one); + + // Test that product works for iterators where Item = Scalar + let xs = [Scalar::from(2u64); 10]; + let ys = [Scalar::from(3u64); 10]; + // now zs is an iterator with Item = Scalar + let zs = xs.iter().zip(ys.iter()).map(|(x,y)| x * y); + + let x_prod: Scalar = xs.iter().product(); + let y_prod: Scalar = ys.iter().product(); + let z_prod: Scalar = zs.product(); + + assert_eq!(x_prod, Scalar::from(1024u64)); + assert_eq!(y_prod, Scalar::from(59049u64)); + assert_eq!(z_prod, Scalar::from(60466176u64)); + assert_eq!(x_prod * y_prod, z_prod); + + } + + #[test] + fn impl_sum() { + + // Test that sum works for non-empty iterators + let two = Scalar::from(2u64); + let one_vector = vec![Scalar::one(), Scalar::one()]; + let should_be_two: Scalar = one_vector.iter().sum(); + assert_eq!(should_be_two, two); + + // Test that sum works for the empty iterator + let zero = Scalar::zero(); + let empty_vector = vec![]; + let should_be_zero: Scalar = empty_vector.iter().sum(); + assert_eq!(should_be_zero, zero); + + // Test that sum works for owned types + let xs = [Scalar::from(1u64); 10]; + let ys = [Scalar::from(2u64); 10]; + // now zs is an iterator with Item = Scalar + let zs = xs.iter().zip(ys.iter()).map(|(x,y)| x + y); + + let x_sum: Scalar = xs.iter().sum(); + let y_sum: Scalar = ys.iter().sum(); + let z_sum: Scalar = zs.sum(); + + assert_eq!(x_sum, Scalar::from(10u64)); + assert_eq!(y_sum, Scalar::from(20u64)); + assert_eq!(z_sum, Scalar::from(30u64)); + assert_eq!(x_sum + y_sum, z_sum); + } + + #[test] + fn square() { + let expected = &X * &X; + let actual = X.unpack().square().pack(); + for i in 0..32 { + assert!(expected[i] == actual[i]); + } + } + + #[test] + fn reduce() { + let biggest = Scalar::from_bytes_mod_order([0xff; 32]); + assert_eq!(biggest, CANONICAL_2_256_MINUS_1); + } + + #[test] + fn from_bytes_mod_order_wide() { + let mut bignum = [0u8; 64]; + // set bignum = x + 2^256x + for i in 0..32 { + bignum[ i] = X[i]; + bignum[32+i] = X[i]; + } + // 3958878930004874126169954872055634648693766179881526445624823978500314864344 + // = x + 2^256x (mod l) + let reduced = Scalar{ + bytes: [ + 216, 154, 179, 139, 210, 121, 2, 71, + 69, 99, 158, 216, 23, 173, 63, 100, + 204, 0, 91, 50, 219, 153, 57, 249, + 28, 82, 31, 197, 100, 165, 192, 8, + ], + }; + let test_red = Scalar::from_bytes_mod_order_wide(&bignum); + for i in 0..32 { + assert!(test_red[i] == reduced[i]); + } + } + + #[allow(non_snake_case)] + #[test] + fn invert() { + let inv_X = X.invert(); + assert_eq!(inv_X, XINV); + let should_be_one = &inv_X * &X; + assert_eq!(should_be_one, Scalar::one()); + } + + // Negating a scalar twice should result in the original scalar. + #[allow(non_snake_case)] + #[test] + fn neg_twice_is_identity() { + let negative_X = -&X; + let should_be_X = -&negative_X; + + assert_eq!(should_be_X, X); + } + + #[test] + fn to_bytes_from_bytes_roundtrips() { + let unpacked = X.unpack(); + let bytes = unpacked.to_bytes(); + let should_be_unpacked = UnpackedScalar::from_bytes(&bytes); + + assert_eq!(should_be_unpacked.0, unpacked.0); + } + + #[test] + fn montgomery_reduce_matches_from_bytes_mod_order_wide() { + let mut bignum = [0u8; 64]; + + // set bignum = x + 2^256x + for i in 0..32 { + bignum[ i] = X[i]; + bignum[32+i] = X[i]; + } + // x + 2^256x (mod l) + // = 3958878930004874126169954872055634648693766179881526445624823978500314864344 + let expected = Scalar{ + bytes: [ + 216, 154, 179, 139, 210, 121, 2, 71, + 69, 99, 158, 216, 23, 173, 63, 100, + 204, 0, 91, 50, 219, 153, 57, 249, + 28, 82, 31, 197, 100, 165, 192, 8 + ], + }; + let reduced = Scalar::from_bytes_mod_order_wide(&bignum); + + // The reduced scalar should match the expected + assert_eq!(reduced.bytes, expected.bytes); + + // (x + 2^256x) * R + let interim = UnpackedScalar::mul_internal(&UnpackedScalar::from_bytes_wide(&bignum), + &constants::R); + // ((x + 2^256x) * R) / R (mod l) + let montgomery_reduced = UnpackedScalar::montgomery_reduce(&interim); + + // The Montgomery reduced scalar should match the reduced one, as well as the expected + assert_eq!(montgomery_reduced.0, reduced.unpack().0); + assert_eq!(montgomery_reduced.0, expected.unpack().0) + } + + #[test] + fn canonical_decoding() { + // canonical encoding of 1667457891 + let canonical_bytes = [99, 99, 99, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,]; + + // encoding of + // 7265385991361016183439748078976496179028704920197054998554201349516117938192 + // = 28380414028753969466561515933501938171588560817147392552250411230663687203 (mod l) + // non_canonical because unreduced mod l + let non_canonical_bytes_because_unreduced = [16; 32]; + + // encoding with high bit set, to check that the parser isn't pre-masking the high bit + let non_canonical_bytes_because_highbit = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128]; + + assert!( Scalar::from_canonical_bytes(canonical_bytes).is_some() ); + assert!( Scalar::from_canonical_bytes(non_canonical_bytes_because_unreduced).is_none() ); + assert!( Scalar::from_canonical_bytes(non_canonical_bytes_because_highbit).is_none() ); + } + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_scalar_roundtrip() { + use bincode; + let encoded = bincode::serialize(&X).unwrap(); + let parsed: Scalar = bincode::deserialize(&encoded).unwrap(); + assert_eq!(parsed, X); + + // Check that the encoding is 32 bytes exactly + assert_eq!(encoded.len(), 32); + + // Check that the encoding itself matches the usual one + assert_eq!( + X, + bincode::deserialize(X.as_bytes()).unwrap(), + ); + } + + #[cfg(debug_assertions)] + #[test] + #[should_panic] + fn batch_invert_with_a_zero_input_panics() { + let mut xs = vec![Scalar::one(); 16]; + xs[3] = Scalar::zero(); + // This should panic in debug mode. + Scalar::batch_invert(&mut xs); + } + + #[test] + fn batch_invert_empty() { + assert_eq!(Scalar::one(), Scalar::batch_invert(&mut [])); + } + + #[test] + fn batch_invert_consistency() { + let mut x = Scalar::from(1u64); + let mut v1: Vec<_> = (0..16).map(|_| {let tmp = x; x = x + x; tmp}).collect(); + let v2 = v1.clone(); + + let expected: Scalar = v1.iter().product(); + let expected = expected.invert(); + let ret = Scalar::batch_invert(&mut v1); + assert_eq!(ret, expected); + + for (a, b) in v1.iter().zip(v2.iter()) { + assert_eq!(a * b, Scalar::one()); + } + } + + fn test_pippenger_radix_iter(scalar: Scalar, w: usize) { + let digits_count = Scalar::to_radix_2w_size_hint(w); + let digits = scalar.to_radix_2w(w); + + let radix = Scalar::from((1< +// - Henry de Valence + +//! Module for common traits. + +#![allow(non_snake_case)] + +use core::borrow::Borrow; + +use subtle; + +use scalar::Scalar; + +// ------------------------------------------------------------------------ +// Public Traits +// ------------------------------------------------------------------------ + +/// Trait for getting the identity element of a point type. +pub trait Identity { + /// Returns the identity element of the curve. + /// Can be used as a constructor. + fn identity() -> Self; +} + +/// Trait for testing if a curve point is equivalent to the identity point. +pub trait IsIdentity { + /// Return true if this element is the identity element of the curve. + fn is_identity(&self) -> bool; +} + +/// Implement generic identity equality testing for a point representations +/// which have constant-time equality testing and a defined identity +/// constructor. +impl IsIdentity for T +where + T: subtle::ConstantTimeEq + Identity, +{ + fn is_identity(&self) -> bool { + self.ct_eq(&T::identity()).unwrap_u8() == 1u8 + } +} + +/// A precomputed table of basepoints, for optimising scalar multiplications. +pub trait BasepointTable { + /// The type of point contained within this table. + type Point; + + /// Generate a new precomputed basepoint table from the given basepoint. + fn create(basepoint: &Self::Point) -> Self; + + /// Retrieve the original basepoint from this table. + fn basepoint(&self) -> Self::Point; + + /// Multiply a `scalar` by this precomputed basepoint table, in constant time. + fn basepoint_mul(&self, scalar: &Scalar) -> Self::Point; +} + +/// A trait for constant-time multiscalar multiplication without precomputation. +pub trait MultiscalarMul { + /// The type of point being multiplied, e.g., `RistrettoPoint`. + type Point; + + /// Given an iterator of (possibly secret) scalars and an iterator of + /// public points, compute + /// $$ + /// Q = c\_1 P\_1 + \cdots + c\_n P\_n. + /// $$ + /// + /// It is an error to call this function with two iterators of different lengths. + /// + /// # Examples + /// + /// The trait bound aims for maximum flexibility: the inputs must be + /// convertable to iterators (`I: IntoIter`), and the iterator's items + /// must be `Borrow` (or `Borrow`), to allow + /// iterators returning either `Scalar`s or `&Scalar`s. + /// + /// ``` + /// use curve25519_dalek::constants; + /// use curve25519_dalek::traits::MultiscalarMul; + /// use curve25519_dalek::ristretto::RistrettoPoint; + /// use curve25519_dalek::scalar::Scalar; + /// + /// // Some scalars + /// let a = Scalar::from(87329482u64); + /// let b = Scalar::from(37264829u64); + /// let c = Scalar::from(98098098u64); + /// + /// // Some points + /// let P = constants::RISTRETTO_BASEPOINT_POINT; + /// let Q = P + P; + /// let R = P + Q; + /// + /// // A1 = a*P + b*Q + c*R + /// let abc = [a,b,c]; + /// let A1 = RistrettoPoint::multiscalar_mul(&abc, &[P,Q,R]); + /// // Note: (&abc).into_iter(): Iterator + /// + /// // A2 = (-a)*P + (-b)*Q + (-c)*R + /// let minus_abc = abc.iter().map(|x| -x); + /// let A2 = RistrettoPoint::multiscalar_mul(minus_abc, &[P,Q,R]); + /// // Note: minus_abc.into_iter(): Iterator + /// + /// assert_eq!(A1.compress(), (-A2).compress()); + /// ``` + fn multiscalar_mul(scalars: I, points: J) -> Self::Point + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow; +} + +/// A trait for variable-time multiscalar multiplication without precomputation. +pub trait VartimeMultiscalarMul { + /// The type of point being multiplied, e.g., `RistrettoPoint`. + type Point; + + /// Given an iterator of public scalars and an iterator of + /// `Option`s of points, compute either `Some(Q)`, where + /// $$ + /// Q = c\_1 P\_1 + \cdots + c\_n P\_n, + /// $$ + /// if all points were `Some(P_i)`, or else return `None`. + /// + /// This function is particularly useful when verifying statements + /// involving compressed points. Accepting `Option` allows + /// inlining point decompression into the multiscalar call, + /// avoiding the need for temporary buffers. + /// ``` + /// use curve25519_dalek::constants; + /// use curve25519_dalek::traits::VartimeMultiscalarMul; + /// use curve25519_dalek::ristretto::RistrettoPoint; + /// use curve25519_dalek::scalar::Scalar; + /// + /// // Some scalars + /// let a = Scalar::from(87329482u64); + /// let b = Scalar::from(37264829u64); + /// let c = Scalar::from(98098098u64); + /// let abc = [a,b,c]; + /// + /// // Some points + /// let P = constants::RISTRETTO_BASEPOINT_POINT; + /// let Q = P + P; + /// let R = P + Q; + /// let PQR = [P, Q, R]; + /// + /// let compressed = [P.compress(), Q.compress(), R.compress()]; + /// + /// // Now we can compute A1 = a*P + b*Q + c*R using P, Q, R: + /// let A1 = RistrettoPoint::vartime_multiscalar_mul(&abc, &PQR); + /// + /// // Or using the compressed points: + /// let A2 = RistrettoPoint::optional_multiscalar_mul( + /// &abc, + /// compressed.iter().map(|pt| pt.decompress()), + /// ); + /// + /// assert_eq!(A2, Some(A1)); + /// + /// // It's also possible to mix compressed and uncompressed points: + /// let A3 = RistrettoPoint::optional_multiscalar_mul( + /// abc.iter() + /// .chain(abc.iter()), + /// compressed.iter().map(|pt| pt.decompress()) + /// .chain(PQR.iter().map(|&pt| Some(pt))), + /// ); + /// + /// assert_eq!(A3, Some(A1+A1)); + /// ``` + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>; + + /// Given an iterator of public scalars and an iterator of + /// public points, compute + /// $$ + /// Q = c\_1 P\_1 + \cdots + c\_n P\_n, + /// $$ + /// using variable-time operations. + /// + /// It is an error to call this function with two iterators of different lengths. + /// + /// # Examples + /// + /// The trait bound aims for maximum flexibility: the inputs must be + /// convertable to iterators (`I: IntoIter`), and the iterator's items + /// must be `Borrow` (or `Borrow`), to allow + /// iterators returning either `Scalar`s or `&Scalar`s. + /// + /// ``` + /// use curve25519_dalek::constants; + /// use curve25519_dalek::traits::VartimeMultiscalarMul; + /// use curve25519_dalek::ristretto::RistrettoPoint; + /// use curve25519_dalek::scalar::Scalar; + /// + /// // Some scalars + /// let a = Scalar::from(87329482u64); + /// let b = Scalar::from(37264829u64); + /// let c = Scalar::from(98098098u64); + /// + /// // Some points + /// let P = constants::RISTRETTO_BASEPOINT_POINT; + /// let Q = P + P; + /// let R = P + Q; + /// + /// // A1 = a*P + b*Q + c*R + /// let abc = [a,b,c]; + /// let A1 = RistrettoPoint::vartime_multiscalar_mul(&abc, &[P,Q,R]); + /// // Note: (&abc).into_iter(): Iterator + /// + /// // A2 = (-a)*P + (-b)*Q + (-c)*R + /// let minus_abc = abc.iter().map(|x| -x); + /// let A2 = RistrettoPoint::vartime_multiscalar_mul(minus_abc, &[P,Q,R]); + /// // Note: minus_abc.into_iter(): Iterator + /// + /// assert_eq!(A1.compress(), (-A2).compress()); + /// ``` + fn vartime_multiscalar_mul(scalars: I, points: J) -> Self::Point + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + Self::Point: Clone, + { + Self::optional_multiscalar_mul( + scalars, + points.into_iter().map(|P| Some(P.borrow().clone())), + ) + .unwrap() + } +} + +/// A trait for variable-time multiscalar multiplication with precomputation. +/// +/// A general multiscalar multiplication with precomputation can be written as +/// $$ +/// Q = a_1 A_1 + \cdots + a_n A_n + b_1 B_1 + \cdots + b_m B_m, +/// $$ +/// where the \\(B_i\\) are *static* points, for which precomputation +/// is possible, and the \\(A_j\\) are *dynamic* points, for which +/// precomputation is not possible. +/// +/// This trait has three methods for performing this computation: +/// +/// * [`vartime_multiscalar_mul`], which handles the special case +/// where \\(n = 0\\) and there are no dynamic points; +/// +/// * [`vartime_mixed_multiscalar_mul`], which takes the dynamic +/// points as already-validated `Point`s and is infallible; +/// +/// * [`optional_mixed_multiscalar_mul`], which takes the dynamic +/// points as `Option`s and returns an `Option`, +/// allowing decompression to be composed into the input iterators. +/// +/// All methods require that the lengths of the input iterators be +/// known and matching, as if they were `ExactSizeIterator`s. (It +/// does not require `ExactSizeIterator` only because that trait is +/// broken). +pub trait VartimePrecomputedMultiscalarMul: Sized { + /// The type of point to be multiplied, e.g., `RistrettoPoint`. + type Point: Clone; + + /// Given the static points \\( B_i \\), perform precomputation + /// and return the precomputation data. + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow; + + /// Given `static_scalars`, an iterator of public scalars + /// \\(b_i\\), compute + /// $$ + /// Q = b_1 B_1 + \cdots + b_m B_m, + /// $$ + /// where the \\(B_j\\) are the points that were supplied to `new`. + /// + /// It is an error to call this function with iterators of + /// inconsistent lengths. + /// + /// The trait bound aims for maximum flexibility: the input must + /// be convertable to iterators (`I: IntoIter`), and the + /// iterator's items must be `Borrow`, to allow iterators + /// returning either `Scalar`s or `&Scalar`s. + fn vartime_multiscalar_mul(&self, static_scalars: I) -> Self::Point + where + I: IntoIterator, + I::Item: Borrow, + { + use core::iter; + + Self::vartime_mixed_multiscalar_mul( + self, + static_scalars, + iter::empty::(), + iter::empty::(), + ) + } + + /// Given `static_scalars`, an iterator of public scalars + /// \\(b_i\\), `dynamic_scalars`, an iterator of public scalars + /// \\(a_i\\), and `dynamic_points`, an iterator of points + /// \\(A_i\\), compute + /// $$ + /// Q = a_1 A_1 + \cdots + a_n A_n + b_1 B_1 + \cdots + b_m B_m, + /// $$ + /// where the \\(B_j\\) are the points that were supplied to `new`. + /// + /// It is an error to call this function with iterators of + /// inconsistent lengths. + /// + /// The trait bound aims for maximum flexibility: the inputs must be + /// convertable to iterators (`I: IntoIter`), and the iterator's items + /// must be `Borrow` (or `Borrow`), to allow + /// iterators returning either `Scalar`s or `&Scalar`s. + fn vartime_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Self::Point + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator, + K::Item: Borrow, + { + Self::optional_mixed_multiscalar_mul( + self, + static_scalars, + dynamic_scalars, + dynamic_points.into_iter().map(|P| Some(P.borrow().clone())), + ) + .unwrap() + } + + /// Given `static_scalars`, an iterator of public scalars + /// \\(b_i\\), `dynamic_scalars`, an iterator of public scalars + /// \\(a_i\\), and `dynamic_points`, an iterator of points + /// \\(A_i\\), compute + /// $$ + /// Q = a_1 A_1 + \cdots + a_n A_n + b_1 B_1 + \cdots + b_m B_m, + /// $$ + /// where the \\(B_j\\) are the points that were supplied to `new`. + /// + /// If any of the dynamic points were `None`, return `None`. + /// + /// It is an error to call this function with iterators of + /// inconsistent lengths. + /// + /// This function is particularly useful when verifying statements + /// involving compressed points. Accepting `Option` allows + /// inlining point decompression into the multiscalar call, + /// avoiding the need for temporary buffers. + fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator>; +} + +// ------------------------------------------------------------------------ +// Private Traits +// ------------------------------------------------------------------------ + +/// Trait for checking whether a point is on the curve. +/// +/// This trait is only for debugging/testing, since it should be +/// impossible for a `curve25519-dalek` user to construct an invalid +/// point. +pub(crate) trait ValidityCheck { + /// Checks whether the point is on the curve. Not CT. + fn is_valid(&self) -> bool; +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/src/window.rs b/net/gurk-rs/files/vendor/curve25519-dalek/src/window.rs new file mode 100644 index 0000000..2cf1fbe --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/src/window.rs @@ -0,0 +1,228 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Code for fixed- and sliding-window functionality + +#![allow(non_snake_case)] + +use core::fmt::Debug; + +use subtle::ConditionallyNegatable; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; +use subtle::Choice; + +use traits::Identity; + +use edwards::EdwardsPoint; +use backend::serial::curve_models::ProjectiveNielsPoint; +use backend::serial::curve_models::AffineNielsPoint; + +use zeroize::Zeroize; + +macro_rules! impl_lookup_table { + (Name = $name:ident, Size = $size:expr, SizeNeg = $neg:expr, SizeRange = $range:expr, ConversionRange = $conv_range:expr) => { + +/// A lookup table of precomputed multiples of a point \\(P\\), used to +/// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\). +/// +/// The computation of \\( xP \\) is done in constant time by the `select` function. +/// +/// Since `LookupTable` does not implement `Index`, it's more difficult +/// to accidentally use the table directly. Unfortunately the table is +/// only `pub(crate)` so that we can write hardcoded constants, so it's +/// still technically possible. It would be nice to prevent direct +/// access to the table. +#[derive(Copy, Clone)] +pub struct $name(pub(crate) [T; $size]); + +impl $name +where + T: Identity + ConditionallySelectable + ConditionallyNegatable, +{ + /// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time. + pub fn select(&self, x: i8) -> T { + debug_assert!(x >= $neg); + debug_assert!(x as i16 <= $size as i16); // XXX We have to convert to i16s here for the radix-256 case.. this is wrong. + + // Compute xabs = |x| + let xmask = x as i16 >> 7; + let xabs = (x as i16 + xmask) ^ xmask; + + // Set t = 0 * P = identity + let mut t = T::identity(); + for j in $range { + // Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`. + let c = (xabs as u16).ct_eq(&(j as u16)); + t.conditional_assign(&self.0[j - 1], c); + } + // Now t == |x| * P. + + let neg_mask = Choice::from((xmask & 1) as u8); + t.conditional_negate(neg_mask); + // Now t == x * P. + + t + } +} + +impl Default for $name { + fn default() -> $name { + $name([T::default(); $size]) + } +} + +impl Debug for $name { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{:?}(", stringify!($name))?; + + for x in self.0.iter() { + write!(f, "{:?}", x)?; + } + + write!(f, ")") + } +} + +impl<'a> From<&'a EdwardsPoint> for $name { + fn from(P: &'a EdwardsPoint) -> Self { + let mut points = [P.to_projective_niels(); $size]; + for j in $conv_range { + points[j + 1] = (P + &points[j]).to_extended().to_projective_niels(); + } + $name(points) + } +} + +impl<'a> From<&'a EdwardsPoint> for $name { + fn from(P: &'a EdwardsPoint) -> Self { + let mut points = [P.to_affine_niels(); $size]; + // XXX batch inversion would be good if perf mattered here + for j in $conv_range { + points[j + 1] = (P + &points[j]).to_extended().to_affine_niels() + } + $name(points) + } +} + +impl Zeroize for $name +where + T: Copy + Default + Zeroize +{ + fn zeroize(&mut self) { + for x in self.0.iter_mut() { + x.zeroize(); + } + } +} + +}} // End macro_rules! impl_lookup_table + +// The first one has to be named "LookupTable" because it's used as a constructor for consts. +impl_lookup_table! {Name = LookupTable, Size = 8, SizeNeg = -8, SizeRange = 1 .. 9, ConversionRange = 0 .. 7} // radix-16 +impl_lookup_table! {Name = LookupTableRadix32, Size = 16, SizeNeg = -16, SizeRange = 1 .. 17, ConversionRange = 0 .. 15} // radix-32 +impl_lookup_table! {Name = LookupTableRadix64, Size = 32, SizeNeg = -32, SizeRange = 1 .. 33, ConversionRange = 0 .. 31} // radix-64 +impl_lookup_table! {Name = LookupTableRadix128, Size = 64, SizeNeg = -64, SizeRange = 1 .. 65, ConversionRange = 0 .. 63} // radix-128 +impl_lookup_table! {Name = LookupTableRadix256, Size = 128, SizeNeg = -128, SizeRange = 1 .. 129, ConversionRange = 0 .. 127} // radix-256 + +// For homogeneity we then alias it to "LookupTableRadix16". +pub type LookupTableRadix16 = LookupTable; + +/// Holds odd multiples 1A, 3A, ..., 15A of a point A. +#[derive(Copy, Clone)] +pub(crate) struct NafLookupTable5(pub(crate) [T; 8]); + +impl NafLookupTable5 { + /// Given public, odd \\( x \\) with \\( 0 < x < 2^4 \\), return \\(xA\\). + pub fn select(&self, x: usize) -> T { + debug_assert_eq!(x & 1, 1); + debug_assert!(x < 16); + + self.0[x / 2] + } +} + +impl Debug for NafLookupTable5 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "NafLookupTable5({:?})", self.0) + } +} + +impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.to_projective_niels(); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + NafLookupTable5(Ai) + } +} + +impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.to_affine_niels(); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_affine_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + NafLookupTable5(Ai) + } +} + +/// Holds stuff up to 8. +#[derive(Copy, Clone)] +pub(crate) struct NafLookupTable8(pub(crate) [T; 64]); + +impl NafLookupTable8 { + pub fn select(&self, x: usize) -> T { + debug_assert_eq!(x & 1, 1); + debug_assert!(x < 128); + + self.0[x / 2] + } +} + +impl Debug for NafLookupTable8 { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "NafLookupTable8([\n")?; + for i in 0..64 { + write!(f, "\t{:?},\n", &self.0[i])?; + } + write!(f, "])") + } +} + +impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.to_projective_niels(); 64]; + let A2 = A.double(); + for i in 0..63 { + Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] + NafLookupTable8(Ai) + } +} + +impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.to_affine_niels(); 64]; + let A2 = A.double(); + for i in 0..63 { + Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_affine_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] + NafLookupTable8(Ai) + } +} diff --git a/net/gurk-rs/files/vendor/curve25519-dalek/vendor/ristretto.sage b/net/gurk-rs/files/vendor/curve25519-dalek/vendor/ristretto.sage new file mode 100644 index 0000000..04cf4f9 --- /dev/null +++ b/net/gurk-rs/files/vendor/curve25519-dalek/vendor/ristretto.sage @@ -0,0 +1,857 @@ +import binascii +class InvalidEncodingException(Exception): pass +class NotOnCurveException(Exception): pass +class SpecException(Exception): pass + +def lobit(x): return int(x) & 1 +def hibit(x): return lobit(2*x) +def negative(x): return lobit(x) +def enc_le(x,n): return bytearray([int(x)>>(8*i) & 0xFF for i in xrange(n)]) +def dec_le(x): return sum(b<<(8*i) for i,b in enumerate(x)) +def randombytes(n): return bytearray([randint(0,255) for _ in range(n)]) + +def optimized_version_of(spec): + """Decorator: This function is an optimized version of some specification""" + def decorator(f): + def wrapper(self,*args,**kwargs): + def pr(x): + if isinstance(x,bytearray): return binascii.hexlify(x) + else: return str(x) + try: spec_ans = getattr(self,spec,spec)(*args,**kwargs),None + except Exception as e: spec_ans = None,e + try: opt_ans = f(self,*args,**kwargs),None + except Exception as e: opt_ans = None,e + if spec_ans[1] is None and opt_ans[1] is not None: + raise + #raise SpecException("Mismatch in %s: spec returned %s but opt threw %s" + # % (f.__name__,str(spec_ans[0]),str(opt_ans[1]))) + if spec_ans[1] is not None and opt_ans[1] is None: + raise + #raise SpecException("Mismatch in %s: spec threw %s but opt returned %s" + # % (f.__name__,str(spec_ans[1]),str(opt_ans[0]))) + if spec_ans[0] != opt_ans[0]: + raise SpecException("Mismatch in %s: %s != %s" + % (f.__name__,pr(spec_ans[0]),pr(opt_ans[0]))) + if opt_ans[1] is not None: raise + else: return opt_ans[0] + wrapper.__name__ = f.__name__ + return wrapper + return decorator + +def xsqrt(x,exn=InvalidEncodingException("Not on curve")): + """Return sqrt(x)""" + if not is_square(x): raise exn + s = sqrt(x) + if negative(s): s=-s + return s + +def isqrt(x,exn=InvalidEncodingException("Not on curve")): + """Return 1/sqrt(x)""" + if x==0: return 0 + if not is_square(x): raise exn + s = sqrt(x) + #if negative(s): s=-s + return 1/s + +def inv0(x): return 1/x if x != 0 else 0 + +def isqrt_i(x): + """Return 1/sqrt(x) or 1/sqrt(zeta * x)""" + if x==0: return True,0 + gen = x.parent(-1) + while is_square(gen): gen = sqrt(gen) + if is_square(x): return True,1/sqrt(x) + else: return False,1/sqrt(x*gen) + +class QuotientEdwardsPoint(object): + """Abstract class for point an a quotiented Edwards curve; needs F,a,d,cofactor to work""" + def __init__(self,x=0,y=1): + x = self.x = self.F(x) + y = self.y = self.F(y) + if y^2 + self.a*x^2 != 1 + self.d*x^2*y^2: + raise NotOnCurveException(str(self)) + + def __repr__(self): + return "%s(0x%x,0x%x)" % (self.__class__.__name__, self.x, self.y) + + def __iter__(self): + yield self.x + yield self.y + + def __add__(self,other): + x,y = self + X,Y = other + a,d = self.a,self.d + return self.__class__( + (x*Y+y*X)/(1+d*x*y*X*Y), + (y*Y-a*x*X)/(1-d*x*y*X*Y) + ) + + def __neg__(self): return self.__class__(-self.x,self.y) + def __sub__(self,other): return self + (-other) + def __rmul__(self,other): return self*other + def __eq__(self,other): + """NB: this is the only method that is different from the usual one""" + x,y = self + X,Y = other + return x*Y == X*y or (self.cofactor==8 and -self.a*x*X == y*Y) + def __ne__(self,other): return not (self==other) + + def __mul__(self,exp): + exp = int(exp) + if exp < 0: exp,self = -exp,-self + total = self.__class__() + work = self + while exp != 0: + if exp & 1: total += work + work += work + exp >>= 1 + return total + + def xyzt(self): + x,y = self + z = self.F.random_element() + return x*z,y*z,z,x*y*z + + def torque(self): + """Apply cofactor group, except keeping the point even""" + if self.cofactor == 8: + if self.a == -1: return self.__class__(self.y*self.i, self.x*self.i) + if self.a == 1: return self.__class__(-self.y, self.x) + else: + return self.__class__(-self.x, -self.y) + + def doubleAndEncodeSpec(self): + return (self+self).encode() + + # Utility functions + @classmethod + def bytesToGf(cls,bytes,mustBeProper=True,mustBePositive=False,maskHiBits=False): + """Convert little-endian bytes to field element, sanity check length""" + if len(bytes) != cls.encLen: + raise InvalidEncodingException("wrong length %d" % len(bytes)) + s = dec_le(bytes) + if mustBeProper and s >= cls.F.order(): + raise InvalidEncodingException("%d out of range!" % s) + bitlen = int(ceil(log(cls.F.order())/log(2))) + if maskHiBits: s &= 2^bitlen-1 + s = cls.F(s) + if mustBePositive and negative(s): + raise InvalidEncodingException("%d is negative!" % s) + return s + + @classmethod + def gfToBytes(cls,x,mustBePositive=False): + """Convert little-endian bytes to field element, sanity check length""" + if negative(x) and mustBePositive: x = -x + return enc_le(x,cls.encLen) + +class RistrettoPoint(QuotientEdwardsPoint): + """The new Ristretto group""" + def encodeSpec(self): + """Unoptimized specification for encoding""" + x,y = self + if self.cofactor==8 and (negative(x*y) or y==0): (x,y) = self.torque() + if y == -1: y = 1 # Avoid divide by 0; doesn't affect impl + + if negative(x): x,y = -x,-y + s = xsqrt(self.mneg*(1-y)/(1+y),exn=Exception("Unimplemented: point is odd: " + str(self))) + return self.gfToBytes(s) + + @classmethod + def decodeSpec(cls,s): + """Unoptimized specification for decoding""" + s = cls.bytesToGf(s,mustBePositive=True) + + a,d = cls.a,cls.d + x = xsqrt(4*s^2 / (a*d*(1+a*s^2)^2 - (1-a*s^2)^2)) + y = (1+a*s^2) / (1-a*s^2) + + if cls.cofactor==8 and (negative(x*y) or y==0): + raise InvalidEncodingException("x*y has high bit") + + return cls(x,y) + + @optimized_version_of("encodeSpec") + def encode(self): + """Encode, optimized version""" + a,d,mneg = self.a,self.d,self.mneg + x,y,z,t = self.xyzt() + + if self.cofactor==8: + u1 = mneg*(z+y)*(z-y) + u2 = x*y # = t*z + isr = isqrt(u1*u2^2) + i1 = isr*u1 # sqrt(mneg*(z+y)*(z-y))/(x*y) + i2 = isr*u2 # 1/sqrt(a*(y+z)*(y-z)) + z_inv = i1*i2*t # 1/z + + if negative(t*z_inv): + if a==-1: + x,y = y*self.i,x*self.i + den_inv = self.magic * i1 + else: + x,y = -y,x + den_inv = self.i * self.magic * i1 + + else: + den_inv = i2 + + if negative(x*z_inv): y = -y + s = (z-y) * den_inv + else: + num = mneg*(z+y)*(z-y) + isr = isqrt(num*y^2) + if negative(isr^2*num*y*t): y = -y + s = isr*y*(z-y) + + return self.gfToBytes(s,mustBePositive=True) + + @optimized_version_of("doubleAndEncodeSpec") + def doubleAndEncode(self): + X,Y,Z,T = self.xyzt() + a,d,mneg = self.a,self.d,self.mneg + + if self.cofactor==8: + e = 2*X*Y + f = Z^2+d*T^2 + g = Y^2-a*X^2 + h = Z^2-d*T^2 + + inv1 = 1/(e*f*g*h) + z_inv = inv1*e*g # 1 / (f*h) + t_inv = inv1*f*h + + if negative(e*g*z_inv): + if a==-1: sqrta = self.i + else: sqrta = -1 + e,f,g,h = g,h,-e,f*sqrta + factor = self.i + else: + factor = self.magic + + if negative(h*e*z_inv): g=-g + s = (h-g)*factor*g*t_inv + + else: + foo = Y^2+a*X^2 + bar = X*Y + den = 1/(foo*bar) + if negative(2*bar^2*den): tmp = a*X^2 + else: tmp = Y^2 + s = self.magic*(Z^2-tmp)*foo*den + + return self.gfToBytes(s,mustBePositive=True) + + @classmethod + @optimized_version_of("decodeSpec") + def decode(cls,s): + """Decode, optimized version""" + s = cls.bytesToGf(s,mustBePositive=True) + + a,d = cls.a,cls.d + yden = 1-a*s^2 + ynum = 1+a*s^2 + yden_sqr = yden^2 + xden_sqr = a*d*ynum^2 - yden_sqr + + isr = isqrt(xden_sqr * yden_sqr) + + xden_inv = isr * yden + yden_inv = xden_inv * isr * xden_sqr + + x = 2*s*xden_inv + if negative(x): x = -x + y = ynum * yden_inv + + if cls.cofactor==8 and (negative(x*y) or y==0): + raise InvalidEncodingException("x*y is invalid: %d, %d" % (x,y)) + + return cls(x,y) + + @classmethod + def fromJacobiQuartic(cls,s,t,sgn=1): + """Convert point from its Jacobi Quartic representation""" + a,d = cls.a,cls.d + assert s^4 - 2*cls.a*(1-2*d/(d-a))*s^2 + 1 == t^2 + x = 2*s*cls.magic / t + y = (1+a*s^2) / (1-a*s^2) + return cls(sgn*x,y) + + @classmethod + def elligatorSpec(cls,r0): + a,d = cls.a,cls.d + r = cls.qnr * cls.bytesToGf(r0,mustBeProper=False,maskHiBits=True)^2 + den = (d*r-a)*(a*r-d) + if den == 0: return cls() + n1 = cls.a*(r+1)*(a+d)*(d-a)/den + n2 = r*n1 + if is_square(n1): + sgn,s,t = 1, xsqrt(n1), -(r-1)*(a+d)^2 / den - 1 + else: + sgn,s,t = -1,-xsqrt(n2), r*(r-1)*(a+d)^2 / den - 1 + + return cls.fromJacobiQuartic(s,t) + + @classmethod + @optimized_version_of("elligatorSpec") + def elligator(cls,r0): + a,d = cls.a,cls.d + r0 = cls.bytesToGf(r0,mustBeProper=False,maskHiBits=True) + r = cls.qnr * r0^2 + den = (d*r-a)*(a*r-d) + num = cls.a*(r+1)*(a+d)*(d-a) + + iss,isri = isqrt_i(num*den) + if iss: sgn,twiddle = 1,1 + else: sgn,twiddle = -1,r0*cls.qnr + isri *= twiddle + s = isri*num + t = -sgn*isri*s*(r-1)*(d+a)^2 - 1 + if negative(s) == iss: s = -s + return cls.fromJacobiQuartic(s,t) + + +class Decaf_1_1_Point(QuotientEdwardsPoint): + """Like current decaf but tweaked for simplicity""" + def encodeSpec(self): + """Unoptimized specification for encoding""" + a,d = self.a,self.d + x,y = self + if x==0 or y==0: return(self.gfToBytes(0)) + + if self.cofactor==8 and negative(x*y*self.isoMagic): + x,y = self.torque() + + sr = xsqrt(1-a*x^2) + altx = x*y*self.isoMagic / sr + if negative(altx): s = (1+sr)/x + else: s = (1-sr)/x + + return self.gfToBytes(s,mustBePositive=True) + + @classmethod + def decodeSpec(cls,s): + """Unoptimized specification for decoding""" + a,d = cls.a,cls.d + s = cls.bytesToGf(s,mustBePositive=True) + + if s==0: return cls() + t = xsqrt(s^4 + 2*(a-2*d)*s^2 + 1) + altx = 2*s*cls.isoMagic/t + if negative(altx): t = -t + x = 2*s / (1+a*s^2) + y = (1-a*s^2) / t + + if cls.cofactor==8 and (negative(x*y*cls.isoMagic) or y==0): + raise InvalidEncodingException("x*y is invalid: %d, %d" % (x,y)) + + return cls(x,y) + + def toJacobiQuartic(self,toggle_rotation=False,toggle_altx=False,toggle_s=False): + "Return s,t on jacobi curve" + a,d = self.a,self.d + x,y,z,t = self.xyzt() + + if self.cofactor == 8: + # Cofactor 8 version + # Simulate IMAGINE_TWIST because that's how libdecaf does it + x = self.i*x + t = self.i*t + a = -a + d = -d + + # OK, the actual libdecaf code should be here + num = (z+y)*(z-y) + den = x*y + isr = isqrt(num*(a-d)*den^2) + + iden = isr * den * self.isoMagic # 1/sqrt((z+y)(z-y)) = 1/sqrt(1-Y^2) / z + inum = isr * num # sqrt(1-Y^2) * z / xysqrt(a-d) ~ 1/sqrt(1-ax^2)/z + + if negative(iden*inum*self.i*t^2*(d-a)) != toggle_rotation: + iden,inum = inum,iden + fac = x*sqrt(a) + toggle=(a==-1) + else: + fac = y + toggle=False + + imi = self.isoMagic * self.i + altx = inum*t*imi + neg_altx = negative(altx) != toggle_altx + if neg_altx != toggle: inum =- inum + + tmp = fac*(inum*z + 1) + s = iden*tmp*imi + + negm1 = (negative(s) != toggle_s) != neg_altx + if negm1: m1 = a*fac + z + else: m1 = a*fac - z + + swap = toggle_s + + else: + # Much simpler cofactor 4 version + num = (x+t)*(x-t) + isr = isqrt(num*(a-d)*x^2) + ratio = isr*num + altx = ratio*self.isoMagic + + neg_altx = negative(altx) != toggle_altx + if neg_altx: ratio =- ratio + + tmp = ratio*z - t + s = (a-d)*isr*x*tmp + + negx = (negative(s) != toggle_s) != neg_altx + if negx: m1 = -a*t + x + else: m1 = -a*t - x + + swap = toggle_s + + if negative(s): s = -s + + return s,m1,a*tmp,swap + + def invertElligator(self,toggle_r=False,*args,**kwargs): + "Produce preimage of self under elligator, or None" + a,d = self.a,self.d + + rets = [] + + tr = [False,True] if self.cofactor == 8 else [False] + for toggle_rotation in tr: + for toggle_altx in [False,True]: + for toggle_s in [False,True]: + for toggle_r in [False,True]: + s,m1,m12,swap = self.toJacobiQuartic(toggle_rotation,toggle_altx,toggle_s) + + #print + #print toggle_rotation,toggle_altx,toggle_s + #print m1 + #print m12 + + + if self == self.__class__(): + if self.cofactor == 4: + # Hacks for identity! + if toggle_altx: m12 = 1 + elif toggle_s: m1 = 1 + elif toggle_r: continue + ## BOTH??? + + else: + m12 = 1 + imi = self.isoMagic * self.i + if toggle_rotation: + if toggle_altx: m1 = -imi + else: m1 = +imi + else: + if toggle_altx: m1 = 0 + else: m1 = a-d + + rnum = (d*a*m12-m1) + rden = ((d*a-1)*m12+m1) + if swap: rnum,rden = rden,rnum + + ok,sr = isqrt_i(rnum*rden*self.qnr) + if not ok: continue + sr *= rnum + #print "Works! %d %x" % (swap,sr) + + if negative(sr) != toggle_r: sr = -sr + ret = self.gfToBytes(sr) + if self.elligator(ret) != self and self.elligator(ret) != -self: + print "WRONG!",[toggle_rotation,toggle_altx,toggle_s] + if self.elligator(ret) == -self and self != -self: print "Negated!",[toggle_rotation,toggle_altx,toggle_s] + rets.append(bytes(ret)) + return rets + + @optimized_version_of("encodeSpec") + def encode(self): + """Encode, optimized version""" + return self.gfToBytes(self.toJacobiQuartic()[0]) + + @classmethod + @optimized_version_of("decodeSpec") + def decode(cls,s): + """Decode, optimized version""" + a,d = cls.a,cls.d + s = cls.bytesToGf(s,mustBePositive=True) + + #if s==0: return cls() + s2 = s^2 + den = 1+a*s2 + num = den^2 - 4*d*s2 + isr = isqrt(num*den^2) + altx = 2*s*isr*den*cls.isoMagic + if negative(altx): isr = -isr + x = 2*s *isr^2*den*num + y = (1-a*s^2) * isr*den + + if cls.cofactor==8 and (negative(x*y*cls.isoMagic) or y==0): + raise InvalidEncodingException("x*y is invalid: %d, %d" % (x,y)) + + return cls(x,y) + + @classmethod + def fromJacobiQuartic(cls,s,t,sgn=1): + """Convert point from its Jacobi Quartic representation""" + a,d = cls.a,cls.d + if s==0: return cls() + x = 2*s / (1+a*s^2) + y = (1-a*s^2) / t + return cls(x,sgn*y) + + @optimized_version_of("doubleAndEncodeSpec") + def doubleAndEncode(self): + X,Y,Z,T = self.xyzt() + a,d = self.a,self.d + + if self.cofactor == 8: + # Cofactor 8 version + # Simulate IMAGINE_TWIST because that's how libdecaf does it + X = self.i*X + T = self.i*T + a = -a + d = -d + # TODO: This is only being called for a=-1, so could + # be wrong for a=1 + + e = 2*X*Y + f = Y^2+a*X^2 + g = Y^2-a*X^2 + h = Z^2-d*T^2 + + eim = e*self.isoMagic + inv = 1/(eim*g*f*h) + fh_inv = eim*g*inv*self.i + + if negative(eim*g*fh_inv): + idf = g*self.isoMagic*self.i + bar = f + foo = g + test = eim*f + else: + idf = eim + bar = h + foo = -eim + test = g*h + + if negative(test*fh_inv): bar =- bar + s = idf*(foo+bar)*inv*f*h + + else: + xy = X*Y + h = Z^2-d*T^2 + inv = 1/(xy*h) + if negative(inv*2*xy^2*self.isoMagic): tmp = Y + else: tmp = X + s = tmp^2*h*inv # = X/Y or Y/X, interestingly + + return self.gfToBytes(s,mustBePositive=True) + + @classmethod + def elligatorSpec(cls,r0,fromR=False): + a,d = cls.a,cls.d + if fromR: r = r0 + else: r = cls.qnr * cls.bytesToGf(r0,mustBeProper=False,maskHiBits=True)^2 + + den = (d*r-(d-a))*((d-a)*r-d) + if den == 0: return cls() + n1 = (r+1)*(a-2*d)/den + n2 = r*n1 + if is_square(n1): + sgn,s,t = 1, xsqrt(n1), -(r-1)*(a-2*d)^2 / den - 1 + else: + sgn,s,t = -1, -xsqrt(n2), r*(r-1)*(a-2*d)^2 / den - 1 + + return cls.fromJacobiQuartic(s,t) + + @classmethod + @optimized_version_of("elligatorSpec") + def elligator(cls,r0): + a,d = cls.a,cls.d + r0 = cls.bytesToGf(r0,mustBeProper=False,maskHiBits=True) + r = cls.qnr * r0^2 + den = (d*r-(d-a))*((d-a)*r-d) + num = (r+1)*(a-2*d) + + iss,isri = isqrt_i(num*den) + if iss: sgn,twiddle = 1,1 + else: sgn,twiddle = -1,r0*cls.qnr + isri *= twiddle + s = isri*num + t = -sgn*isri*s*(r-1)*(a-2*d)^2 - 1 + if negative(s) == iss: s = -s + return cls.fromJacobiQuartic(s,t) + + def elligatorInverseBruteForce(self): + """Invert Elligator using SAGE's polynomial solver""" + a,d = self.a,self.d + R. = self.F[] + r = self.qnr * r0^2 + den = (d*r-(d-a))*((d-a)*r-d) + n1 = (r+1)*(a-2*d)/den + n2 = r*n1 + ret = set() + for s2,t in [(n1, -(r-1)*(a-2*d)^2 / den - 1), + (n2,r*(r-1)*(a-2*d)^2 / den - 1)]: + x2 = 4*s2/(1+a*s2)^2 + y = (1-a*s2) / t + + selfT = self + for i in xrange(self.cofactor/2): + xT,yT = selfT + polyX = xT^2-x2 + polyY = yT-y + sx = set(r for r,_ in polyX.numerator().roots()) + sy = set(r for r,_ in polyY.numerator().roots()) + ret = ret.union(sx.intersection(sy)) + + selfT = selfT.torque() + + ret = [self.gfToBytes(r) for r in ret] + + for r in ret: + assert self.elligator(r) in [self,-self] + + ret = [r for r in ret if self.elligator(r) == self] + + return ret + +class Ed25519Point(RistrettoPoint): + F = GF(2^255-19) + d = F(-121665/121666) + a = F(-1) + i = sqrt(F(-1)) + mneg = F(1) + qnr = i + magic = isqrt(a*d-1) + cofactor = 8 + encLen = 32 + + @classmethod + def base(cls): + return cls( 15112221349535400772501151409588531511454012693041857206046113283949847762202, 46316835694926478169428394003475163141307993866256225615783033603165251855960 + ) + +class NegEd25519Point(RistrettoPoint): + F = GF(2^255-19) + d = F(121665/121666) + a = F(1) + i = sqrt(F(-1)) + mneg = F(-1) # TODO checkme vs 1-ad or whatever + qnr = i + magic = isqrt(a*d-1) + cofactor = 8 + encLen = 32 + + @classmethod + def base(cls): + y = cls.F(4/5) + x = sqrt((y^2-1)/(cls.d*y^2-cls.a)) + if negative(x): x = -x + return cls(x,y) + +class IsoEd448Point(RistrettoPoint): + F = GF(2^448-2^224-1) + d = F(39082/39081) + a = F(1) + mneg = F(-1) + qnr = -1 + magic = isqrt(a*d-1) + cofactor = 4 + encLen = 56 + + @classmethod + def base(cls): + return cls( # RFC has it wrong + 345397493039729516374008604150537410266655260075183290216406970281645695073672344430481787759340633221708391583424041788924124567700732, + -363419362147803445274661903944002267176820680343659030140745099590306164083365386343198191849338272965044442230921818680526749009182718 + ) + +class TwistedEd448GoldilocksPoint(Decaf_1_1_Point): + F = GF(2^448-2^224-1) + d = F(-39082) + a = F(-1) + qnr = -1 + cofactor = 4 + encLen = 56 + isoMagic = IsoEd448Point.magic + + @classmethod + def base(cls): + return cls.decodeSpec(Ed448GoldilocksPoint.base().encodeSpec()) + +class Ed448GoldilocksPoint(Decaf_1_1_Point): + F = GF(2^448-2^224-1) + d = F(-39081) + a = F(1) + qnr = -1 + cofactor = 4 + encLen = 56 + isoMagic = IsoEd448Point.magic + + @classmethod + def base(cls): + return 2*cls( + 224580040295924300187604334099896036246789641632564134246125461686950415467406032909029192869357953282578032075146446173674602635247710, 298819210078481492676017930443930673437544040154080242095928241372331506189835876003536878655418784733982303233503462500531545062832660 + ) + +class IsoEd25519Point(Decaf_1_1_Point): + # TODO: twisted iso too! + # TODO: twisted iso might have to IMAGINE_TWIST or whatever + F = GF(2^255-19) + d = F(-121665) + a = F(1) + i = sqrt(F(-1)) + qnr = i + magic = isqrt(a*d-1) + cofactor = 8 + encLen = 32 + isoMagic = Ed25519Point.magic + isoA = Ed25519Point.a + + @classmethod + def base(cls): + return cls.decodeSpec(Ed25519Point.base().encode()) + +class TestFailedException(Exception): pass + +def test(cls,n): + print "Testing curve %s" % cls.__name__ + + specials = [1] + ii = cls.F(-1) + while is_square(ii): + specials.append(ii) + ii = sqrt(ii) + specials.append(ii) + for i in specials: + if negative(cls.F(i)): i = -i + i = enc_le(i,cls.encLen) + try: + Q = cls.decode(i) + QE = Q.encode() + if QE != i: + raise TestFailedException("Round trip special %s != %s" % + (binascii.hexlify(QE),binascii.hexlify(i))) + except NotOnCurveException: pass + except InvalidEncodingException: pass + + + P = cls.base() + Q = cls() + for i in xrange(n): + #print binascii.hexlify(Q.encode()) + QE = Q.encode() + QQ = cls.decode(QE) + if QQ != Q: raise TestFailedException("Round trip %s != %s" % (str(QQ),str(Q))) + + # Testing s -> 1/s: encodes -point on cofactor + s = cls.bytesToGf(QE) + if s != 0: + ss = cls.gfToBytes(1/s,mustBePositive=True) + try: + QN = cls.decode(ss) + if cls.cofactor == 8: + raise TestFailedException("1/s shouldnt work for cofactor 8") + if QN != -Q: + raise TestFailedException("s -> 1/s should negate point for cofactor 4") + except InvalidEncodingException as e: + # Should be raised iff cofactor==8 + if cls.cofactor == 4: + raise TestFailedException("s -> 1/s should work for cofactor 4") + + QT = Q + for h in xrange(cls.cofactor): + QT = QT.torque() + if QT.encode() != QE: + raise TestFailedException("Can't torque %s,%d" % (str(Q),h+1)) + + Q0 = Q + P + if Q0 == Q: raise TestFailedException("Addition doesn't work") + if Q0-P != Q: raise TestFailedException("Subtraction doesn't work") + + r = randint(1,1000) + Q1 = Q0*r + Q2 = Q0*(r+1) + if Q1 + Q0 != Q2: raise TestFailedException("Scalarmul doesn't work") + Q = Q1 + +def testElligator(cls,n): + print "Testing elligator on %s" % cls.__name__ + for i in xrange(n): + r = randombytes(cls.encLen) + P = cls.elligator(r) + if hasattr(P,"invertElligator"): + iv = P.invertElligator() + modr = bytes(cls.gfToBytes(cls.bytesToGf(r,mustBeProper=False,maskHiBits=True))) + iv2 = P.torque().invertElligator() + if modr not in iv: print "Failed to invert Elligator!" + if len(iv) != len(set(iv)): + print "Elligator inverses not unique!", len(set(iv)), len(iv) + if iv != iv2: + print "Elligator is untorqueable!" + #print [binascii.hexlify(j) for j in iv] + #print [binascii.hexlify(j) for j in iv2] + #break + else: + pass # TODO + +def gangtest(classes,n): + print "Gang test",[cls.__name__ for cls in classes] + specials = [1] + ii = classes[0].F(-1) + while is_square(ii): + specials.append(ii) + ii = sqrt(ii) + specials.append(ii) + + for i in xrange(n): + rets = [bytes((cls.base()*i).encode()) for cls in classes] + if len(set(rets)) != 1: + print "Divergence in encode at %d" % i + for c,ret in zip(classes,rets): + print c,binascii.hexlify(ret) + print + + if i < len(specials): r0 = enc_le(specials[i],classes[0].encLen) + else: r0 = randombytes(classes[0].encLen) + + rets = [bytes((cls.elligator(r0)*i).encode()) for cls in classes] + if len(set(rets)) != 1: + print "Divergence in elligator at %d" % i + for c,ret in zip(classes,rets): + print c,binascii.hexlify(ret) + print + +def testDoubleAndEncode(cls,n): + print "Testing doubleAndEncode on %s" % cls.__name__ + for i in xrange(n): + r1 = randombytes(cls.encLen) + r2 = randombytes(cls.encLen) + u = cls.elligator(r1) + cls.elligator(r2) + u.doubleAndEncode() + +testDoubleAndEncode(Ed25519Point,100) +testDoubleAndEncode(NegEd25519Point,100) +testDoubleAndEncode(IsoEd25519Point,100) +testDoubleAndEncode(IsoEd448Point,100) +testDoubleAndEncode(TwistedEd448GoldilocksPoint,100) +#test(Ed25519Point,100) +#test(NegEd25519Point,100) +#test(IsoEd25519Point,100) +#test(IsoEd448Point,100) +#test(TwistedEd448GoldilocksPoint,100) +#test(Ed448GoldilocksPoint,100) +#testElligator(Ed25519Point,100) +#testElligator(NegEd25519Point,100) +#testElligator(IsoEd25519Point,100) +#testElligator(IsoEd448Point,100) +#testElligator(Ed448GoldilocksPoint,100) +#testElligator(TwistedEd448GoldilocksPoint,100) +#gangtest([IsoEd448Point,TwistedEd448GoldilocksPoint,Ed448GoldilocksPoint],100) +#gangtest([Ed25519Point,IsoEd25519Point],100) diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/.cargo-checksum.json b/net/gurk-rs/files/vendor/libsignal-protocol/.cargo-checksum.json new file mode 100644 index 0000000..ab9a8ee --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"9978ce7662c8c17ce4a131ac3bbfa450fd339ba39579d47e992941a4b21c006f","benches/ratchet.rs":"5102fcc1e43bf1b7d90d6f890e010e6f4056b826eac8a90235442928b32b85ff","benches/sealed_sender.rs":"8e581630a315dcd6e087dbcb441ece518d22e491de8f6038ce3a85280efc7b5c","benches/session.rs":"fa03d4dad7983273dd755f3d8cbe70853b1504aeabbef4c9cde663f65e63cb8d","build.rs":"ce3c7b66ef94f0c91803a8ec80a76f94f4d6223f3f11738e1ee10ad87983baf3","src/address.rs":"4bc5d361fe73ceeee76659cd778bea9d2de38115fc1177485e3bdabc13a7bcf3","src/consts.rs":"8630aa9486f8e65648cdd254359a070b79d0e3ab363699c241958f2f615b0ff2","src/crypto.rs":"a76e41c4f7ef07f914131f3420b5bd0addd656c5a1bea8227597c0a1ef1ba0e6","src/curve.rs":"d5bd475be83bca69a29695b2c5ebf275fe81ba9b096ad9671f795d0d3dab28e2","src/curve/curve25519.rs":"3e48c615c89ef03a2ff97a40844b81a17b29c95781e127ccd98c6b45b4109662","src/error.rs":"7cca985e8c8f225b59aef7ee4d4de967db1b843771e0763d8982559de66f339b","src/fingerprint.rs":"4d5eb04283113997c03fca3adf61236b081a5ba6ec03aaa62c7118eb12dce041","src/group_cipher.rs":"cadd9ac026bdb87cd6c5e15f97556962e47673b467d622d7de5583ec7893dfa9","src/identity_key.rs":"0876f1e8b7022632a7d125615a57d128cb2cc95cb460127fe0dbc9ee673410ea","src/lib.rs":"145d9f7ad1c4f400f37a6413ba5c09f2d74a4633b4e3181644470144821010a8","src/proto.rs":"9f0456ffff28f14f0e3fac51825d916abb785f8cf45a29b867aa17ae20a3f084","src/proto/fingerprint.proto":"ff64ad6d93f27ed525f9405d23d5e230d72697a762408fa83b04bae84e85125e","src/proto/fingerprint.rs":"091f5ec64ca5b9d143c5bf838130fadb6a5eed8b0ac9e551d318d677699e0d99","src/proto/sealed_sender.proto":"058d6aefd554ed30f96d142b5585ae375c09dd151c5b6c878e1af4152e49f433","src/proto/sealed_sender.rs":"c28a74bf813808ba92d3fb7029069b8f515bb302591680f821de2a649ffcc838","src/proto/service.proto":"38a9f6d53ccadc872d0c47a1bb973a8a741e55959c5b6b7d1aec7f4b8d082250","src/proto/service.rs":"d05ba074d94d4cbe6f90109dc9a9856a9ea744b51e7720c52f77381cecf08443","src/proto/storage.proto":"4113b802bc10bded1119b1a2f4c5e7cd96ac08c3c5838f7a3c47d0dcf0b6d87a","src/proto/storage.rs":"be1cc45e44ec2ed7c3a11d9e6d32e3c333035aec32cf5b5ccf2d3da8010af4a0","src/proto/wire.proto":"dd7df265ae21e79d020764e137e88df7b76661f148e1e504dacc9a63fa411fb4","src/proto/wire.rs":"e16a9fb626d2aebf81cec15bf1e9f7a7d06a72f95d3d7f948fef179fd03f501d","src/protocol.rs":"66a1518455ad01f01286a4388595042b433e1a54c7d2ef5737e2f0d8263f9d44","src/ratchet.rs":"28a141ad8359de514a1b75c74131fcf659bab0a2efc0dbcf650d33250420f171","src/ratchet/keys.rs":"943416a4bf5d2e49813956b6234b51a1765488e415c772ec135ab9a7004a6e38","src/ratchet/params.rs":"5781aaa006e825e7596ca03cb69f1502dd6d2a749b65fec45d4bac5161ecb74e","src/sealed_sender.rs":"a16852ed7921b9a901418b1640eecdf1c82c15afc621501d5af6513ef989b4c8","src/sender_keys.rs":"ceb9fbd148fb6b129cbb69201c5a97a270dde84c111f97fa2b7a39aa71d39e0c","src/session.rs":"9c2d96f43b205ff1122f523b45285233ba8749f64dbe7424f070326a8e290afe","src/session_cipher.rs":"3f60353791a62621b1de70cbd121328a9fb3c7731f4fec2aa356d97633f58c00","src/state.rs":"52ced20ecd6a50e22a30b2c062ebd669db8aa2f45477e414ba841b626c40641c","src/state/bundle.rs":"d006e77e472cc12e2ea93ae2c37e07658a3d90ddeecced7296985f6a3660d8d3","src/state/prekey.rs":"1827a7ab2390991ea7a388b4714405c682427a25be088c4d9c9d0529e718d2f9","src/state/session.rs":"1d0e4b92c90a1c9f09cee7f2b3ef067e2d11fd5085d78b63d453317536edb07f","src/state/signed_prekey.rs":"0286606af9ba7629822482df2257d00eb0ab6a64462ce8342366e58b67b91343","src/storage.rs":"51bd8090c29a4bcc293a645542f3ee11922cfaf030e2b933c24e0b81aed7f0b9","src/storage/inmem.rs":"3b788ce43e7243f0c978f97064beb3b89a790f07abbbf945ab0d2c0b3ec9e041","src/storage/traits.rs":"41e24813c16c6e2a09e1da7308981d4b47c6a891f123fba7eec37dd4af5886ac","src/utils.rs":"a6a17011a534f5bf8e81d69033fa4062d6b8d6368173627c46d6df8ab43c4fd2","tests/groups.rs":"664f5cb58947aee75bbc25e904b45ff9970d91c7ea21496077683d597603ce8d","tests/ratchet.rs":"ae54a030822b64c2909470037b54e0f291b3152d50e494f8da51f0987472e5da","tests/sealed_sender.rs":"261e16e5781c018622c63b0cc2c7d6ba47d05d582ff3b34fbed643ae2c2d62ce","tests/session.rs":"f2f66ba8fa51c9f650cb273354ff8f9f0af38e079298be4aff929c2f9eaf22c7","tests/support/mod.rs":"fdc47dd560ef95a58bcf76e4b385d459d997a25b6790a483de07349dc99b4617"},"package":null} \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/Cargo.toml b/net/gurk-rs/files/vendor/libsignal-protocol/Cargo.toml new file mode 100644 index 0000000..e3d66d0 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/Cargo.toml @@ -0,0 +1,56 @@ +# +# Copyright (C) 2020-2021 Signal Messenger, LLC. +# SPDX-License-Identifier: AGPL-3.0-only +# + +[package] +name = "libsignal-protocol" +version = "0.1.0" +authors = ["Ehren Kret ", "Jack Lloyd "] +edition = "2018" +license = "AGPL-3.0-only" +repository = "https://github.com/signalapp/libsignal-client" + +[dependencies] +aes = { version = "0.7.4", features = ["ctr"] } +aes-gcm-siv = "0.10.1" +arrayref = "0.3.6" +async-trait = "0.1.41" +block-modes = "0.8" +curve25519-dalek = { version = "3.0", features = ["serde"] } +hkdf = "0.11" +hmac = "0.11.0" +itertools = "0.10.1" +prost = "0.8" +rand = "0.7.3" +sha2 = "0.9" +subtle = "2.2.3" +x25519-dalek = "1.0" +hex = "0.4" +log = "0.4" +num_enum = "0.5.1" +uuid = "0.8" +displaydoc = "0.2" +thiserror = "1.0.30" + +[features] +armv8 = ["aes/armv8", "aes-gcm-siv/armv8"] + +[dev-dependencies] +criterion = "0.3" +futures-util = "0.3.7" + +[build-dependencies] +prost-build = "0.8" + +[[bench]] +name = "session" +harness = false + +[[bench]] +name = "ratchet" +harness = false + +[[bench]] +name = "sealed_sender" +harness = false diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/benches/ratchet.rs b/net/gurk-rs/files/vendor/libsignal-protocol/benches/ratchet.rs new file mode 100644 index 0000000..047c23f --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/benches/ratchet.rs @@ -0,0 +1,103 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use criterion::{criterion_group, criterion_main, Criterion, SamplingMode}; +use futures_util::FutureExt; +use libsignal_protocol::*; +use std::convert::TryFrom; +use uuid::Uuid; + +#[path = "../tests/support/mod.rs"] +mod support; + +pub fn ratchet_forward_result(c: &mut Criterion) -> Result<(), SignalProtocolError> { + let mut group = c.benchmark_group("ratchet"); + group.sampling_mode(SamplingMode::Flat); + group.sample_size(10); //minimum allowed... + group.warm_up_time(core::time::Duration::from_millis(100)); + + let mut csprng = rand::rngs::OsRng; + + let sender_address = ProtocolAddress::new("+14159999111".to_owned(), 1); + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let sent_distribution_message = create_sender_key_distribution_message( + &sender_address, + distribution_id, + &mut alice_store, + &mut csprng, + None, + ) + .now_or_never() + .expect("sync")?; + + let recv_distribution_message = + SenderKeyDistributionMessage::try_from(sent_distribution_message.serialized())?; + + process_sender_key_distribution_message( + &sender_address, + &recv_distribution_message, + &mut bob_store, + None, + ) + .now_or_never() + .expect("sync")?; + + for ratchets in [100, 1000].iter() { + let ratchets = *ratchets; + + for i in 0..ratchets { + group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + format!("nefarious plotting {}", i).as_bytes(), + &mut csprng, + None, + ) + .now_or_never() + .expect("sync")?; + } + + let alice_ciphertext = group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + "you got the plan?".as_bytes(), + &mut csprng, + None, + ) + .now_or_never() + .expect("sync")?; + + group.bench_function(format!("ratchet {}", ratchets), |b| { + b.iter(|| { + let mut bob_store = bob_store.clone(); + group_decrypt( + alice_ciphertext.serialized(), + &mut bob_store, + &sender_address, + None, + ) + .now_or_never() + .expect("sync") + .expect("ok"); + }) + }); + } + + Ok(()) +} + +pub fn ratchet_forward(mut c: &mut Criterion) { + ratchet_forward_result(&mut c).expect("success"); +} + +criterion_group!(ratchet, ratchet_forward); + +criterion_main!(ratchet); diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/benches/sealed_sender.rs b/net/gurk-rs/files/vendor/libsignal-protocol/benches/sealed_sender.rs new file mode 100644 index 0000000..f548c6e --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/benches/sealed_sender.rs @@ -0,0 +1,287 @@ +// +// Copyright 2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use futures_util::FutureExt; +use libsignal_protocol::*; +use rand::rngs::OsRng; +use rand::Rng; +use uuid::Uuid; + +#[path = "../tests/support/mod.rs"] +mod support; + +pub fn v1(c: &mut Criterion) { + let mut rng = OsRng; + + let alice_address = ProtocolAddress::new("9d0652a3-dcc3-4d11-975f-74d61598733f".to_owned(), 1); + let bob_address = ProtocolAddress::new("796abedb-ca4e-4f18-8803-1fde5b921f9f".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store().expect("brand new store"); + let mut bob_store = support::test_in_memory_protocol_store().expect("brand new store"); + + let bob_pre_key_bundle = support::create_pre_key_bundle(&mut bob_store, &mut rng) + .now_or_never() + .expect("sync") + .expect("valid"); + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut rng, + None, + ) + .now_or_never() + .expect("sync") + .expect("valid"); + + let trust_root = KeyPair::generate(&mut rng); + let server_key = KeyPair::generate(&mut rng); + + let server_cert = + ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng) + .expect("valid"); + + let expires = 1605722925; + + let sender_cert = SenderCertificate::new( + alice_address.name().to_string(), + None, + *alice_store + .get_identity_key_pair(None) + .now_or_never() + .expect("sync") + .expect("valid") + .public_key(), + alice_address.device_id(), + expires, + server_cert, + &server_key.private_key, + &mut rng, + ) + .expect("valid"); + + let message = b"hello"; + let usmc = UnidentifiedSenderMessageContent::new( + CiphertextMessageType::Plaintext, + sender_cert, + message.to_vec(), + ContentHint::Default, + None, + ) + .expect("valid"); + + let mut encrypt_it = || { + sealed_sender_encrypt_from_usmc( + &bob_address, + &usmc, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .now_or_never() + .expect("sync") + .expect("valid") + }; + let encrypted = encrypt_it(); + + let mut decrypt_it = || { + sealed_sender_decrypt_to_usmc(&encrypted, &mut bob_store.identity_store, None) + .now_or_never() + .expect("sync") + .expect("valid") + }; + assert_eq!(message, decrypt_it().contents().expect("valid")); + + c.bench_function("v1/encrypt", |b| b.iter(&mut encrypt_it)); + c.bench_function("v1/decrypt", |b| b.iter(&mut decrypt_it)); +} + +pub fn v2(c: &mut Criterion) { + let mut rng = OsRng; + + let alice_address = ProtocolAddress::new("9d0652a3-dcc3-4d11-975f-74d61598733f".to_owned(), 1); + let bob_address = ProtocolAddress::new("796abedb-ca4e-4f18-8803-1fde5b921f9f".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store().expect("brand new store"); + let mut bob_store = support::test_in_memory_protocol_store().expect("brand new store"); + + let bob_pre_key_bundle = support::create_pre_key_bundle(&mut bob_store, &mut rng) + .now_or_never() + .expect("sync") + .expect("valid"); + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut rng, + None, + ) + .now_or_never() + .expect("sync") + .expect("valid"); + + let trust_root = KeyPair::generate(&mut rng); + let server_key = KeyPair::generate(&mut rng); + + let server_cert = + ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng) + .expect("valid"); + + let expires = 1605722925; + + let sender_cert = SenderCertificate::new( + alice_address.name().to_string(), + None, + *alice_store + .get_identity_key_pair(None) + .now_or_never() + .expect("sync") + .expect("valid") + .public_key(), + alice_address.device_id(), + expires, + server_cert, + &server_key.private_key, + &mut rng, + ) + .expect("valid"); + + let message = b"hello"; + let usmc = UnidentifiedSenderMessageContent::new( + CiphertextMessageType::Plaintext, + sender_cert, + message.to_vec(), + ContentHint::Default, + None, + ) + .expect("valid"); + + let mut encrypt_it = || { + sealed_sender_multi_recipient_encrypt( + &[&bob_address], + &alice_store + .session_store + .load_existing_sessions(&[&bob_address]) + .expect("present"), + &usmc, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .now_or_never() + .expect("sync") + .expect("valid") + }; + let outgoing = encrypt_it(); + + let incoming = sealed_sender_multi_recipient_fan_out(&outgoing) + .expect("valid") + .into_iter() + .next() + .expect("at least one destination"); + + let mut decrypt_it = || { + sealed_sender_decrypt_to_usmc(&incoming, &mut bob_store.identity_store, None) + .now_or_never() + .expect("sync") + .expect("valid") + }; + assert_eq!(message, decrypt_it().contents().expect("valid")); + + c.bench_function("v2/encrypt", |b| b.iter(&mut encrypt_it)); + c.bench_function("v2/decrypt", |b| b.iter(&mut decrypt_it)); + + // Fill out additional recipients. + let mut recipients = vec![bob_address.clone()]; + while recipients.len() < 10 { + let next_address = ProtocolAddress::new(Uuid::from_bytes(rng.gen()).to_string(), 1); + + let mut next_store = support::test_in_memory_protocol_store().expect("brand new store"); + + let next_pre_key_bundle = support::create_pre_key_bundle(&mut next_store, &mut rng) + .now_or_never() + .expect("sync") + .expect("valid"); + + process_prekey_bundle( + &next_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &next_pre_key_bundle, + &mut rng, + None, + ) + .now_or_never() + .expect("sync") + .expect("valid"); + + recipients.push(next_address); + } + + let mut group = c.benchmark_group("v2/encrypt/multi-recipient"); + for recipient_count in [2, 5, 10] { + group.bench_with_input( + BenchmarkId::from_parameter(recipient_count), + &recipient_count, + |b, &recipient_count| { + let recipients: Vec<_> = recipients.iter().take(recipient_count).collect(); + b.iter(|| { + sealed_sender_multi_recipient_encrypt( + &recipients, + &alice_store + .session_store + .load_existing_sessions(&recipients) + .expect("present"), + &usmc, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .now_or_never() + .expect("sync") + .expect("valid") + }); + }, + ); + } + group.finish(); + + let mut group = c.benchmark_group("v2/encrypt/multi-device"); + for device_count in [2, 5, 10] { + group.bench_with_input( + BenchmarkId::from_parameter(device_count), + &device_count, + |b, &device_count| { + let recipients: Vec<_> = vec![&bob_address; device_count]; + b.iter(|| { + sealed_sender_multi_recipient_encrypt( + &recipients, + &alice_store + .session_store + .load_existing_sessions(&recipients) + .expect("present"), + &usmc, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .now_or_never() + .expect("sync") + .expect("valid") + }); + }, + ); + } + group.finish(); +} + +criterion_group!(benches, v1, v2); + +criterion_main!(benches); diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/benches/session.rs b/net/gurk-rs/files/vendor/libsignal-protocol/benches/session.rs new file mode 100644 index 0000000..f5f8c35 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/benches/session.rs @@ -0,0 +1,249 @@ +// +// Copyright 2020-2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use criterion::{criterion_group, criterion_main, Criterion}; +use futures_util::FutureExt; +use libsignal_protocol::*; +use rand::rngs::OsRng; + +#[path = "../tests/support/mod.rs"] +mod support; + +pub fn session_encrypt_result(c: &mut Criterion) -> Result<(), SignalProtocolError> { + let (alice_session_record, bob_session_record) = support::initialize_sessions_v3()?; + + let alice_address = ProtocolAddress::new("+14159999999".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14158888888".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + alice_store + .store_session(&bob_address, &alice_session_record, None) + .now_or_never() + .expect("sync")?; + bob_store + .store_session(&alice_address, &bob_session_record, None) + .now_or_never() + .expect("sync")?; + + let message_to_decrypt = support::encrypt(&mut alice_store, &bob_address, "a short message") + .now_or_never() + .expect("sync")?; + + c.bench_function("session decrypt first message", |b| { + b.iter(|| { + let mut bob_store = bob_store.clone(); + support::decrypt(&mut bob_store, &alice_address, &message_to_decrypt) + .now_or_never() + .expect("sync") + .expect("success"); + }) + }); + + let _ = support::decrypt(&mut bob_store, &alice_address, &message_to_decrypt) + .now_or_never() + .expect("sync")?; + let message_to_decrypt = support::encrypt(&mut alice_store, &bob_address, "a short message") + .now_or_never() + .expect("sync")?; + + c.bench_function("session encrypt", |b| { + b.iter(|| { + support::encrypt(&mut alice_store, &bob_address, "a short message") + .now_or_never() + .expect("sync") + .expect("success"); + }) + }); + c.bench_function("session decrypt", |b| { + b.iter(|| { + let mut bob_store = bob_store.clone(); + support::decrypt(&mut bob_store, &alice_address, &message_to_decrypt) + .now_or_never() + .expect("sync") + .expect("success"); + }) + }); + + // Archive on Alice's side... + let mut state = alice_store + .load_session(&bob_address, None) + .now_or_never() + .expect("sync")? + .expect("already decrypted successfully"); + state.archive_current_state()?; + alice_store + .store_session(&bob_address, &state, None) + .now_or_never() + .expect("sync")?; + + // ...then initialize a new session... + let bob_signed_pre_key_pair = KeyPair::generate(&mut OsRng); + + let bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key.serialize(); + let bob_signed_pre_key_signature = bob_store + .get_identity_key_pair(None) + .now_or_never() + .expect("sync")? + .private_key() + .calculate_signature(&bob_signed_pre_key_public, &mut OsRng)?; + + let signed_pre_key_id = 22; + + let bob_pre_key_bundle = PreKeyBundle::new( + bob_store + .get_local_registration_id(None) + .now_or_never() + .expect("sync")?, + 1, // device id + None, // pre key + signed_pre_key_id, // signed pre key id + bob_signed_pre_key_pair.public_key, + bob_signed_pre_key_signature.to_vec(), + *bob_store + .get_identity_key_pair(None) + .now_or_never() + .expect("sync")? + .identity_key(), + )?; + + bob_store + .save_signed_pre_key( + signed_pre_key_id, + &SignedPreKeyRecord::new( + signed_pre_key_id, + /*timestamp*/ 42, + &bob_signed_pre_key_pair, + &bob_signed_pre_key_signature, + ), + None, + ) + .now_or_never() + .expect("sync")?; + + // initialize_sessions_v3 makes up its own identity keys, + // so we need to reset here to avoid it looking like the identity changed. + alice_store.identity_store.reset(); + bob_store.identity_store.reset(); + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut OsRng, + None, + ) + .now_or_never() + .expect("sync")?; + + let original_message_to_decrypt = message_to_decrypt; + + // ...send another message to archive on Bob's side... + let message_to_decrypt = support::encrypt(&mut alice_store, &bob_address, "a short message") + .now_or_never() + .expect("sync")?; + let _ = support::decrypt(&mut bob_store, &alice_address, &message_to_decrypt) + .now_or_never() + .expect("sync")?; + // ...and prepare another message to benchmark decrypting. + let message_to_decrypt = support::encrypt(&mut alice_store, &bob_address, "a short message") + .now_or_never() + .expect("sync")?; + + c.bench_function("session decrypt with archived state", |b| { + b.iter(|| { + let mut bob_store = bob_store.clone(); + support::decrypt(&mut bob_store, &alice_address, &message_to_decrypt) + .now_or_never() + .expect("sync") + .expect("success"); + }) + }); + + // Reset once more to go back to the original message. + bob_store.identity_store.reset(); + + c.bench_function("session decrypt using previous state", |b| { + b.iter(|| { + let mut bob_store = bob_store.clone(); + support::decrypt(&mut bob_store, &alice_address, &original_message_to_decrypt) + .now_or_never() + .expect("sync") + .expect("success"); + }) + }); + + Ok(()) +} + +pub fn session_encrypt_decrypt_result(c: &mut Criterion) -> Result<(), SignalProtocolError> { + let (alice_session_record, bob_session_record) = support::initialize_sessions_v3()?; + + let alice_address = ProtocolAddress::new("+14159999999".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14158888888".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + alice_store + .store_session(&bob_address, &alice_session_record, None) + .now_or_never() + .expect("sync")?; + bob_store + .store_session(&alice_address, &bob_session_record, None) + .now_or_never() + .expect("sync")?; + + c.bench_function("session encrypt+decrypt 1 way", |b| { + b.iter(|| { + let ctext = support::encrypt(&mut alice_store, &bob_address, "a short message") + .now_or_never() + .expect("sync") + .expect("success"); + let _ptext = support::decrypt(&mut bob_store, &alice_address, &ctext) + .now_or_never() + .expect("sync") + .expect("success"); + }) + }); + + c.bench_function("session encrypt+decrypt ping pong", |b| { + b.iter(|| { + let ctext = support::encrypt(&mut alice_store, &bob_address, "a short message") + .now_or_never() + .expect("sync") + .expect("success"); + let _ptext = support::decrypt(&mut bob_store, &alice_address, &ctext) + .now_or_never() + .expect("sync") + .expect("success"); + + let ctext = support::encrypt(&mut bob_store, &alice_address, "a short message") + .now_or_never() + .expect("sync") + .expect("success"); + let _ptext = support::decrypt(&mut alice_store, &bob_address, &ctext) + .now_or_never() + .expect("sync") + .expect("success"); + }) + }); + + Ok(()) +} + +pub fn session_encrypt(mut c: &mut Criterion) { + session_encrypt_result(&mut c).expect("success"); +} + +pub fn session_encrypt_decrypt(mut c: &mut Criterion) { + session_encrypt_decrypt_result(&mut c).expect("success"); +} + +criterion_group!(benches, session_encrypt, session_encrypt_decrypt); + +criterion_main!(benches); diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/build.rs b/net/gurk-rs/files/vendor/libsignal-protocol/build.rs new file mode 100644 index 0000000..8fc1b49 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/build.rs @@ -0,0 +1,18 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +fn main() { + let protos = [ + "src/proto/fingerprint.proto", + "src/proto/sealed_sender.proto", + "src/proto/service.proto", + "src/proto/storage.proto", + "src/proto/wire.proto", + ]; + prost_build::compile_protos(&protos, &["src"]).expect("Protobufs in src are valid"); + for proto in &protos { + println!("cargo:rerun-if-changed={}", proto); + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/address.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/address.rs new file mode 100644 index 0000000..18aa59f --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/address.rs @@ -0,0 +1,73 @@ +// +// Copyright 2020-2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +#![warn(missing_docs)] + +//! A normalized representation of an individual Signal client instance. + +#[cfg(doc)] +use crate::SignalMessage; + +use std::fmt; + +/// The type used in memory to represent a *device*, i.e. a particular Signal client instance which +/// represents some user. +/// +/// Used in [ProtocolAddress]. +pub type DeviceId = u32; + +/// Represents a unique Signal client instance as `(, )` pair. +#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] +pub struct ProtocolAddress { + name: String, + device_id: DeviceId, +} + +impl ProtocolAddress { + /// Create a new address. + /// + /// - `name` defines a user's public identity, and therefore must be globally unique to that + /// user. + /// - Each Signal client instance then has its own `device_id`, which must be unique among + /// all clients for that user. + /// + ///``` + /// use libsignal_protocol::{DeviceId, ProtocolAddress}; + /// + /// // This is a unique id for some user, typically a UUID. + /// let user_id: String = "04899A85-4C9E-44CC-8428-A02AB69335F1".to_string(); + /// // Each client instance representing that user has a unique device id. + /// let device_id: DeviceId = 2_u32.into(); + /// let address = ProtocolAddress::new(user_id.clone(), device_id); + /// + /// assert!(address.name() == &user_id); + /// assert!(address.device_id() == device_id); + ///``` + pub fn new(name: String, device_id: DeviceId) -> Self { + ProtocolAddress { name, device_id } + } + + /// A unique identifier for the target user. This is usually a UUID. + #[inline] + pub fn name(&self) -> &str { + &self.name + } + + /// An identifier representing a particular Signal client instance to send to. + /// + /// For example, if a user has set up Signal on both their phone and laptop, any [SignalMessage] + /// sent to the user will still only go to a single device. So when a user sends a message to + /// another user at all, they're actually sending a message to *every* device. + #[inline] + pub fn device_id(&self) -> DeviceId { + self.device_id + } +} + +impl fmt::Display for ProtocolAddress { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}.{}", self.name, self.device_id) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/consts.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/consts.rs new file mode 100644 index 0000000..6b0b4db --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/consts.rs @@ -0,0 +1,10 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +pub const MAX_FORWARD_JUMPS: usize = 25_000; +pub const MAX_MESSAGE_KEYS: usize = 2000; +pub const MAX_RECEIVER_CHAINS: usize = 5; +pub const ARCHIVED_STATES_MAX_LENGTH: usize = 40; +pub const MAX_SENDER_KEY_STATES: usize = 5; diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/crypto.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/crypto.rs new file mode 100644 index 0000000..5fb8071 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/crypto.rs @@ -0,0 +1,147 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::{error::Result, SignalProtocolError}; + +use aes::cipher::{NewCipher, StreamCipher}; +use aes::{Aes256, Aes256Ctr}; +use block_modes::block_padding::Pkcs7; +use block_modes::{BlockMode, Cbc}; +use hmac::{Hmac, Mac, NewMac}; +use sha2::Sha256; +use subtle::ConstantTimeEq; + +pub fn aes_256_ctr_encrypt(ptext: &[u8], key: &[u8]) -> Result> { + if key.len() != 32 { + return Err(SignalProtocolError::InvalidCipherCryptographicParameters( + 32, 0, + )); + } + + let zero_nonce = [0u8; 16]; + let mut cipher = Aes256Ctr::new(key.into(), (&zero_nonce).into()); + + let mut ctext = ptext.to_vec(); + cipher.apply_keystream(&mut ctext); + Ok(ctext) +} + +pub fn aes_256_ctr_decrypt(ctext: &[u8], key: &[u8]) -> Result> { + aes_256_ctr_encrypt(ctext, key) +} + +pub fn aes_256_cbc_encrypt(ptext: &[u8], key: &[u8], iv: &[u8]) -> Result> { + match Cbc::::new_from_slices(key, iv) { + Ok(mode) => Ok(mode.encrypt_vec(ptext)), + Err(block_modes::InvalidKeyIvLength) => Err( + SignalProtocolError::InvalidCipherCryptographicParameters(key.len(), iv.len()), + ), + } +} + +pub fn aes_256_cbc_decrypt(ctext: &[u8], key: &[u8], iv: &[u8]) -> Result> { + if ctext.is_empty() || ctext.len() % 16 != 0 { + return Err(SignalProtocolError::InvalidCiphertext); + } + + let mode = match Cbc::::new_from_slices(key, iv) { + Ok(mode) => mode, + Err(block_modes::InvalidKeyIvLength) => { + return Err(SignalProtocolError::InvalidCipherCryptographicParameters( + key.len(), + iv.len(), + )) + } + }; + + mode.decrypt_vec(ctext) + .map_err(|_| SignalProtocolError::InvalidCiphertext) +} + +pub fn hmac_sha256(key: &[u8], input: &[u8]) -> Result<[u8; 32]> { + let mut hmac = + Hmac::::new_from_slice(key).expect("HMAC-SHA256 should accept any size key"); + hmac.update(input); + Ok(hmac.finalize().into_bytes().into()) +} + +pub fn aes256_ctr_hmacsha256_encrypt( + msg: &[u8], + cipher_key: &[u8], + mac_key: &[u8], +) -> Result> { + let ctext = aes_256_ctr_encrypt(msg, cipher_key)?; + let mac = hmac_sha256(mac_key, &ctext)?; + let mut result = Vec::with_capacity(ctext.len() + 10); + result.extend_from_slice(&ctext); + result.extend_from_slice(&mac[..10]); + Ok(result) +} + +pub fn aes256_ctr_hmacsha256_decrypt( + ctext: &[u8], + cipher_key: &[u8], + mac_key: &[u8], +) -> Result> { + if ctext.len() < 10 { + return Err(SignalProtocolError::InvalidCiphertext); + } + let ptext_len = ctext.len() - 10; + let our_mac = hmac_sha256(mac_key, &ctext[..ptext_len])?; + let same: bool = our_mac[..10].ct_eq(&ctext[ptext_len..]).into(); + if !same { + return Err(SignalProtocolError::InvalidCiphertext); + } + aes_256_ctr_decrypt(&ctext[..ptext_len], cipher_key) +} + +#[cfg(test)] +mod test { + use super::Result; + + #[test] + fn aes_cbc_test() -> Result<()> { + let key = hex::decode("4e22eb16d964779994222e82192ce9f747da72dc4abe49dfdeeb71d0ffe3796e") + .expect("valid hex"); + let iv = hex::decode("6f8a557ddc0a140c878063a6d5f31d3d").expect("valid hex"); + + let ptext = hex::decode("30736294a124482a4159").expect("valid hex"); + + let ctext = super::aes_256_cbc_encrypt(&ptext, &key, &iv)?; + assert_eq!( + hex::encode(ctext.clone()), + "dd3f573ab4508b9ed0e45e0baf5608f3" + ); + + let recovered = super::aes_256_cbc_decrypt(&ctext, &key, &iv)?; + assert_eq!(hex::encode(ptext), hex::encode(recovered.clone())); + + // padding is invalid: + assert!(super::aes_256_cbc_decrypt(&recovered, &key, &iv).is_err()); + assert!(super::aes_256_cbc_decrypt(&ctext, &key, &ctext).is_err()); + + // bitflip the IV to cause a change in the recovered text + let bad_iv = hex::decode("ef8a557ddc0a140c878063a6d5f31d3d").expect("valid hex"); + let recovered = super::aes_256_cbc_decrypt(&ctext, &key, &bad_iv)?; + assert_eq!(hex::encode(recovered), "b0736294a124482a4159"); + + Ok(()) + } + + #[test] + fn aes_ctr_test() -> Result<()> { + let key = hex::decode("603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4") + .expect("valid hex"); + let ptext = [0u8; 35]; + + let ctext = super::aes_256_ctr_encrypt(&ptext, &key)?; + assert_eq!( + hex::encode(ctext), + "e568f68194cf76d6174d4cc04310a85491151e5d0b7a1f1bc0d7acd0ae3e51e4170e23" + ); + + Ok(()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/curve.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/curve.rs new file mode 100644 index 0000000..0f62512 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/curve.rs @@ -0,0 +1,402 @@ +// +// Copyright 2020-2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +pub(crate) mod curve25519; + +use crate::{Result, SignalProtocolError}; + +use std::cmp::Ordering; +use std::convert::TryFrom; +use std::fmt; + +use arrayref::array_ref; +use rand::{CryptoRng, Rng}; +use subtle::ConstantTimeEq; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum KeyType { + Djb, +} + +impl fmt::Display for KeyType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +impl KeyType { + fn value(&self) -> u8 { + match &self { + KeyType::Djb => 0x05u8, + } + } +} + +impl TryFrom for KeyType { + type Error = SignalProtocolError; + + fn try_from(x: u8) -> Result { + match x { + 0x05u8 => Ok(KeyType::Djb), + t => Err(SignalProtocolError::BadKeyType(t)), + } + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +enum PublicKeyData { + DjbPublicKey([u8; curve25519::PUBLIC_KEY_LENGTH]), +} + +#[derive(Clone, Copy, Eq)] +pub struct PublicKey { + key: PublicKeyData, +} + +impl PublicKey { + fn new(key: PublicKeyData) -> Self { + Self { key } + } + + pub fn deserialize(value: &[u8]) -> Result { + if value.is_empty() { + return Err(SignalProtocolError::NoKeyTypeIdentifier); + } + let key_type = KeyType::try_from(value[0])?; + match key_type { + KeyType::Djb => { + // We allow trailing data after the public key (why?) + if value.len() < curve25519::PUBLIC_KEY_LENGTH + 1 { + return Err(SignalProtocolError::BadKeyLength(KeyType::Djb, value.len())); + } + let mut key = [0u8; curve25519::PUBLIC_KEY_LENGTH]; + key.copy_from_slice(&value[1..][..curve25519::PUBLIC_KEY_LENGTH]); + Ok(PublicKey { + key: PublicKeyData::DjbPublicKey(key), + }) + } + } + } + + pub fn public_key_bytes(&self) -> Result<&[u8]> { + match self.key { + PublicKeyData::DjbPublicKey(ref v) => Ok(v), + } + } + + pub fn from_djb_public_key_bytes(bytes: &[u8]) -> Result { + match <[u8; curve25519::PUBLIC_KEY_LENGTH]>::try_from(bytes) { + Err(_) => Err(SignalProtocolError::BadKeyLength(KeyType::Djb, bytes.len())), + Ok(key) => Ok(PublicKey { + key: PublicKeyData::DjbPublicKey(key), + }), + } + } + + pub fn serialize(&self) -> Box<[u8]> { + let value_len = match self.key { + PublicKeyData::DjbPublicKey(v) => v.len(), + }; + let mut result = Vec::with_capacity(1 + value_len); + result.push(self.key_type().value()); + match self.key { + PublicKeyData::DjbPublicKey(v) => result.extend_from_slice(&v), + } + result.into_boxed_slice() + } + + pub fn verify_signature(&self, message: &[u8], signature: &[u8]) -> Result { + match self.key { + PublicKeyData::DjbPublicKey(pub_key) => { + if signature.len() != curve25519::SIGNATURE_LENGTH { + return Ok(false); + } + Ok(curve25519::PrivateKey::verify_signature( + &pub_key, + message, + array_ref![signature, 0, curve25519::SIGNATURE_LENGTH], + )) + } + } + } + + fn key_data(&self) -> &[u8] { + match self.key { + PublicKeyData::DjbPublicKey(ref k) => k.as_ref(), + } + } + + pub fn key_type(&self) -> KeyType { + match self.key { + PublicKeyData::DjbPublicKey(_) => KeyType::Djb, + } + } +} + +impl From for PublicKey { + fn from(key: PublicKeyData) -> PublicKey { + Self { key } + } +} + +impl TryFrom<&[u8]> for PublicKey { + type Error = SignalProtocolError; + + fn try_from(value: &[u8]) -> Result { + Self::deserialize(value) + } +} + +impl subtle::ConstantTimeEq for PublicKey { + /// A constant-time comparison as long as the two keys have a matching type. + /// + /// If the two keys have different types, the comparison short-circuits, + /// much like comparing two slices of different lengths. + fn ct_eq(&self, other: &PublicKey) -> subtle::Choice { + if self.key_type() != other.key_type() { + return 0.ct_eq(&1); + } + self.key_data().ct_eq(other.key_data()) + } +} + +impl PartialEq for PublicKey { + fn eq(&self, other: &PublicKey) -> bool { + bool::from(self.ct_eq(other)) + } +} + +impl Ord for PublicKey { + fn cmp(&self, other: &Self) -> Ordering { + if self.key_type() != other.key_type() { + return self.key_type().cmp(&other.key_type()); + } + + crate::utils::constant_time_cmp(self.key_data(), other.key_data()) + } +} + +impl PartialOrd for PublicKey { + fn partial_cmp(&self, other: &PublicKey) -> Option { + Some(self.cmp(other)) + } +} + +impl fmt::Debug for PublicKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "PublicKey {{ key_type={}, serialize={:?} }}", + self.key_type(), + self.serialize() + ) + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +enum PrivateKeyData { + DjbPrivateKey([u8; curve25519::PRIVATE_KEY_LENGTH]), +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct PrivateKey { + key: PrivateKeyData, +} + +impl PrivateKey { + pub fn deserialize(value: &[u8]) -> Result { + if value.len() != curve25519::PRIVATE_KEY_LENGTH { + Err(SignalProtocolError::BadKeyLength(KeyType::Djb, value.len())) + } else { + let mut key = [0u8; curve25519::PRIVATE_KEY_LENGTH]; + key.copy_from_slice(&value[..curve25519::PRIVATE_KEY_LENGTH]); + // Clamp: + key[0] &= 0xF8; + key[31] &= 0x7F; + key[31] |= 0x40; + Ok(Self { + key: PrivateKeyData::DjbPrivateKey(key), + }) + } + } + + pub fn serialize(&self) -> Vec { + match self.key { + PrivateKeyData::DjbPrivateKey(v) => v.to_vec(), + } + } + + pub fn public_key(&self) -> Result { + match self.key { + PrivateKeyData::DjbPrivateKey(private_key) => { + let public_key = + curve25519::PrivateKey::from(private_key).derive_public_key_bytes(); + Ok(PublicKey::new(PublicKeyData::DjbPublicKey(public_key))) + } + } + } + + pub fn key_type(&self) -> KeyType { + match self.key { + PrivateKeyData::DjbPrivateKey(_) => KeyType::Djb, + } + } + + pub fn calculate_signature( + &self, + message: &[u8], + csprng: &mut R, + ) -> Result> { + match self.key { + PrivateKeyData::DjbPrivateKey(k) => { + let private_key = curve25519::PrivateKey::from(k); + Ok(Box::new(private_key.calculate_signature(csprng, message))) + } + } + } + + pub fn calculate_agreement(&self, their_key: &PublicKey) -> Result> { + match (self.key, their_key.key) { + (PrivateKeyData::DjbPrivateKey(priv_key), PublicKeyData::DjbPublicKey(pub_key)) => { + let private_key = curve25519::PrivateKey::from(priv_key); + Ok(Box::new(private_key.calculate_agreement(&pub_key))) + } + } + } +} + +impl From for PrivateKey { + fn from(key: PrivateKeyData) -> PrivateKey { + Self { key } + } +} + +impl TryFrom<&[u8]> for PrivateKey { + type Error = SignalProtocolError; + + fn try_from(value: &[u8]) -> Result { + Self::deserialize(value) + } +} + +#[derive(Copy, Clone)] +pub struct KeyPair { + pub public_key: PublicKey, + pub private_key: PrivateKey, +} + +impl KeyPair { + pub fn generate(csprng: &mut R) -> Self { + let private_key = curve25519::PrivateKey::new(csprng); + + let public_key = PublicKey::from(PublicKeyData::DjbPublicKey( + private_key.derive_public_key_bytes(), + )); + let private_key = PrivateKey::from(PrivateKeyData::DjbPrivateKey( + private_key.private_key_bytes(), + )); + + Self { + public_key, + private_key, + } + } + + pub fn new(public_key: PublicKey, private_key: PrivateKey) -> Self { + Self { + public_key, + private_key, + } + } + + pub fn from_public_and_private(public_key: &[u8], private_key: &[u8]) -> Result { + let public_key = PublicKey::try_from(public_key)?; + let private_key = PrivateKey::try_from(private_key)?; + Ok(Self { + public_key, + private_key, + }) + } + + pub fn calculate_signature( + &self, + message: &[u8], + csprng: &mut R, + ) -> Result> { + self.private_key.calculate_signature(message, csprng) + } + + pub fn calculate_agreement(&self, their_key: &PublicKey) -> Result> { + self.private_key.calculate_agreement(their_key) + } +} + +impl TryFrom for KeyPair { + type Error = SignalProtocolError; + + fn try_from(value: PrivateKey) -> Result { + let public_key = value.public_key()?; + Ok(Self::new(public_key, value)) + } +} + +#[cfg(test)] +mod tests { + use rand::rngs::OsRng; + + use super::*; + + #[test] + fn test_large_signatures() -> Result<()> { + let mut csprng = OsRng; + let key_pair = KeyPair::generate(&mut csprng); + let mut message = [0u8; 1024 * 1024]; + let signature = key_pair + .private_key + .calculate_signature(&message, &mut csprng)?; + + assert!(key_pair.public_key.verify_signature(&message, &signature)?); + message[0] ^= 0x01u8; + assert!(!key_pair.public_key.verify_signature(&message, &signature)?); + message[0] ^= 0x01u8; + let public_key = key_pair.private_key.public_key()?; + assert!(public_key.verify_signature(&message, &signature)?); + + Ok(()) + } + + #[test] + fn test_decode_size() -> Result<()> { + let mut csprng = OsRng; + let key_pair = KeyPair::generate(&mut csprng); + let serialized_public = key_pair.public_key.serialize(); + + assert_eq!( + serialized_public, + key_pair.private_key.public_key()?.serialize() + ); + let empty: [u8; 0] = []; + + let just_right = PublicKey::try_from(&serialized_public[..]); + + assert!(just_right.is_ok()); + assert!(PublicKey::try_from(&serialized_public[1..]).is_err()); + assert!(PublicKey::try_from(&empty[..]).is_err()); + + let mut bad_key_type = [0u8; 33]; + bad_key_type[..].copy_from_slice(&serialized_public[..]); + bad_key_type[0] = 0x01u8; + assert!(PublicKey::try_from(&bad_key_type[..]).is_err()); + + let mut extra_space = [0u8; 34]; + extra_space[..33].copy_from_slice(&serialized_public[..]); + let extra_space_decode = PublicKey::try_from(&extra_space[..]); + assert!(extra_space_decode.is_ok()); + + assert_eq!(&serialized_public[..], &just_right?.serialize()[..]); + assert_eq!(&serialized_public[..], &extra_space_decode?.serialize()[..]); + Ok(()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/curve/curve25519.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/curve/curve25519.rs new file mode 100644 index 0000000..0978004 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/curve/curve25519.rs @@ -0,0 +1,284 @@ +// +// Copyright 2020-2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; +use curve25519_dalek::edwards::EdwardsPoint; +use curve25519_dalek::montgomery::MontgomeryPoint; +use curve25519_dalek::scalar::Scalar; +use rand::{CryptoRng, Rng}; +use sha2::{Digest, Sha512}; +use subtle::ConstantTimeEq; +use x25519_dalek::{PublicKey, StaticSecret}; + +const AGREEMENT_LENGTH: usize = 32; +pub const PRIVATE_KEY_LENGTH: usize = 32; +pub const PUBLIC_KEY_LENGTH: usize = 32; +pub const SIGNATURE_LENGTH: usize = 64; + +#[derive(Clone)] +pub struct PrivateKey { + secret: StaticSecret, +} + +impl PrivateKey { + pub fn new(csprng: &mut R) -> Self + where + R: CryptoRng + Rng, + { + let secret = StaticSecret::new(csprng); + PrivateKey { secret } + } + + pub fn calculate_agreement( + &self, + their_public_key: &[u8; PUBLIC_KEY_LENGTH], + ) -> [u8; AGREEMENT_LENGTH] { + *self + .secret + .diffie_hellman(&PublicKey::from(*their_public_key)) + .as_bytes() + } + + /// Calculates an XEdDSA signature using the X25519 private key directly. + /// + /// Refer to https://signal.org/docs/specifications/xeddsa/#curve25519 for more details. + /// + /// Note that this implementation varies slightly from that paper in that the sign bit is not + /// fixed to 0, but rather passed back in the most significant bit of the signature which would + /// otherwise always be 0. This is for compatibility with the implementation found in + /// libsignal-protocol-java. + pub fn calculate_signature(&self, csprng: &mut R, message: &[u8]) -> [u8; SIGNATURE_LENGTH] + where + R: CryptoRng + Rng, + { + let mut random_bytes = [0u8; 64]; + csprng.fill_bytes(&mut random_bytes); + + let key_data = self.secret.to_bytes(); + let a = Scalar::from_bits(key_data); + let ed_public_key_point = &a * &ED25519_BASEPOINT_TABLE; + let ed_public_key = ed_public_key_point.compress(); + let sign_bit = ed_public_key.as_bytes()[31] & 0b1000_0000_u8; + + let mut hash1 = Sha512::new(); + let hash_prefix = [ + 0xFEu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, + 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, + 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, + ]; + hash1.update(&hash_prefix); + hash1.update(&key_data); + hash1.update(&message); + hash1.update(&random_bytes[..]); + + let r = Scalar::from_hash(hash1); + let cap_r = (&r * &ED25519_BASEPOINT_TABLE).compress(); + + let mut hash = Sha512::new(); + hash.update(cap_r.as_bytes()); + hash.update(ed_public_key.as_bytes()); + hash.update(&message); + + let h = Scalar::from_hash(hash); + let s = (h * a) + r; + + let mut result = [0u8; SIGNATURE_LENGTH]; + result[..32].copy_from_slice(cap_r.as_bytes()); + result[32..].copy_from_slice(s.as_bytes()); + result[SIGNATURE_LENGTH - 1] &= 0b0111_1111_u8; + result[SIGNATURE_LENGTH - 1] |= sign_bit; + result + } + + pub fn verify_signature( + their_public_key: &[u8; PUBLIC_KEY_LENGTH], + message: &[u8], + signature: &[u8; SIGNATURE_LENGTH], + ) -> bool { + let mont_point = MontgomeryPoint(*their_public_key); + let ed_pub_key_point = + match mont_point.to_edwards((signature[SIGNATURE_LENGTH - 1] & 0b1000_0000_u8) >> 7) { + Some(x) => x, + None => return false, + }; + let cap_a = ed_pub_key_point.compress(); + let mut cap_r = [0u8; 32]; + cap_r.copy_from_slice(&signature[..32]); + let mut s = [0u8; 32]; + s.copy_from_slice(&signature[32..]); + s[31] &= 0b0111_1111_u8; + if (s[31] & 0b1110_0000_u8) != 0 { + return false; + } + let minus_cap_a = -ed_pub_key_point; + + let mut hash = Sha512::new(); + hash.update(&cap_r); + hash.update(cap_a.as_bytes()); + hash.update(&message); + let h = Scalar::from_hash(hash); + + let cap_r_check_point = EdwardsPoint::vartime_double_scalar_mul_basepoint( + &h, + &minus_cap_a, + &Scalar::from_bits(s), + ); + let cap_r_check = cap_r_check_point.compress(); + + bool::from(cap_r_check.as_bytes().ct_eq(&cap_r)) + } + + pub fn derive_public_key_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] { + *PublicKey::from(&self.secret).as_bytes() + } + + pub fn private_key_bytes(&self) -> [u8; PRIVATE_KEY_LENGTH] { + self.secret.to_bytes() + } +} + +impl From<[u8; PRIVATE_KEY_LENGTH]> for PrivateKey { + fn from(private_key: [u8; 32]) -> Self { + let secret = StaticSecret::from(private_key); + PrivateKey { secret } + } +} + +#[cfg(test)] +mod tests { + use rand::rngs::OsRng; + use rand::RngCore; + + use super::*; + + #[test] + fn test_agreement() { + let alice_public: [u8; 32] = [ + 0x1b, 0xb7, 0x59, 0x66, 0xf2, 0xe9, 0x3a, 0x36, 0x91, 0xdf, 0xff, 0x94, 0x2b, 0xb2, + 0xa4, 0x66, 0xa1, 0xc0, 0x8b, 0x8d, 0x78, 0xca, 0x3f, 0x4d, 0x6d, 0xf8, 0xb8, 0xbf, + 0xa2, 0xe4, 0xee, 0x28, + ]; + let alice_private: [u8; 32] = [ + 0xc8, 0x06, 0x43, 0x9d, 0xc9, 0xd2, 0xc4, 0x76, 0xff, 0xed, 0x8f, 0x25, 0x80, 0xc0, + 0x88, 0x8d, 0x58, 0xab, 0x40, 0x6b, 0xf7, 0xae, 0x36, 0x98, 0x87, 0x90, 0x21, 0xb9, + 0x6b, 0xb4, 0xbf, 0x59, + ]; + let bob_public: [u8; 32] = [ + 0x65, 0x36, 0x14, 0x99, 0x3d, 0x2b, 0x15, 0xee, 0x9e, 0x5f, 0xd3, 0xd8, 0x6c, 0xe7, + 0x19, 0xef, 0x4e, 0xc1, 0xda, 0xae, 0x18, 0x86, 0xa8, 0x7b, 0x3f, 0x5f, 0xa9, 0x56, + 0x5a, 0x27, 0xa2, 0x2f, + ]; + let bob_private: [u8; 32] = [ + 0xb0, 0x3b, 0x34, 0xc3, 0x3a, 0x1c, 0x44, 0xf2, 0x25, 0xb6, 0x62, 0xd2, 0xbf, 0x48, + 0x59, 0xb8, 0x13, 0x54, 0x11, 0xfa, 0x7b, 0x03, 0x86, 0xd4, 0x5f, 0xb7, 0x5d, 0xc5, + 0xb9, 0x1b, 0x44, 0x66, + ]; + let shared: [u8; 32] = [ + 0x32, 0x5f, 0x23, 0x93, 0x28, 0x94, 0x1c, 0xed, 0x6e, 0x67, 0x3b, 0x86, 0xba, 0x41, + 0x01, 0x74, 0x48, 0xe9, 0x9b, 0x64, 0x9a, 0x9c, 0x38, 0x06, 0xc1, 0xdd, 0x7c, 0xa4, + 0xc4, 0x77, 0xe6, 0x29, + ]; + + let alice_key = PrivateKey::from(alice_private); + let bob_key = PrivateKey::from(bob_private); + + assert_eq!(alice_public, alice_key.derive_public_key_bytes()); + assert_eq!(bob_public, bob_key.derive_public_key_bytes()); + + let alice_computed_secret = alice_key.calculate_agreement(&bob_public); + let bob_computed_secret = bob_key.calculate_agreement(&alice_public); + + assert_eq!(shared, alice_computed_secret); + assert_eq!(shared, bob_computed_secret); + } + + #[test] + fn test_random_agreements() { + let mut csprng = OsRng; + for _ in 0..50 { + let alice_key = PrivateKey::new(&mut csprng); + let bob_key = PrivateKey::new(&mut csprng); + + let alice_computed_secret = + alice_key.calculate_agreement(&bob_key.derive_public_key_bytes()); + let bob_computed_secret = + bob_key.calculate_agreement(&alice_key.derive_public_key_bytes()); + + assert_eq!(alice_computed_secret, bob_computed_secret); + } + } + + #[test] + fn test_signature() { + let alice_identity_private: [u8; PRIVATE_KEY_LENGTH] = [ + 0xc0, 0x97, 0x24, 0x84, 0x12, 0xe5, 0x8b, 0xf0, 0x5d, 0xf4, 0x87, 0x96, 0x82, 0x05, + 0x13, 0x27, 0x94, 0x17, 0x8e, 0x36, 0x76, 0x37, 0xf5, 0x81, 0x8f, 0x81, 0xe0, 0xe6, + 0xce, 0x73, 0xe8, 0x65, + ]; + let alice_identity_public: [u8; PUBLIC_KEY_LENGTH] = [ + 0xab, 0x7e, 0x71, 0x7d, 0x4a, 0x16, 0x3b, 0x7d, 0x9a, 0x1d, 0x80, 0x71, 0xdf, 0xe9, + 0xdc, 0xf8, 0xcd, 0xcd, 0x1c, 0xea, 0x33, 0x39, 0xb6, 0x35, 0x6b, 0xe8, 0x4d, 0x88, + 0x7e, 0x32, 0x2c, 0x64, + ]; + let alice_ephemeral_public: [u8; PUBLIC_KEY_LENGTH + 1] = [ + 0x05, 0xed, 0xce, 0x9d, 0x9c, 0x41, 0x5c, 0xa7, 0x8c, 0xb7, 0x25, 0x2e, 0x72, 0xc2, + 0xc4, 0xa5, 0x54, 0xd3, 0xeb, 0x29, 0x48, 0x5a, 0x0e, 0x1d, 0x50, 0x31, 0x18, 0xd1, + 0xa8, 0x2d, 0x99, 0xfb, 0x4a, + ]; + let alice_signature: [u8; SIGNATURE_LENGTH] = [ + 0x5d, 0xe8, 0x8c, 0xa9, 0xa8, 0x9b, 0x4a, 0x11, 0x5d, 0xa7, 0x91, 0x09, 0xc6, 0x7c, + 0x9c, 0x74, 0x64, 0xa3, 0xe4, 0x18, 0x02, 0x74, 0xf1, 0xcb, 0x8c, 0x63, 0xc2, 0x98, + 0x4e, 0x28, 0x6d, 0xfb, 0xed, 0xe8, 0x2d, 0xeb, 0x9d, 0xcd, 0x9f, 0xae, 0x0b, 0xfb, + 0xb8, 0x21, 0x56, 0x9b, 0x3d, 0x90, 0x01, 0xbd, 0x81, 0x30, 0xcd, 0x11, 0xd4, 0x86, + 0xce, 0xf0, 0x47, 0xbd, 0x60, 0xb8, 0x6e, 0x88, + ]; + + let alice_identity_key = PrivateKey::from(alice_identity_private); + + assert_eq!( + alice_identity_public, + alice_identity_key.derive_public_key_bytes() + ); + + assert!( + PrivateKey::verify_signature( + &alice_identity_public, + &alice_ephemeral_public, + &alice_signature + ), + "signature check failed" + ); + + for i in 0..alice_signature.len() { + let mut alice_signature_copy: [u8; SIGNATURE_LENGTH] = [0; SIGNATURE_LENGTH]; + alice_signature_copy.copy_from_slice(&alice_signature); + alice_signature_copy[i] ^= 0x01u8; + + assert!( + !PrivateKey::verify_signature( + &alice_identity_public, + &alice_ephemeral_public, + &alice_signature_copy + ), + "signature check passed when it should not have" + ); + } + } + + #[test] + fn test_random_signatures() { + let mut csprng = OsRng; + for _ in 0..50 { + let mut message = [0u8; 64]; + csprng.fill_bytes(&mut message); + let key = PrivateKey::new(&mut csprng); + let signature = key.calculate_signature(&mut csprng, &message); + assert!( + PrivateKey::verify_signature(&key.derive_public_key_bytes(), &message, &signature), + "signature check failed" + ); + } + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/error.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/error.rs new file mode 100644 index 0000000..ae42326 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/error.rs @@ -0,0 +1,108 @@ +// +// Copyright 2020-2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::curve::KeyType; + +use displaydoc::Display; +use thiserror::Error; + +use std::panic::UnwindSafe; + +pub type Result = std::result::Result; + +#[derive(Debug, Display, Error)] +pub enum SignalProtocolError { + /// invalid argument: {0} + InvalidArgument(String), + /// invalid state for call to {0} to succeed: {1} + InvalidState(&'static str, String), + + // TODO: avoid duplicating error information in the Display impl and the #[from] or #[source] + // attribute if/when we switch to using an error reporting mechanism supporting stack traces: + // see https://github.com/yaahc/blog.rust-lang.org/blob/master/posts/inside-rust/2021-05-15-What-the-error-handling-project-group-is-working-towards.md#duplicate-information-issue + /// failed to decode protobuf: {0} + ProtobufDecodingError(#[from] prost::DecodeError), + /// failed to encode protobuf: {0} + ProtobufEncodingError(#[from] prost::EncodeError), + /// protobuf encoding was invalid + InvalidProtobufEncoding, + + /// ciphertext serialized bytes were too short <{0}> + CiphertextMessageTooShort(usize), + /// ciphertext version was too old <{0}> + LegacyCiphertextVersion(u8), + /// ciphertext version was unrecognized <{0}> + UnrecognizedCiphertextVersion(u8), + /// unrecognized message version <{0}> + UnrecognizedMessageVersion(u32), + + /// fingerprint identifiers do not match + FingerprintIdentifierMismatch, + /// fingerprint version number mismatch them {0} us {1} + FingerprintVersionMismatch(u32, u32), + /// fingerprint parsing error + FingerprintParsingError, + + /// no key type identifier + NoKeyTypeIdentifier, + /// bad key type <{0:#04x}> + BadKeyType(u8), + /// bad key length <{1}> for key with type <{0}> + BadKeyLength(KeyType, usize), + + /// invalid signature detected + SignatureValidationFailed, + + /// untrusted identity for address {0} + UntrustedIdentity(crate::ProtocolAddress), + + /// invalid prekey identifier + InvalidPreKeyId, + /// invalid signed prekey identifier + InvalidSignedPreKeyId, + + /// invalid root key length <{0}> + InvalidRootKeyLength(usize), + /// invalid chain key length <{0}> + InvalidChainKeyLength(usize), + + /// invalid MAC key length <{0}> + InvalidMacKeyLength(usize), + /// invalid cipher key length <{0}> or nonce length <{1}> + InvalidCipherCryptographicParameters(usize, usize), + /// invalid ciphertext message + InvalidCiphertext, + + /// no sender key state + NoSenderKeyState, + + /// session with '{0}' not found + SessionNotFound(String), + /// invalid session structure + InvalidSessionStructure, + /// session for {0} has invalid registration ID {1:X} + InvalidRegistrationId(crate::ProtocolAddress, u32), + + /// message with old counter {0} / {1} + DuplicatedMessage(u32, u32), + /// invalid message {0} + InvalidMessage(&'static str), + /// internal error {0} + InternalError(&'static str), + /// error while invoking an ffi callback: {0} + FfiBindingError(String), + /// error in method call '{0}': {1} + ApplicationCallbackError( + &'static str, + #[source] Box, + ), + + /// invalid sealed sender message {0} + InvalidSealedSenderMessage(String), + /// unknown sealed sender message version {0} + UnknownSealedSenderVersion(u8), + /// self send of a sealed sender message + SealedSenderSelfSend, +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/fingerprint.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/fingerprint.rs new file mode 100644 index 0000000..e65178d --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/fingerprint.rs @@ -0,0 +1,545 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::proto; +use crate::{IdentityKey, Result, SignalProtocolError}; +use prost::Message; +use sha2::{digest::Digest, Sha512}; +use std::fmt; +use subtle::ConstantTimeEq; + +#[derive(Debug, Clone)] +pub struct DisplayableFingerprint { + local: String, + remote: String, +} + +impl fmt::Display for DisplayableFingerprint { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.local < self.remote { + write!(f, "{}{}", self.local, self.remote) + } else { + write!(f, "{}{}", self.remote, self.local) + } + } +} + +fn get_encoded_string(fprint: &[u8]) -> Result { + if fprint.len() < 30 { + return Err(SignalProtocolError::InvalidArgument( + "DisplayableFingerprint created with short encoding".to_string(), + )); + } + + fn read5_mod_100k(fprint: &[u8]) -> u64 { + assert_eq!(fprint.len(), 5); + let x = fprint.iter().fold(0u64, |acc, &x| acc * 256 + (x as u64)); + x % 100000 + } + + // todo use iterators + let s = format!( + "{:05}{:05}{:05}{:05}{:05}{:05}", + read5_mod_100k(&fprint[0..5]), + read5_mod_100k(&fprint[5..10]), + read5_mod_100k(&fprint[10..15]), + read5_mod_100k(&fprint[15..20]), + read5_mod_100k(&fprint[20..25]), + read5_mod_100k(&fprint[25..30]) + ); + + Ok(s) +} + +impl DisplayableFingerprint { + pub fn new(local: &[u8], remote: &[u8]) -> Result { + Ok(Self { + local: get_encoded_string(local)?, + remote: get_encoded_string(remote)?, + }) + } +} + +#[derive(Debug, Clone)] +pub struct ScannableFingerprint { + version: u32, + local_fingerprint: Vec, + remote_fingerprint: Vec, +} + +impl ScannableFingerprint { + fn new(version: u32, local_fprint: &[u8], remote_fprint: &[u8]) -> Self { + Self { + version, + local_fingerprint: local_fprint[..32].to_vec(), + remote_fingerprint: remote_fprint[..32].to_vec(), + } + } + + pub fn deserialize(protobuf: &[u8]) -> Result { + let fingerprint = proto::fingerprint::CombinedFingerprints::decode(protobuf) + .map_err(|_| SignalProtocolError::FingerprintParsingError)?; + + Ok(Self { + version: fingerprint + .version + .ok_or(SignalProtocolError::FingerprintParsingError)?, + local_fingerprint: fingerprint + .local_fingerprint + .ok_or(SignalProtocolError::FingerprintParsingError)? + .content + .ok_or(SignalProtocolError::FingerprintParsingError)?, + remote_fingerprint: fingerprint + .remote_fingerprint + .ok_or(SignalProtocolError::FingerprintParsingError)? + .content + .ok_or(SignalProtocolError::FingerprintParsingError)?, + }) + } + + pub fn serialize(&self) -> Result> { + let combined_fingerprints = proto::fingerprint::CombinedFingerprints { + version: Some(self.version), + local_fingerprint: Some(proto::fingerprint::LogicalFingerprint { + content: Some(self.local_fingerprint.to_owned()), + }), + remote_fingerprint: Some(proto::fingerprint::LogicalFingerprint { + content: Some(self.remote_fingerprint.to_owned()), + }), + }; + + Ok(combined_fingerprints.encode_to_vec()) + } + + pub fn compare(&self, combined: &[u8]) -> Result { + let combined = proto::fingerprint::CombinedFingerprints::decode(combined) + .map_err(|_| SignalProtocolError::FingerprintParsingError)?; + + let their_version = combined.version.unwrap_or(0); + + if their_version != self.version { + return Err(SignalProtocolError::FingerprintVersionMismatch( + their_version, + self.version, + )); + } + + let same1 = combined + .local_fingerprint + .as_ref() + .ok_or(SignalProtocolError::FingerprintParsingError)? + .content + .as_ref() + .ok_or(SignalProtocolError::FingerprintParsingError)? + .ct_eq(&self.remote_fingerprint); + let same2 = combined + .remote_fingerprint + .as_ref() + .ok_or(SignalProtocolError::FingerprintParsingError)? + .content + .as_ref() + .ok_or(SignalProtocolError::FingerprintParsingError)? + .ct_eq(&self.local_fingerprint); + + Ok(same1.into() && same2.into()) + } +} + +#[derive(Debug, Clone)] +pub struct Fingerprint { + pub display: DisplayableFingerprint, + pub scannable: ScannableFingerprint, +} + +impl Fingerprint { + fn get_fingerprint( + iterations: u32, + local_id: &[u8], + local_key: &IdentityKey, + ) -> Result> { + if iterations <= 1 || iterations > 1000000 { + return Err(SignalProtocolError::InvalidArgument(format!( + "Invalid fingerprint iterations {}", + iterations + ))); + } + + let fingerprint_version = [0u8, 0u8]; // 0x0000 + let key_bytes = local_key.serialize(); + + let mut sha512 = Sha512::new(); + + // iteration=0 + sha512.update(&fingerprint_version); + sha512.update(&key_bytes); + sha512.update(local_id); + sha512.update(&key_bytes); + let mut buf = sha512.finalize(); + + for _i in 1..iterations { + let mut sha512 = Sha512::new(); + sha512.update(&buf); + sha512.update(&key_bytes); + buf = sha512.finalize(); + } + + Ok(buf.to_vec()) + } + + pub fn new( + version: u32, + iterations: u32, + local_id: &[u8], + local_key: &IdentityKey, + remote_id: &[u8], + remote_key: &IdentityKey, + ) -> Result { + let local_fingerprint = Fingerprint::get_fingerprint(iterations, local_id, local_key)?; + let remote_fingerprint = Fingerprint::get_fingerprint(iterations, remote_id, remote_key)?; + + Ok(Fingerprint { + display: DisplayableFingerprint::new(&local_fingerprint, &remote_fingerprint)?, + scannable: ScannableFingerprint::new(version, &local_fingerprint, &remote_fingerprint), + }) + } + + pub fn display_string(&self) -> Result { + Ok(format!("{}", self.display)) + } +} + +#[cfg(test)] +mod test { + use super::*; + + const ALICE_IDENTITY: &str = + "0506863bc66d02b40d27b8d49ca7c09e9239236f9d7d25d6fcca5ce13c7064d868"; + const BOB_IDENTITY: &str = "05f781b6fb32fed9ba1cf2de978d4d5da28dc34046ae814402b5c0dbd96fda907b"; + + const DISPLAYABLE_FINGERPRINT_V1: &str = + "300354477692869396892869876765458257569162576843440918079131"; + const ALICE_SCANNABLE_FINGERPRINT_V1 : &str = "080112220a201e301a0353dce3dbe7684cb8336e85136cdc0ee96219494ada305d62a7bd61df1a220a20d62cbf73a11592015b6b9f1682ac306fea3aaf3885b84d12bca631e9d4fb3a4d"; + const BOB_SCANNABLE_FINGERPRINT_V1 : &str = "080112220a20d62cbf73a11592015b6b9f1682ac306fea3aaf3885b84d12bca631e9d4fb3a4d1a220a201e301a0353dce3dbe7684cb8336e85136cdc0ee96219494ada305d62a7bd61df"; + + const ALICE_SCANNABLE_FINGERPRINT_V2 : &str = "080212220a201e301a0353dce3dbe7684cb8336e85136cdc0ee96219494ada305d62a7bd61df1a220a20d62cbf73a11592015b6b9f1682ac306fea3aaf3885b84d12bca631e9d4fb3a4d"; + const BOB_SCANNABLE_FINGERPRINT_V2 : & str = "080212220a20d62cbf73a11592015b6b9f1682ac306fea3aaf3885b84d12bca631e9d4fb3a4d1a220a201e301a0353dce3dbe7684cb8336e85136cdc0ee96219494ada305d62a7bd61df"; + + const ALICE_STABLE_ID: &str = "+14152222222"; + const BOB_STABLE_ID: &str = "+14153333333"; + + #[test] + fn fingerprint_encodings() -> Result<()> { + let l = vec![0x12; 32]; + let r = vec![0xBA; 32]; + + let fprint2 = ScannableFingerprint::new(2, &l, &r); + let proto2 = fprint2.serialize()?; + + let expected2_encoding = + "080212220a20".to_owned() + &"12".repeat(32) + "1a220a20" + &"ba".repeat(32); + assert_eq!(hex::encode(proto2), expected2_encoding); + + Ok(()) + } + + #[test] + fn fingerprint_test_v1() -> Result<()> { + // testVectorsVersion1 in Java + + let a_key = IdentityKey::decode(&hex::decode(ALICE_IDENTITY).expect("valid hex"))?; + let b_key = IdentityKey::decode(&hex::decode(BOB_IDENTITY).expect("valid hex"))?; + + let version = 1; + let iterations = 5200; + + let a_fprint = Fingerprint::new( + version, + iterations, + ALICE_STABLE_ID.as_bytes(), + &a_key, + BOB_STABLE_ID.as_bytes(), + &b_key, + )?; + + let b_fprint = Fingerprint::new( + version, + iterations, + BOB_STABLE_ID.as_bytes(), + &b_key, + ALICE_STABLE_ID.as_bytes(), + &a_key, + )?; + + assert_eq!( + hex::encode(a_fprint.scannable.serialize()?), + ALICE_SCANNABLE_FINGERPRINT_V1 + ); + assert_eq!( + hex::encode(b_fprint.scannable.serialize()?), + BOB_SCANNABLE_FINGERPRINT_V1 + ); + + assert_eq!(format!("{}", a_fprint.display), DISPLAYABLE_FINGERPRINT_V1); + assert_eq!(format!("{}", b_fprint.display), DISPLAYABLE_FINGERPRINT_V1); + + assert_eq!( + hex::encode(a_fprint.scannable.serialize()?), + ALICE_SCANNABLE_FINGERPRINT_V1 + ); + assert_eq!( + hex::encode(b_fprint.scannable.serialize()?), + BOB_SCANNABLE_FINGERPRINT_V1 + ); + + Ok(()) + } + + #[test] + fn fingerprint_test_v2() -> Result<()> { + // testVectorsVersion2 in Java + + let a_key = IdentityKey::decode(&hex::decode(ALICE_IDENTITY).expect("valid hex"))?; + let b_key = IdentityKey::decode(&hex::decode(BOB_IDENTITY).expect("valid hex"))?; + + let version = 2; + let iterations = 5200; + + let a_fprint = Fingerprint::new( + version, + iterations, + ALICE_STABLE_ID.as_bytes(), + &a_key, + BOB_STABLE_ID.as_bytes(), + &b_key, + )?; + + let b_fprint = Fingerprint::new( + version, + iterations, + BOB_STABLE_ID.as_bytes(), + &b_key, + ALICE_STABLE_ID.as_bytes(), + &a_key, + )?; + + assert_eq!( + hex::encode(a_fprint.scannable.serialize()?), + ALICE_SCANNABLE_FINGERPRINT_V2 + ); + assert_eq!( + hex::encode(b_fprint.scannable.serialize()?), + BOB_SCANNABLE_FINGERPRINT_V2 + ); + + // unchanged vs v1 + assert_eq!(format!("{}", a_fprint.display), DISPLAYABLE_FINGERPRINT_V1); + assert_eq!(format!("{}", b_fprint.display), DISPLAYABLE_FINGERPRINT_V1); + + assert_eq!( + hex::encode(a_fprint.scannable.serialize()?), + ALICE_SCANNABLE_FINGERPRINT_V2 + ); + assert_eq!( + hex::encode(b_fprint.scannable.serialize()?), + BOB_SCANNABLE_FINGERPRINT_V2 + ); + + Ok(()) + } + + #[test] + fn fingerprint_matching_identifiers() -> Result<()> { + // testMatchingFingerprints + + use crate::IdentityKeyPair; + use rand::rngs::OsRng; + + let a_key_pair = IdentityKeyPair::generate(&mut OsRng); + let b_key_pair = IdentityKeyPair::generate(&mut OsRng); + + let a_key = a_key_pair.identity_key(); + let b_key = b_key_pair.identity_key(); + + let version = 1; + let iterations = 1024; + + let a_fprint = Fingerprint::new( + version, + iterations, + ALICE_STABLE_ID.as_bytes(), + a_key, + BOB_STABLE_ID.as_bytes(), + b_key, + )?; + + let b_fprint = Fingerprint::new( + version, + iterations, + BOB_STABLE_ID.as_bytes(), + b_key, + ALICE_STABLE_ID.as_bytes(), + a_key, + )?; + + assert_eq!( + format!("{}", a_fprint.display), + format!("{}", b_fprint.display) + ); + assert_eq!(format!("{}", a_fprint.display).len(), 60); + + assert!(a_fprint + .scannable + .compare(&b_fprint.scannable.serialize()?)?); + assert!(b_fprint + .scannable + .compare(&a_fprint.scannable.serialize()?)?); + + // Java is missing this test + assert!(!a_fprint + .scannable + .compare(&a_fprint.scannable.serialize()?)?); + assert!(!b_fprint + .scannable + .compare(&b_fprint.scannable.serialize()?)?); + + Ok(()) + } + + #[test] + fn fingerprint_mismatching_fingerprints() -> Result<()> { + use crate::IdentityKeyPair; + use rand::rngs::OsRng; + + let a_key_pair = IdentityKeyPair::generate(&mut OsRng); + let b_key_pair = IdentityKeyPair::generate(&mut OsRng); + let m_key_pair = IdentityKeyPair::generate(&mut OsRng); // mitm + + let a_key = a_key_pair.identity_key(); + let b_key = b_key_pair.identity_key(); + let m_key = m_key_pair.identity_key(); + + let version = 1; + let iterations = 1024; + + let a_fprint = Fingerprint::new( + version, + iterations, + ALICE_STABLE_ID.as_bytes(), + a_key, + BOB_STABLE_ID.as_bytes(), + m_key, + )?; + + let b_fprint = Fingerprint::new( + version, + iterations, + BOB_STABLE_ID.as_bytes(), + b_key, + ALICE_STABLE_ID.as_bytes(), + a_key, + )?; + + assert_ne!( + format!("{}", a_fprint.display), + format!("{}", b_fprint.display) + ); + + assert!(!a_fprint + .scannable + .compare(&b_fprint.scannable.serialize()?)?); + assert!(!b_fprint + .scannable + .compare(&a_fprint.scannable.serialize()?)?); + + Ok(()) + } + + #[test] + fn fingerprint_mismatching_identifiers() -> Result<()> { + use crate::IdentityKeyPair; + use rand::rngs::OsRng; + + let a_key_pair = IdentityKeyPair::generate(&mut OsRng); + let b_key_pair = IdentityKeyPair::generate(&mut OsRng); + + let a_key = a_key_pair.identity_key(); + let b_key = b_key_pair.identity_key(); + + let version = 1; + let iterations = 1024; + + let a_fprint = Fingerprint::new( + version, + iterations, + "+141512222222".as_bytes(), + a_key, + BOB_STABLE_ID.as_bytes(), + b_key, + )?; + + let b_fprint = Fingerprint::new( + version, + iterations, + BOB_STABLE_ID.as_bytes(), + b_key, + ALICE_STABLE_ID.as_bytes(), + a_key, + )?; + + assert_ne!( + format!("{}", a_fprint.display), + format!("{}", b_fprint.display) + ); + + assert!(!a_fprint + .scannable + .compare(&b_fprint.scannable.serialize()?)?); + assert!(!b_fprint + .scannable + .compare(&a_fprint.scannable.serialize()?)?); + + Ok(()) + } + + #[test] + fn fingerprint_mismatching_versions() -> Result<()> { + let a_key = IdentityKey::decode(&hex::decode(ALICE_IDENTITY).expect("valid hex"))?; + let b_key = IdentityKey::decode(&hex::decode(BOB_IDENTITY).expect("valid hex"))?; + + let iterations = 5200; + + let a_fprint_v1 = Fingerprint::new( + 1, + iterations, + ALICE_STABLE_ID.as_bytes(), + &a_key, + BOB_STABLE_ID.as_bytes(), + &b_key, + )?; + + let a_fprint_v2 = Fingerprint::new( + 2, + iterations, + BOB_STABLE_ID.as_bytes(), + &b_key, + ALICE_STABLE_ID.as_bytes(), + &a_key, + )?; + + // Display fingerprint doesn't change + assert_eq!( + format!("{}", a_fprint_v1.display), + format!("{}", a_fprint_v2.display) + ); + + // Scannable fingerprint does + assert_ne!( + hex::encode(a_fprint_v1.scannable.serialize()?), + hex::encode(a_fprint_v2.scannable.serialize()?) + ); + + Ok(()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/group_cipher.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/group_cipher.rs new file mode 100644 index 0000000..4c1383d --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/group_cipher.rs @@ -0,0 +1,237 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::consts; +use crate::crypto; + +use crate::{ + Context, KeyPair, ProtocolAddress, Result, SenderKeyDistributionMessage, SenderKeyMessage, + SenderKeyRecord, SenderKeyStore, SignalProtocolError, +}; + +use crate::protocol::SENDERKEY_MESSAGE_CURRENT_VERSION; +use crate::sender_keys::{SenderKeyState, SenderMessageKey}; + +use rand::{CryptoRng, Rng}; +use std::convert::TryFrom; +use uuid::Uuid; + +pub async fn group_encrypt( + sender_key_store: &mut dyn SenderKeyStore, + sender: &ProtocolAddress, + distribution_id: Uuid, + plaintext: &[u8], + csprng: &mut R, + ctx: Context, +) -> Result { + let mut record = sender_key_store + .load_sender_key(sender, distribution_id, ctx) + .await? + .ok_or(SignalProtocolError::NoSenderKeyState)?; + + let sender_key_state = record.sender_key_state()?; + + let sender_key = sender_key_state.sender_chain_key()?.sender_message_key()?; + + let ciphertext = + crypto::aes_256_cbc_encrypt(plaintext, &sender_key.cipher_key()?, &sender_key.iv()?)?; + + let signing_key = sender_key_state.signing_key_private()?; + + let skm = SenderKeyMessage::new( + sender_key_state.message_version()? as u8, + distribution_id, + sender_key_state.chain_id()?, + sender_key.iteration()?, + ciphertext.into_boxed_slice(), + csprng, + &signing_key, + )?; + + sender_key_state.set_sender_chain_key(sender_key_state.sender_chain_key()?.next()?)?; + + sender_key_store + .store_sender_key(sender, distribution_id, &record, ctx) + .await?; + + Ok(skm) +} + +fn get_sender_key( + state: &mut SenderKeyState, + iteration: u32, + distribution_id: Uuid, +) -> Result { + let sender_chain_key = state.sender_chain_key()?; + let current_iteration = sender_chain_key.iteration()?; + + if current_iteration > iteration { + if let Some(smk) = state.remove_sender_message_key(iteration)? { + return Ok(smk); + } else { + log::info!( + "SenderKey distribution {} Duplicate message for iteration: {}", + distribution_id, + iteration + ); + return Err(SignalProtocolError::DuplicatedMessage( + current_iteration, + iteration, + )); + } + } + + let jump = (iteration - current_iteration) as usize; + if jump > consts::MAX_FORWARD_JUMPS { + log::error!( + "SenderKey distribution {} Exceeded future message limit: {}, current iteration: {})", + distribution_id, + consts::MAX_FORWARD_JUMPS, + current_iteration + ); + return Err(SignalProtocolError::InvalidMessage( + "message from too far into the future", + )); + } + + let mut sender_chain_key = sender_chain_key; + + while sender_chain_key.iteration()? < iteration { + state.add_sender_message_key(&sender_chain_key.sender_message_key()?)?; + sender_chain_key = sender_chain_key.next()?; + } + + state.set_sender_chain_key(sender_chain_key.next()?)?; + sender_chain_key.sender_message_key() +} + +pub async fn group_decrypt( + skm_bytes: &[u8], + sender_key_store: &mut dyn SenderKeyStore, + sender: &ProtocolAddress, + ctx: Context, +) -> Result> { + let skm = SenderKeyMessage::try_from(skm_bytes)?; + let mut record = sender_key_store + .load_sender_key(sender, skm.distribution_id(), ctx) + .await? + .ok_or(SignalProtocolError::NoSenderKeyState)?; + + let mut sender_key_state = + record.sender_key_state_for_chain_id(skm.chain_id(), skm.distribution_id())?; + + let message_version = skm.message_version() as u32; + if message_version != sender_key_state.message_version()? { + return Err(SignalProtocolError::UnrecognizedMessageVersion( + message_version, + )); + } + + let signing_key = sender_key_state.signing_key_public()?; + if !skm.verify_signature(&signing_key)? { + return Err(SignalProtocolError::SignatureValidationFailed); + } + + let sender_key = get_sender_key( + &mut sender_key_state, + skm.iteration(), + skm.distribution_id(), + )?; + + let plaintext = crypto::aes_256_cbc_decrypt( + skm.ciphertext(), + &sender_key.cipher_key()?, + &sender_key.iv()?, + )?; + + sender_key_store + .store_sender_key(sender, skm.distribution_id(), &record, ctx) + .await?; + + Ok(plaintext) +} + +pub async fn process_sender_key_distribution_message( + sender: &ProtocolAddress, + skdm: &SenderKeyDistributionMessage, + sender_key_store: &mut dyn SenderKeyStore, + ctx: Context, +) -> Result<()> { + let distribution_id = skdm.distribution_id()?; + log::info!( + "{} Processing SenderKey distribution {} with chain ID {}", + sender, + distribution_id, + skdm.chain_id()? + ); + + let mut sender_key_record = sender_key_store + .load_sender_key(sender, distribution_id, ctx) + .await? + .unwrap_or_else(SenderKeyRecord::new_empty); + + sender_key_record.add_sender_key_state( + skdm.message_version(), + skdm.chain_id()?, + skdm.iteration()?, + skdm.chain_key()?, + *skdm.signing_key()?, + None, + )?; + sender_key_store + .store_sender_key(sender, distribution_id, &sender_key_record, ctx) + .await?; + Ok(()) +} + +pub async fn create_sender_key_distribution_message( + sender: &ProtocolAddress, + distribution_id: Uuid, + sender_key_store: &mut dyn SenderKeyStore, + csprng: &mut R, + ctx: Context, +) -> Result { + let mut sender_key_record = sender_key_store + .load_sender_key(sender, distribution_id, ctx) + .await? + .unwrap_or_else(SenderKeyRecord::new_empty); + + if sender_key_record.is_empty()? { + // libsignal-protocol-java uses 31-bit integers for sender key chain IDs + let chain_id = (csprng.gen::()) >> 1; + log::info!( + "Creating SenderKey for distribution {} with chain ID {}", + distribution_id, + chain_id + ); + + let iteration = 0; + let sender_key: [u8; 32] = csprng.gen(); + let signing_key = KeyPair::generate(csprng); + sender_key_record.set_sender_key_state( + SENDERKEY_MESSAGE_CURRENT_VERSION, + chain_id, + iteration, + &sender_key, + signing_key.public_key, + Some(signing_key.private_key), + )?; + sender_key_store + .store_sender_key(sender, distribution_id, &sender_key_record, ctx) + .await?; + } + + let state = sender_key_record.sender_key_state()?; + let sender_chain_key = state.sender_chain_key()?; + + SenderKeyDistributionMessage::new( + state.message_version()? as u8, + distribution_id, + state.chain_id()?, + sender_chain_key.iteration()?, + sender_chain_key.seed()?, + state.signing_key_public()?, + ) +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/identity_key.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/identity_key.rs new file mode 100644 index 0000000..0a9b00b --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/identity_key.rs @@ -0,0 +1,179 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::proto; +use crate::{KeyPair, PrivateKey, PublicKey, Result, SignalProtocolError}; + +use rand::{CryptoRng, Rng}; +use std::convert::TryFrom; + +use prost::Message; + +#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy)] +pub struct IdentityKey { + public_key: PublicKey, +} + +impl IdentityKey { + pub fn new(public_key: PublicKey) -> Self { + Self { public_key } + } + + #[inline] + pub fn public_key(&self) -> &PublicKey { + &self.public_key + } + + #[inline] + pub fn serialize(&self) -> Box<[u8]> { + self.public_key.serialize() + } + + pub fn decode(value: &[u8]) -> Result { + let pk = PublicKey::try_from(value)?; + Ok(Self { public_key: pk }) + } +} + +impl TryFrom<&[u8]> for IdentityKey { + type Error = SignalProtocolError; + + fn try_from(value: &[u8]) -> Result { + IdentityKey::decode(value) + } +} + +impl From for IdentityKey { + fn from(value: PublicKey) -> Self { + Self { public_key: value } + } +} + +impl From for PublicKey { + fn from(value: IdentityKey) -> Self { + value.public_key + } +} + +#[derive(Copy, Clone)] +pub struct IdentityKeyPair { + identity_key: IdentityKey, + private_key: PrivateKey, +} + +impl IdentityKeyPair { + pub fn new(identity_key: IdentityKey, private_key: PrivateKey) -> Self { + Self { + identity_key, + private_key, + } + } + + pub fn generate(csprng: &mut R) -> Self { + let keypair = KeyPair::generate(csprng); + + Self { + identity_key: keypair.public_key.into(), + private_key: keypair.private_key, + } + } + + #[inline] + pub fn identity_key(&self) -> &IdentityKey { + &self.identity_key + } + + #[inline] + pub fn public_key(&self) -> &PublicKey { + self.identity_key.public_key() + } + + #[inline] + pub fn private_key(&self) -> &PrivateKey { + &self.private_key + } + + pub fn serialize(&self) -> Box<[u8]> { + let structure = proto::storage::IdentityKeyPairStructure { + public_key: self.identity_key.serialize().to_vec(), + private_key: self.private_key.serialize().to_vec(), + }; + + let result = structure.encode_to_vec(); + result.into_boxed_slice() + } +} + +impl TryFrom<&[u8]> for IdentityKeyPair { + type Error = SignalProtocolError; + + fn try_from(value: &[u8]) -> Result { + let structure = proto::storage::IdentityKeyPairStructure::decode(value)?; + Ok(Self { + identity_key: IdentityKey::try_from(&structure.public_key[..])?, + private_key: PrivateKey::deserialize(&structure.private_key)?, + }) + } +} + +impl TryFrom for IdentityKeyPair { + type Error = SignalProtocolError; + + fn try_from(private_key: PrivateKey) -> Result { + let identity_key = IdentityKey::new(private_key.public_key()?); + Ok(Self::new(identity_key, private_key)) + } +} + +impl From for IdentityKeyPair { + fn from(value: KeyPair) -> Self { + Self { + identity_key: value.public_key.into(), + private_key: value.private_key, + } + } +} + +impl From for KeyPair { + fn from(value: IdentityKeyPair) -> Self { + Self::new(value.identity_key.into(), value.private_key) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use rand::rngs::OsRng; + + #[test] + fn test_identity_key_from() { + let key_pair = KeyPair::generate(&mut OsRng); + let key_pair_public_serialized = key_pair.public_key.serialize(); + let identity_key = IdentityKey::from(key_pair.public_key); + assert_eq!(key_pair_public_serialized, identity_key.serialize()); + } + + #[test] + fn test_serialize_identity_key_pair() -> Result<()> { + let identity_key_pair = IdentityKeyPair::generate(&mut OsRng); + let serialized = identity_key_pair.serialize(); + let deserialized_identity_key_pair = IdentityKeyPair::try_from(&serialized[..])?; + assert_eq!( + identity_key_pair.identity_key(), + deserialized_identity_key_pair.identity_key() + ); + assert_eq!( + identity_key_pair.private_key().key_type(), + deserialized_identity_key_pair.private_key().key_type() + ); + assert_eq!( + identity_key_pair.private_key().serialize(), + deserialized_identity_key_pair.private_key().serialize() + ); + + Ok(()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/lib.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/lib.rs new file mode 100644 index 0000000..3b7d119 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/lib.rs @@ -0,0 +1,82 @@ +// +// Copyright 2020-2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +//! Rust implementation of the **[Signal Protocol]** for asynchronous +//! forward-secret public-key cryptography. +//! +//! In particular, this library implements operations conforming to the following specifications: +//! - the **[X3DH]** key agreement protocol, +//! - the **[Double Ratchet]** *(Axolotl)* messaging protocol, +//! +//! [Signal Protocol]: https://signal.org/ +//! [X3DH]: https://signal.org/docs/specifications/x3dh/ +//! [Double Ratchet]: https://signal.org/docs/specifications/doubleratchet/ + +#![warn(clippy::unwrap_used)] +#![deny(unsafe_code)] + +// TODO(https://github.com/signalapp/libsignal-client/issues/285): it should be an aspiration to +// eventually warn and then error for public members without docstrings. Also see +// https://doc.rust-lang.org/rustdoc/what-to-include.html for background. +// #![warn(missing_docs)] + +mod address; +mod consts; +mod crypto; +mod curve; +pub mod error; +mod fingerprint; +mod group_cipher; +mod identity_key; +mod proto; +mod protocol; +mod ratchet; +mod sealed_sender; +mod sender_keys; +mod session; +mod session_cipher; +mod state; +mod storage; +mod utils; + +use error::Result; + +pub use { + address::{DeviceId, ProtocolAddress}, + curve::{KeyPair, PrivateKey, PublicKey}, + error::SignalProtocolError, + fingerprint::{DisplayableFingerprint, Fingerprint, ScannableFingerprint}, + group_cipher::{ + create_sender_key_distribution_message, group_decrypt, group_encrypt, + process_sender_key_distribution_message, + }, + identity_key::{IdentityKey, IdentityKeyPair}, + protocol::{ + extract_decryption_error_message_from_serialized_content, CiphertextMessage, + CiphertextMessageType, DecryptionErrorMessage, PlaintextContent, PreKeySignalMessage, + SenderKeyDistributionMessage, SenderKeyMessage, SignalMessage, + }, + ratchet::{ + initialize_alice_session_record, initialize_bob_session_record, + AliceSignalProtocolParameters, BobSignalProtocolParameters, + }, + sealed_sender::{ + sealed_sender_decrypt, sealed_sender_decrypt_to_usmc, sealed_sender_encrypt, + sealed_sender_encrypt_from_usmc, sealed_sender_multi_recipient_encrypt, + sealed_sender_multi_recipient_fan_out, ContentHint, SealedSenderDecryptionResult, + SenderCertificate, ServerCertificate, UnidentifiedSenderMessageContent, + }, + sender_keys::SenderKeyRecord, + session::{process_prekey, process_prekey_bundle}, + session_cipher::{ + message_decrypt, message_decrypt_prekey, message_decrypt_signal, message_encrypt, + }, + state::{PreKeyBundle, PreKeyRecord, SessionRecord, SignedPreKeyRecord}, + storage::{ + Context, Direction, IdentityKeyStore, InMemIdentityKeyStore, InMemPreKeyStore, + InMemSenderKeyStore, InMemSessionStore, InMemSignalProtocolStore, InMemSignedPreKeyStore, + PreKeyStore, ProtocolStore, SenderKeyStore, SessionStore, SignedPreKeyStore, + }, +}; diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/proto.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto.rs new file mode 100644 index 0000000..4576ef3 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto.rs @@ -0,0 +1,10 @@ +// +// Copyright 2020-2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +pub mod fingerprint; +pub mod sealed_sender; +pub mod service; +pub mod storage; +pub mod wire; diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/fingerprint.proto b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/fingerprint.proto new file mode 100644 index 0000000..f876ce6 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/fingerprint.proto @@ -0,0 +1,19 @@ +syntax = "proto2"; + +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +package signal.proto.fingerprint; + +message LogicalFingerprint { + optional bytes content = 1; + // bytes identifier = 2; +} + +message CombinedFingerprints { + optional uint32 version = 1; + optional LogicalFingerprint local_fingerprint = 2; + optional LogicalFingerprint remote_fingerprint = 3; +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/fingerprint.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/fingerprint.rs new file mode 100644 index 0000000..c797e3a --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/fingerprint.rs @@ -0,0 +1,6 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +include!(concat!(env!("OUT_DIR"), "/signal.proto.fingerprint.rs")); diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/sealed_sender.proto b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/sealed_sender.proto new file mode 100644 index 0000000..a178e47 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/sealed_sender.proto @@ -0,0 +1,62 @@ +syntax = "proto2"; + +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +package signal.proto.sealed_sender; + +message ServerCertificate { + message Certificate { + optional uint32 id = 1; + optional bytes key = 2; + } + + optional bytes certificate = 1; + optional bytes signature = 2; +} + +message SenderCertificate { + message Certificate { + optional string senderE164 = 1; + optional string senderUuid = 6; + optional uint32 senderDevice = 2; + optional fixed64 expires = 3; + optional bytes identityKey = 4; + optional ServerCertificate signer = 5; + } + + optional bytes certificate = 1; + optional bytes signature = 2; +} + +message UnidentifiedSenderMessage { + + message Message { + enum Type { + PREKEY_MESSAGE = 1; + MESSAGE = 2; + // Further cases should line up with Envelope.Type, even though old cases don't. + reserved 3 to 6; + SENDERKEY_MESSAGE = 7; + PLAINTEXT_CONTENT = 8; + } + + enum ContentHint { + reserved 0; // Default: sender will not resend; an error should be shown immediately + RESENDABLE = 1; // Sender will try to resend; delay any error UI if possible + IMPLICIT = 2; // Don't show any error UI at all; this is something sent implicitly like a typing message or a receipt + } + + optional Type type = 1; + optional SenderCertificate senderCertificate = 2; + optional bytes content = 3; + optional ContentHint contentHint = 4; + optional bytes groupId = 5; + } + + optional bytes ephemeralPublic = 1; + optional bytes encryptedStatic = 2; + optional bytes encryptedMessage = 3; +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/sealed_sender.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/sealed_sender.rs new file mode 100644 index 0000000..0030e6a --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/sealed_sender.rs @@ -0,0 +1,6 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +include!(concat!(env!("OUT_DIR"), "/signal.proto.sealed_sender.rs")); diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/service.proto b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/service.proto new file mode 100644 index 0000000..38626dc --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/service.proto @@ -0,0 +1,24 @@ +// +// Copyright 2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +syntax = "proto2"; +package signalservice; + +message Content { + optional bytes /* DataMessage */ data_message = 1; + optional bytes /* SyncMessage */ sync_message = 2; + optional bytes /* CallMessage */ call_message = 3; + optional bytes /* NullMessage */ null_message = 4; + optional bytes /* ReceiptMessage */ receipt_message = 5; + optional bytes /* TypingMessage */ typing_message = 6; + optional bytes /* SenderKeyDistributionMessage */ sender_key_distribution_message = 7; + optional bytes /* DecryptionErrorMessage */ decryption_error_message = 8; +} + +message DecryptionErrorMessage { + optional bytes ratchet_key = 1; // set to the public ratchet key from the SignalMessage if a 1-1 payload fails to decrypt + optional uint64 timestamp = 2; + optional uint32 device_id = 3; +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/service.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/service.rs new file mode 100644 index 0000000..f6e6261 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/service.rs @@ -0,0 +1,6 @@ +// +// Copyright 2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +include!(concat!(env!("OUT_DIR"), "/signalservice.rs")); diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/storage.proto b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/storage.proto new file mode 100644 index 0000000..49fcced --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/storage.proto @@ -0,0 +1,108 @@ +syntax = "proto3"; + +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +package signal.proto.storage; + +message SessionStructure { + message Chain { + bytes sender_ratchet_key = 1; + bytes sender_ratchet_key_private = 2; + + message ChainKey { + uint32 index = 1; + bytes key = 2; + } + + ChainKey chain_key = 3; + + message MessageKey { + uint32 index = 1; + bytes cipher_key = 2; + bytes mac_key = 3; + bytes iv = 4; + } + + repeated MessageKey message_keys = 4; + } + + message PendingPreKey { + uint32 pre_key_id = 1; + int32 signed_pre_key_id = 3; + bytes base_key = 2; + } + + uint32 session_version = 1; + bytes local_identity_public = 2; + bytes remote_identity_public = 3; + + bytes root_key = 4; + uint32 previous_counter = 5; + + Chain sender_chain = 6; + // The order is significant; keys at the end are "older" and will get trimmed. + repeated Chain receiver_chains = 7; + + PendingPreKey pending_pre_key = 9; + + uint32 remote_registration_id = 10; + uint32 local_registration_id = 11; + + bool needs_refresh = 12; + bytes alice_base_key = 13; +} + +message RecordStructure { + SessionStructure current_session = 1; + // The order is significant; sessions at the end are "older" and will get trimmed. + repeated /*SessionStructure*/ bytes previous_sessions = 2; +} + +message PreKeyRecordStructure { + uint32 id = 1; + bytes public_key = 2; + bytes private_key = 3; +} + +message SignedPreKeyRecordStructure { + uint32 id = 1; + bytes public_key = 2; + bytes private_key = 3; + bytes signature = 4; + fixed64 timestamp = 5; +} + +message IdentityKeyPairStructure { + bytes public_key = 1; + bytes private_key = 2; +} + +message SenderKeyStateStructure { + message SenderChainKey { + uint32 iteration = 1; + bytes seed = 2; + } + + message SenderMessageKey { + uint32 iteration = 1; + bytes seed = 2; + } + + message SenderSigningKey { + bytes public = 1; + bytes private = 2; + } + + uint32 message_version = 5; + uint32 chain_id = 1; + SenderChainKey sender_chain_key = 2; + SenderSigningKey sender_signing_key = 3; + repeated SenderMessageKey sender_message_keys = 4; +} + +message SenderKeyRecordStructure { + repeated SenderKeyStateStructure sender_key_states = 1; +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/storage.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/storage.rs new file mode 100644 index 0000000..ec2d3f9 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/storage.rs @@ -0,0 +1,6 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +include!(concat!(env!("OUT_DIR"), "/signal.proto.storage.rs")); diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/wire.proto b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/wire.proto new file mode 100644 index 0000000..e0c0683 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/wire.proto @@ -0,0 +1,39 @@ +syntax = "proto2"; + +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +package signal.proto.wire; + +message SignalMessage { + optional bytes ratchet_key = 1; + optional uint32 counter = 2; + optional uint32 previous_counter = 3; + optional bytes ciphertext = 4; +} + +message PreKeySignalMessage { + optional uint32 registration_id = 5; + optional uint32 pre_key_id = 1; + optional uint32 signed_pre_key_id = 6; + optional bytes base_key = 2; + optional bytes identity_key = 3; + optional bytes message = 4; // SignalMessage +} + +message SenderKeyMessage { + optional bytes distribution_uuid = 1; + optional uint32 chain_id = 2; + optional uint32 iteration = 3; + optional bytes ciphertext = 4; +} + +message SenderKeyDistributionMessage { + optional bytes distribution_uuid = 1; + optional uint32 chain_id = 2; + optional uint32 iteration = 3; + optional bytes chain_key = 4; + optional bytes signing_key = 5; +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/wire.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/wire.rs new file mode 100644 index 0000000..e5e4e9c --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/proto/wire.rs @@ -0,0 +1,6 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +include!(concat!(env!("OUT_DIR"), "/signal.proto.wire.rs")); diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/protocol.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/protocol.rs new file mode 100644 index 0000000..b8bcf8a --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/protocol.rs @@ -0,0 +1,1059 @@ +// +// Copyright 2020-2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::proto; +use crate::{IdentityKey, PrivateKey, PublicKey, Result, SignalProtocolError}; + +use std::convert::TryFrom; + +use hmac::{Hmac, Mac, NewMac}; +use prost::Message; +use rand::{CryptoRng, Rng}; +use sha2::Sha256; +use subtle::ConstantTimeEq; +use uuid::Uuid; + +pub const CIPHERTEXT_MESSAGE_CURRENT_VERSION: u8 = 3; +pub const SENDERKEY_MESSAGE_CURRENT_VERSION: u8 = 3; + +pub enum CiphertextMessage { + SignalMessage(SignalMessage), + PreKeySignalMessage(PreKeySignalMessage), + SenderKeyMessage(SenderKeyMessage), + PlaintextContent(PlaintextContent), +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug, num_enum::TryFromPrimitive)] +#[repr(u8)] +pub enum CiphertextMessageType { + Whisper = 2, + PreKey = 3, + SenderKey = 7, + Plaintext = 8, +} + +impl CiphertextMessage { + pub fn message_type(&self) -> CiphertextMessageType { + match self { + CiphertextMessage::SignalMessage(_) => CiphertextMessageType::Whisper, + CiphertextMessage::PreKeySignalMessage(_) => CiphertextMessageType::PreKey, + CiphertextMessage::SenderKeyMessage(_) => CiphertextMessageType::SenderKey, + CiphertextMessage::PlaintextContent(_) => CiphertextMessageType::Plaintext, + } + } + + pub fn serialize(&self) -> &[u8] { + match self { + CiphertextMessage::SignalMessage(x) => x.serialized(), + CiphertextMessage::PreKeySignalMessage(x) => x.serialized(), + CiphertextMessage::SenderKeyMessage(x) => x.serialized(), + CiphertextMessage::PlaintextContent(x) => x.serialized(), + } + } +} + +#[derive(Debug, Clone)] +pub struct SignalMessage { + message_version: u8, + sender_ratchet_key: PublicKey, + counter: u32, + #[allow(dead_code)] + previous_counter: u32, + ciphertext: Box<[u8]>, + serialized: Box<[u8]>, +} + +impl SignalMessage { + const MAC_LENGTH: usize = 8; + + pub fn new( + message_version: u8, + mac_key: &[u8], + sender_ratchet_key: PublicKey, + counter: u32, + previous_counter: u32, + ciphertext: &[u8], + sender_identity_key: &IdentityKey, + receiver_identity_key: &IdentityKey, + ) -> Result { + let message = proto::wire::SignalMessage { + ratchet_key: Some(sender_ratchet_key.serialize().into_vec()), + counter: Some(counter), + previous_counter: Some(previous_counter), + ciphertext: Some(Vec::::from(ciphertext)), + }; + let mut serialized = vec![0u8; 1 + message.encoded_len() + Self::MAC_LENGTH]; + serialized[0] = ((message_version & 0xF) << 4) | CIPHERTEXT_MESSAGE_CURRENT_VERSION; + message.encode(&mut &mut serialized[1..message.encoded_len() + 1])?; + let msg_len_for_mac = serialized.len() - Self::MAC_LENGTH; + let mac = Self::compute_mac( + sender_identity_key, + receiver_identity_key, + mac_key, + &serialized[..msg_len_for_mac], + )?; + serialized[msg_len_for_mac..].copy_from_slice(&mac); + let serialized = serialized.into_boxed_slice(); + Ok(Self { + message_version, + sender_ratchet_key, + counter, + previous_counter, + ciphertext: ciphertext.into(), + serialized, + }) + } + + #[inline] + pub fn message_version(&self) -> u8 { + self.message_version + } + + #[inline] + pub fn sender_ratchet_key(&self) -> &PublicKey { + &self.sender_ratchet_key + } + + #[inline] + pub fn counter(&self) -> u32 { + self.counter + } + + #[inline] + pub fn serialized(&self) -> &[u8] { + &*self.serialized + } + + #[inline] + pub fn body(&self) -> &[u8] { + &*self.ciphertext + } + + pub fn verify_mac( + &self, + sender_identity_key: &IdentityKey, + receiver_identity_key: &IdentityKey, + mac_key: &[u8], + ) -> Result { + let our_mac = &Self::compute_mac( + sender_identity_key, + receiver_identity_key, + mac_key, + &self.serialized[..self.serialized.len() - Self::MAC_LENGTH], + )?; + let their_mac = &self.serialized[self.serialized.len() - Self::MAC_LENGTH..]; + let result: bool = our_mac.ct_eq(their_mac).into(); + if !result { + // A warning instead of an error because we try multiple sessions. + log::warn!( + "Bad Mac! Their Mac: {} Our Mac: {}", + hex::encode(their_mac), + hex::encode(our_mac) + ); + } + Ok(result) + } + + fn compute_mac( + sender_identity_key: &IdentityKey, + receiver_identity_key: &IdentityKey, + mac_key: &[u8], + message: &[u8], + ) -> Result<[u8; Self::MAC_LENGTH]> { + if mac_key.len() != 32 { + return Err(SignalProtocolError::InvalidMacKeyLength(mac_key.len())); + } + let mut mac = Hmac::::new_from_slice(mac_key) + .expect("HMAC-SHA256 should accept any size key"); + + mac.update(sender_identity_key.public_key().serialize().as_ref()); + mac.update(receiver_identity_key.public_key().serialize().as_ref()); + mac.update(message); + let mut result = [0u8; Self::MAC_LENGTH]; + result.copy_from_slice(&mac.finalize().into_bytes()[..Self::MAC_LENGTH]); + Ok(result) + } +} + +impl AsRef<[u8]> for SignalMessage { + fn as_ref(&self) -> &[u8] { + &*self.serialized + } +} + +impl TryFrom<&[u8]> for SignalMessage { + type Error = SignalProtocolError; + + fn try_from(value: &[u8]) -> Result { + if value.len() < SignalMessage::MAC_LENGTH + 1 { + return Err(SignalProtocolError::CiphertextMessageTooShort(value.len())); + } + let message_version = value[0] >> 4; + if message_version < CIPHERTEXT_MESSAGE_CURRENT_VERSION { + return Err(SignalProtocolError::LegacyCiphertextVersion( + message_version, + )); + } + if message_version > CIPHERTEXT_MESSAGE_CURRENT_VERSION { + return Err(SignalProtocolError::UnrecognizedCiphertextVersion( + message_version, + )); + } + + let proto_structure = + proto::wire::SignalMessage::decode(&value[1..value.len() - SignalMessage::MAC_LENGTH])?; + + let sender_ratchet_key = proto_structure + .ratchet_key + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let sender_ratchet_key = PublicKey::deserialize(&sender_ratchet_key)?; + let counter = proto_structure + .counter + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let previous_counter = proto_structure.previous_counter.unwrap_or(0); + let ciphertext = proto_structure + .ciphertext + .ok_or(SignalProtocolError::InvalidProtobufEncoding)? + .into_boxed_slice(); + + Ok(SignalMessage { + message_version, + sender_ratchet_key, + counter, + previous_counter, + ciphertext, + serialized: Box::from(value), + }) + } +} + +#[derive(Debug, Clone)] +pub struct PreKeySignalMessage { + message_version: u8, + registration_id: u32, + pre_key_id: Option, + signed_pre_key_id: u32, + base_key: PublicKey, + identity_key: IdentityKey, + message: SignalMessage, + serialized: Box<[u8]>, +} + +impl PreKeySignalMessage { + pub fn new( + message_version: u8, + registration_id: u32, + pre_key_id: Option, + signed_pre_key_id: u32, + base_key: PublicKey, + identity_key: IdentityKey, + message: SignalMessage, + ) -> Result { + let proto_message = proto::wire::PreKeySignalMessage { + registration_id: Some(registration_id), + pre_key_id, + signed_pre_key_id: Some(signed_pre_key_id), + base_key: Some(base_key.serialize().into_vec()), + identity_key: Some(identity_key.serialize().into_vec()), + message: Some(Vec::from(message.as_ref())), + }; + let mut serialized = vec![0u8; 1 + proto_message.encoded_len()]; + serialized[0] = ((message_version & 0xF) << 4) | CIPHERTEXT_MESSAGE_CURRENT_VERSION; + proto_message.encode(&mut &mut serialized[1..])?; + Ok(Self { + message_version, + registration_id, + pre_key_id, + signed_pre_key_id, + base_key, + identity_key, + message, + serialized: serialized.into_boxed_slice(), + }) + } + + #[inline] + pub fn message_version(&self) -> u8 { + self.message_version + } + + #[inline] + pub fn registration_id(&self) -> u32 { + self.registration_id + } + + #[inline] + pub fn pre_key_id(&self) -> Option { + self.pre_key_id + } + + #[inline] + pub fn signed_pre_key_id(&self) -> u32 { + self.signed_pre_key_id + } + + #[inline] + pub fn base_key(&self) -> &PublicKey { + &self.base_key + } + + #[inline] + pub fn identity_key(&self) -> &IdentityKey { + &self.identity_key + } + + #[inline] + pub fn message(&self) -> &SignalMessage { + &self.message + } + + #[inline] + pub fn serialized(&self) -> &[u8] { + &*self.serialized + } +} + +impl AsRef<[u8]> for PreKeySignalMessage { + fn as_ref(&self) -> &[u8] { + &*self.serialized + } +} + +impl TryFrom<&[u8]> for PreKeySignalMessage { + type Error = SignalProtocolError; + + fn try_from(value: &[u8]) -> Result { + if value.is_empty() { + return Err(SignalProtocolError::CiphertextMessageTooShort(value.len())); + } + + let message_version = value[0] >> 4; + if message_version < CIPHERTEXT_MESSAGE_CURRENT_VERSION { + return Err(SignalProtocolError::LegacyCiphertextVersion( + message_version, + )); + } + if message_version > CIPHERTEXT_MESSAGE_CURRENT_VERSION { + return Err(SignalProtocolError::UnrecognizedCiphertextVersion( + message_version, + )); + } + + let proto_structure = proto::wire::PreKeySignalMessage::decode(&value[1..])?; + + let base_key = proto_structure + .base_key + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let identity_key = proto_structure + .identity_key + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let message = proto_structure + .message + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let signed_pre_key_id = proto_structure + .signed_pre_key_id + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + + let base_key = PublicKey::deserialize(base_key.as_ref())?; + + Ok(PreKeySignalMessage { + message_version, + registration_id: proto_structure.registration_id.unwrap_or(0), + pre_key_id: proto_structure.pre_key_id, + signed_pre_key_id, + base_key, + identity_key: IdentityKey::try_from(identity_key.as_ref())?, + message: SignalMessage::try_from(message.as_ref())?, + serialized: Box::from(value), + }) + } +} + +#[derive(Debug, Clone)] +pub struct SenderKeyMessage { + message_version: u8, + distribution_id: Uuid, + chain_id: u32, + iteration: u32, + ciphertext: Box<[u8]>, + serialized: Box<[u8]>, +} + +impl SenderKeyMessage { + const SIGNATURE_LEN: usize = 64; + + pub fn new( + message_version: u8, + distribution_id: Uuid, + chain_id: u32, + iteration: u32, + ciphertext: Box<[u8]>, + csprng: &mut R, + signature_key: &PrivateKey, + ) -> Result { + let proto_message = proto::wire::SenderKeyMessage { + distribution_uuid: Some(distribution_id.as_bytes().to_vec()), + chain_id: Some(chain_id), + iteration: Some(iteration), + ciphertext: Some(ciphertext.to_vec()), + }; + let proto_message_len = proto_message.encoded_len(); + let mut serialized = vec![0u8; 1 + proto_message_len + Self::SIGNATURE_LEN]; + serialized[0] = ((message_version & 0xF) << 4) | SENDERKEY_MESSAGE_CURRENT_VERSION; + proto_message.encode(&mut &mut serialized[1..1 + proto_message_len])?; + let signature = + signature_key.calculate_signature(&serialized[..1 + proto_message_len], csprng)?; + serialized[1 + proto_message_len..].copy_from_slice(&signature[..]); + Ok(Self { + message_version: SENDERKEY_MESSAGE_CURRENT_VERSION, + distribution_id, + chain_id, + iteration, + ciphertext, + serialized: serialized.into_boxed_slice(), + }) + } + + pub fn verify_signature(&self, signature_key: &PublicKey) -> Result { + let valid = signature_key.verify_signature( + &self.serialized[..self.serialized.len() - Self::SIGNATURE_LEN], + &self.serialized[self.serialized.len() - Self::SIGNATURE_LEN..], + )?; + + Ok(valid) + } + + #[inline] + pub fn message_version(&self) -> u8 { + self.message_version + } + + #[inline] + pub fn distribution_id(&self) -> Uuid { + self.distribution_id + } + + #[inline] + pub fn chain_id(&self) -> u32 { + self.chain_id + } + + #[inline] + pub fn iteration(&self) -> u32 { + self.iteration + } + + #[inline] + pub fn ciphertext(&self) -> &[u8] { + &*self.ciphertext + } + + #[inline] + pub fn serialized(&self) -> &[u8] { + &*self.serialized + } +} + +impl AsRef<[u8]> for SenderKeyMessage { + fn as_ref(&self) -> &[u8] { + &*self.serialized + } +} + +impl TryFrom<&[u8]> for SenderKeyMessage { + type Error = SignalProtocolError; + + fn try_from(value: &[u8]) -> Result { + if value.len() < 1 + Self::SIGNATURE_LEN { + return Err(SignalProtocolError::CiphertextMessageTooShort(value.len())); + } + let message_version = value[0] >> 4; + if message_version < SENDERKEY_MESSAGE_CURRENT_VERSION { + return Err(SignalProtocolError::LegacyCiphertextVersion( + message_version, + )); + } + if message_version > SENDERKEY_MESSAGE_CURRENT_VERSION { + return Err(SignalProtocolError::UnrecognizedCiphertextVersion( + message_version, + )); + } + let proto_structure = + proto::wire::SenderKeyMessage::decode(&value[1..value.len() - Self::SIGNATURE_LEN])?; + + let distribution_id = proto_structure + .distribution_uuid + .and_then(|bytes| Uuid::from_slice(bytes.as_slice()).ok()) + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let chain_id = proto_structure + .chain_id + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let iteration = proto_structure + .iteration + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let ciphertext = proto_structure + .ciphertext + .ok_or(SignalProtocolError::InvalidProtobufEncoding)? + .into_boxed_slice(); + + Ok(SenderKeyMessage { + message_version, + distribution_id, + chain_id, + iteration, + ciphertext, + serialized: Box::from(value), + }) + } +} + +#[derive(Debug, Clone)] +pub struct SenderKeyDistributionMessage { + message_version: u8, + distribution_id: Uuid, + chain_id: u32, + iteration: u32, + chain_key: Vec, + signing_key: PublicKey, + serialized: Box<[u8]>, +} + +impl SenderKeyDistributionMessage { + pub fn new( + message_version: u8, + distribution_id: Uuid, + chain_id: u32, + iteration: u32, + chain_key: Vec, + signing_key: PublicKey, + ) -> Result { + let proto_message = proto::wire::SenderKeyDistributionMessage { + distribution_uuid: Some(distribution_id.as_bytes().to_vec()), + chain_id: Some(chain_id), + iteration: Some(iteration), + chain_key: Some(chain_key.clone()), + signing_key: Some(signing_key.serialize().to_vec()), + }; + let mut serialized = vec![0u8; 1 + proto_message.encoded_len()]; + serialized[0] = ((message_version & 0xF) << 4) | SENDERKEY_MESSAGE_CURRENT_VERSION; + proto_message.encode(&mut &mut serialized[1..])?; + + Ok(Self { + message_version, + distribution_id, + chain_id, + iteration, + chain_key, + signing_key, + serialized: serialized.into_boxed_slice(), + }) + } + + #[inline] + pub fn message_version(&self) -> u8 { + self.message_version + } + + #[inline] + pub fn distribution_id(&self) -> Result { + Ok(self.distribution_id) + } + + #[inline] + pub fn chain_id(&self) -> Result { + Ok(self.chain_id) + } + + #[inline] + pub fn iteration(&self) -> Result { + Ok(self.iteration) + } + + #[inline] + pub fn chain_key(&self) -> Result<&[u8]> { + Ok(&self.chain_key) + } + + #[inline] + pub fn signing_key(&self) -> Result<&PublicKey> { + Ok(&self.signing_key) + } + + #[inline] + pub fn serialized(&self) -> &[u8] { + &*self.serialized + } +} + +impl AsRef<[u8]> for SenderKeyDistributionMessage { + fn as_ref(&self) -> &[u8] { + &*self.serialized + } +} + +impl TryFrom<&[u8]> for SenderKeyDistributionMessage { + type Error = SignalProtocolError; + + fn try_from(value: &[u8]) -> Result { + // The message contains at least a X25519 key and a chain key + if value.len() < 1 + 32 + 32 { + return Err(SignalProtocolError::CiphertextMessageTooShort(value.len())); + } + + let message_version = value[0] >> 4; + + if message_version < SENDERKEY_MESSAGE_CURRENT_VERSION { + return Err(SignalProtocolError::LegacyCiphertextVersion( + message_version, + )); + } + if message_version > SENDERKEY_MESSAGE_CURRENT_VERSION { + return Err(SignalProtocolError::UnrecognizedCiphertextVersion( + message_version, + )); + } + + let proto_structure = proto::wire::SenderKeyDistributionMessage::decode(&value[1..])?; + + let distribution_id = proto_structure + .distribution_uuid + .and_then(|bytes| Uuid::from_slice(bytes.as_slice()).ok()) + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let chain_id = proto_structure + .chain_id + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let iteration = proto_structure + .iteration + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let chain_key = proto_structure + .chain_key + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let signing_key = proto_structure + .signing_key + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + + if chain_key.len() != 32 || signing_key.len() != 33 { + return Err(SignalProtocolError::InvalidProtobufEncoding); + } + + let signing_key = PublicKey::deserialize(&signing_key)?; + + Ok(SenderKeyDistributionMessage { + message_version, + distribution_id, + chain_id, + iteration, + chain_key, + signing_key, + serialized: Box::from(value), + }) + } +} + +#[derive(Debug, Clone)] +pub struct PlaintextContent { + serialized: Box<[u8]>, +} + +impl PlaintextContent { + /// Identifies a serialized PlaintextContent. + /// + /// This ensures someone doesn't try to serialize an arbitrary Content message as + /// PlaintextContent; only messages that are okay to send as plaintext should be allowed. + const PLAINTEXT_CONTEXT_IDENTIFIER_BYTE: u8 = 0xC0; + + /// Marks the end of a message and the start of any padding. + /// + /// Usually messages are padded to avoid exposing patterns, + /// but PlaintextContent messages are all fixed-length anyway, so there won't be any padding. + const PADDING_BOUNDARY_BYTE: u8 = 0x80; + + #[inline] + pub fn body(&self) -> &[u8] { + &self.serialized[1..] + } + + #[inline] + pub fn serialized(&self) -> &[u8] { + &self.serialized + } +} + +impl From for PlaintextContent { + fn from(message: DecryptionErrorMessage) -> Self { + let proto_structure = proto::service::Content { + decryption_error_message: Some(message.serialized().to_vec()), + ..Default::default() + }; + let mut serialized = vec![Self::PLAINTEXT_CONTEXT_IDENTIFIER_BYTE]; + proto_structure + .encode(&mut serialized) + .expect("can always encode to a Vec"); + serialized.push(Self::PADDING_BOUNDARY_BYTE); + Self { + serialized: Box::from(serialized), + } + } +} + +impl TryFrom<&[u8]> for PlaintextContent { + type Error = SignalProtocolError; + + fn try_from(value: &[u8]) -> Result { + if value.is_empty() { + return Err(SignalProtocolError::CiphertextMessageTooShort(0)); + } + if value[0] != Self::PLAINTEXT_CONTEXT_IDENTIFIER_BYTE { + return Err(SignalProtocolError::UnrecognizedMessageVersion( + value[0] as u32, + )); + } + Ok(Self { + serialized: Box::from(value), + }) + } +} + +#[derive(Debug, Clone)] +pub struct DecryptionErrorMessage { + ratchet_key: Option, + timestamp: u64, + device_id: u32, + serialized: Box<[u8]>, +} + +impl DecryptionErrorMessage { + pub fn for_original( + original_bytes: &[u8], + original_type: CiphertextMessageType, + original_timestamp: u64, + original_sender_device_id: u32, + ) -> Result { + let ratchet_key = match original_type { + CiphertextMessageType::Whisper => { + Some(*SignalMessage::try_from(original_bytes)?.sender_ratchet_key()) + } + CiphertextMessageType::PreKey => Some( + *PreKeySignalMessage::try_from(original_bytes)? + .message() + .sender_ratchet_key(), + ), + CiphertextMessageType::SenderKey => None, + CiphertextMessageType::Plaintext => { + return Err(SignalProtocolError::InvalidArgument( + "cannot create a DecryptionErrorMessage for plaintext content; it is not encrypted".to_string() + )); + } + }; + + let proto_message = proto::service::DecryptionErrorMessage { + timestamp: Some(original_timestamp), + ratchet_key: ratchet_key.map(|k| k.serialize().into()), + device_id: Some(original_sender_device_id), + }; + let mut serialized = Vec::new(); + proto_message.encode(&mut serialized)?; + + Ok(Self { + ratchet_key, + timestamp: original_timestamp, + device_id: original_sender_device_id, + serialized: serialized.into_boxed_slice(), + }) + } + + #[inline] + pub fn timestamp(&self) -> u64 { + self.timestamp + } + + #[inline] + pub fn ratchet_key(&self) -> Option<&PublicKey> { + self.ratchet_key.as_ref() + } + + #[inline] + pub fn device_id(&self) -> u32 { + self.device_id + } + + #[inline] + pub fn serialized(&self) -> &[u8] { + &self.serialized + } +} + +impl TryFrom<&[u8]> for DecryptionErrorMessage { + type Error = SignalProtocolError; + + fn try_from(value: &[u8]) -> Result { + let proto_structure = proto::service::DecryptionErrorMessage::decode(value)?; + let timestamp = proto_structure + .timestamp + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let ratchet_key = proto_structure + .ratchet_key + .map(|k| PublicKey::deserialize(&k)) + .transpose()?; + let device_id = proto_structure.device_id.unwrap_or_default(); + Ok(Self { + timestamp, + ratchet_key, + device_id, + serialized: Box::from(value), + }) + } +} + +/// For testing +pub fn extract_decryption_error_message_from_serialized_content( + bytes: &[u8], +) -> Result { + if bytes.last() != Some(&PlaintextContent::PADDING_BOUNDARY_BYTE) { + return Err(SignalProtocolError::InvalidProtobufEncoding); + } + let content = proto::service::Content::decode(bytes.split_last().expect("checked above").1)?; + content + .decryption_error_message + .as_deref() + .ok_or_else(|| { + SignalProtocolError::InvalidArgument( + "Content does not contain DecryptionErrorMessage".to_owned(), + ) + }) + .and_then(DecryptionErrorMessage::try_from) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::KeyPair; + + use rand::rngs::OsRng; + use rand::{CryptoRng, Rng}; + + fn create_signal_message(csprng: &mut T) -> Result + where + T: Rng + CryptoRng, + { + let mut mac_key = [0u8; 32]; + csprng.fill_bytes(&mut mac_key); + let mac_key = mac_key; + + let mut ciphertext = [0u8; 20]; + csprng.fill_bytes(&mut ciphertext); + let ciphertext = ciphertext; + + let sender_ratchet_key_pair = KeyPair::generate(csprng); + let sender_identity_key_pair = KeyPair::generate(csprng); + let receiver_identity_key_pair = KeyPair::generate(csprng); + + SignalMessage::new( + 3, + &mac_key, + sender_ratchet_key_pair.public_key, + 42, + 41, + &ciphertext, + &sender_identity_key_pair.public_key.into(), + &receiver_identity_key_pair.public_key.into(), + ) + } + + fn assert_signal_message_equals(m1: &SignalMessage, m2: &SignalMessage) { + assert_eq!(m1.message_version, m2.message_version); + assert_eq!(m1.sender_ratchet_key, m2.sender_ratchet_key); + assert_eq!(m1.counter, m2.counter); + assert_eq!(m1.previous_counter, m2.previous_counter); + assert_eq!(m1.ciphertext, m2.ciphertext); + assert_eq!(m1.serialized, m2.serialized); + } + + #[test] + fn test_signal_message_serialize_deserialize() -> Result<()> { + let mut csprng = OsRng; + let message = create_signal_message(&mut csprng)?; + let deser_message = + SignalMessage::try_from(message.as_ref()).expect("should deserialize without error"); + assert_signal_message_equals(&message, &deser_message); + Ok(()) + } + + #[test] + fn test_pre_key_signal_message_serialize_deserialize() -> Result<()> { + let mut csprng = OsRng; + let identity_key_pair = KeyPair::generate(&mut csprng); + let base_key_pair = KeyPair::generate(&mut csprng); + let message = create_signal_message(&mut csprng)?; + let pre_key_signal_message = PreKeySignalMessage::new( + 3, + 365, + None, + 97, + base_key_pair.public_key, + identity_key_pair.public_key.into(), + message, + )?; + let deser_pre_key_signal_message = + PreKeySignalMessage::try_from(pre_key_signal_message.as_ref()) + .expect("should deserialize without error"); + assert_eq!( + pre_key_signal_message.message_version, + deser_pre_key_signal_message.message_version + ); + assert_eq!( + pre_key_signal_message.registration_id, + deser_pre_key_signal_message.registration_id + ); + assert_eq!( + pre_key_signal_message.pre_key_id, + deser_pre_key_signal_message.pre_key_id + ); + assert_eq!( + pre_key_signal_message.signed_pre_key_id, + deser_pre_key_signal_message.signed_pre_key_id + ); + assert_eq!( + pre_key_signal_message.base_key, + deser_pre_key_signal_message.base_key + ); + assert_eq!( + pre_key_signal_message.identity_key.public_key(), + deser_pre_key_signal_message.identity_key.public_key() + ); + assert_signal_message_equals( + &pre_key_signal_message.message, + &deser_pre_key_signal_message.message, + ); + assert_eq!( + pre_key_signal_message.serialized, + deser_pre_key_signal_message.serialized + ); + Ok(()) + } + + #[test] + fn test_sender_key_message_serialize_deserialize() -> Result<()> { + let mut csprng = OsRng; + let signature_key_pair = KeyPair::generate(&mut csprng); + let sender_key_message = SenderKeyMessage::new( + SENDERKEY_MESSAGE_CURRENT_VERSION, + Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6), + 42, + 7, + [1u8, 2, 3].into(), + &mut csprng, + &signature_key_pair.private_key, + )?; + let deser_sender_key_message = SenderKeyMessage::try_from(sender_key_message.as_ref()) + .expect("should deserialize without error"); + assert_eq!( + sender_key_message.message_version, + deser_sender_key_message.message_version + ); + assert_eq!( + sender_key_message.chain_id, + deser_sender_key_message.chain_id + ); + assert_eq!( + sender_key_message.iteration, + deser_sender_key_message.iteration + ); + assert_eq!( + sender_key_message.ciphertext, + deser_sender_key_message.ciphertext + ); + assert_eq!( + sender_key_message.serialized, + deser_sender_key_message.serialized + ); + Ok(()) + } + + #[test] + fn test_decryption_error_message() -> Result<()> { + let mut csprng = OsRng; + let identity_key_pair = KeyPair::generate(&mut csprng); + let base_key_pair = KeyPair::generate(&mut csprng); + let message = create_signal_message(&mut csprng)?; + let timestamp = 0x2_0000_0001; + let device_id = 0x8086_2021; + + { + let error_message = DecryptionErrorMessage::for_original( + message.serialized(), + CiphertextMessageType::Whisper, + timestamp, + device_id, + )?; + let error_message = DecryptionErrorMessage::try_from(error_message.serialized())?; + assert_eq!( + error_message.ratchet_key(), + Some(message.sender_ratchet_key()) + ); + assert_eq!(error_message.timestamp(), timestamp); + assert_eq!(error_message.device_id(), device_id); + } + + let pre_key_signal_message = PreKeySignalMessage::new( + 3, + 365, + None, + 97, + base_key_pair.public_key, + identity_key_pair.public_key.into(), + message, + )?; + + { + let error_message = DecryptionErrorMessage::for_original( + pre_key_signal_message.serialized(), + CiphertextMessageType::PreKey, + timestamp, + device_id, + )?; + let error_message = DecryptionErrorMessage::try_from(error_message.serialized())?; + assert_eq!( + error_message.ratchet_key(), + Some(pre_key_signal_message.message().sender_ratchet_key()) + ); + assert_eq!(error_message.timestamp(), timestamp); + assert_eq!(error_message.device_id(), device_id); + } + + let sender_key_message = SenderKeyMessage::new( + 3, + Uuid::nil(), + 1, + 2, + Box::from(b"test".to_owned()), + &mut csprng, + &base_key_pair.private_key, + )?; + + { + let error_message = DecryptionErrorMessage::for_original( + sender_key_message.serialized(), + CiphertextMessageType::SenderKey, + timestamp, + device_id, + )?; + let error_message = DecryptionErrorMessage::try_from(error_message.serialized())?; + assert_eq!(error_message.ratchet_key(), None); + assert_eq!(error_message.timestamp(), timestamp); + assert_eq!(error_message.device_id(), device_id); + } + + Ok(()) + } + + #[test] + fn test_decryption_error_message_for_plaintext() { + assert!(matches!( + DecryptionErrorMessage::for_original(&[], CiphertextMessageType::Plaintext, 5, 7), + Err(SignalProtocolError::InvalidArgument(_)) + )); + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/ratchet.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/ratchet.rs new file mode 100644 index 0000000..2d91fee --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/ratchet.rs @@ -0,0 +1,168 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +mod keys; +mod params; + +pub use self::keys::{ChainKey, MessageKeys, RootKey}; +pub use self::params::{AliceSignalProtocolParameters, BobSignalProtocolParameters}; +use crate::proto::storage::SessionStructure; +use crate::protocol::CIPHERTEXT_MESSAGE_CURRENT_VERSION; +use crate::state::SessionState; +use crate::{KeyPair, Result, SessionRecord}; +use rand::{CryptoRng, Rng}; + +fn derive_keys(secret_input: &[u8]) -> Result<(RootKey, ChainKey)> { + let mut secrets = [0; 64]; + hkdf::Hkdf::::new(None, secret_input) + .expand(b"WhisperText", &mut secrets) + .expect("valid length"); + + let root_key = RootKey::new(&secrets[0..32])?; + let chain_key = ChainKey::new(&secrets[32..64], 0)?; + + Ok((root_key, chain_key)) +} + +pub(crate) fn initialize_alice_session( + parameters: &AliceSignalProtocolParameters, + mut csprng: &mut R, +) -> Result { + let local_identity = parameters.our_identity_key_pair().identity_key(); + + let sending_ratchet_key = KeyPair::generate(&mut csprng); + + let mut secrets = Vec::with_capacity(32 * 5); + + secrets.extend_from_slice(&[0xFFu8; 32]); // "discontinuity bytes" + + let our_base_private_key = parameters.our_base_key_pair().private_key; + + secrets.extend_from_slice( + ¶meters + .our_identity_key_pair() + .private_key() + .calculate_agreement(parameters.their_signed_pre_key())?, + ); + + secrets.extend_from_slice( + &our_base_private_key.calculate_agreement(parameters.their_identity_key().public_key())?, + ); + + secrets.extend_from_slice( + &our_base_private_key.calculate_agreement(parameters.their_signed_pre_key())?, + ); + + if let Some(their_one_time_prekey) = parameters.their_one_time_pre_key() { + secrets + .extend_from_slice(&our_base_private_key.calculate_agreement(their_one_time_prekey)?); + } + + let (root_key, chain_key) = derive_keys(&secrets)?; + + let (sending_chain_root_key, sending_chain_chain_key) = root_key.create_chain( + parameters.their_ratchet_key(), + &sending_ratchet_key.private_key, + )?; + + let session = SessionStructure { + session_version: CIPHERTEXT_MESSAGE_CURRENT_VERSION as u32, + local_identity_public: local_identity.public_key().serialize().to_vec(), + remote_identity_public: parameters.their_identity_key().serialize().to_vec(), + root_key: sending_chain_root_key.key().to_vec(), + previous_counter: 0, + sender_chain: None, + receiver_chains: vec![], + pending_pre_key: None, + remote_registration_id: 0, + local_registration_id: 0, + needs_refresh: false, + alice_base_key: vec![], + }; + + let mut session = SessionState::new(session); + + session.add_receiver_chain(parameters.their_ratchet_key(), &chain_key)?; + session.set_sender_chain(&sending_ratchet_key, &sending_chain_chain_key)?; + + Ok(session) +} + +pub(crate) fn initialize_bob_session( + parameters: &BobSignalProtocolParameters, +) -> Result { + let local_identity = parameters.our_identity_key_pair().identity_key(); + + let mut secrets = Vec::with_capacity(32 * 5); + + secrets.extend_from_slice(&[0xFFu8; 32]); // "discontinuity bytes" + + secrets.extend_from_slice( + ¶meters + .our_signed_pre_key_pair() + .private_key + .calculate_agreement(parameters.their_identity_key().public_key())?, + ); + + secrets.extend_from_slice( + ¶meters + .our_identity_key_pair() + .private_key() + .calculate_agreement(parameters.their_base_key())?, + ); + + secrets.extend_from_slice( + ¶meters + .our_signed_pre_key_pair() + .private_key + .calculate_agreement(parameters.their_base_key())?, + ); + + if let Some(our_one_time_pre_key_pair) = parameters.our_one_time_pre_key_pair() { + secrets.extend_from_slice( + &our_one_time_pre_key_pair + .private_key + .calculate_agreement(parameters.their_base_key())?, + ); + } + + let (root_key, chain_key) = derive_keys(&secrets)?; + + let session = SessionStructure { + session_version: CIPHERTEXT_MESSAGE_CURRENT_VERSION as u32, + local_identity_public: local_identity.public_key().serialize().to_vec(), + remote_identity_public: parameters.their_identity_key().serialize().to_vec(), + root_key: root_key.key().to_vec(), + previous_counter: 0, + sender_chain: None, + receiver_chains: vec![], + pending_pre_key: None, + remote_registration_id: 0, + local_registration_id: 0, + needs_refresh: false, + alice_base_key: vec![], + }; + + let mut session = SessionState::new(session); + + session.set_sender_chain(parameters.our_ratchet_key_pair(), &chain_key)?; + + Ok(session) +} + +pub fn initialize_alice_session_record( + parameters: &AliceSignalProtocolParameters, + csprng: &mut R, +) -> Result { + Ok(SessionRecord::new(initialize_alice_session( + parameters, csprng, + )?)) +} + +pub fn initialize_bob_session_record( + parameters: &BobSignalProtocolParameters, +) -> Result { + Ok(SessionRecord::new(initialize_bob_session(parameters)?)) +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/ratchet/keys.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/ratchet/keys.rs new file mode 100644 index 0000000..310df3c --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/ratchet/keys.rs @@ -0,0 +1,210 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use arrayref::array_ref; + +use crate::crypto; +use crate::{PrivateKey, PublicKey, Result, SignalProtocolError}; +use std::fmt; + +pub struct MessageKeys { + cipher_key: [u8; 32], + mac_key: [u8; 32], + iv: [u8; 16], + counter: u32, +} + +impl MessageKeys { + pub fn derive_keys(input_key_material: &[u8], counter: u32) -> Result { + let mut okm = [0; 80]; + hkdf::Hkdf::::new(None, input_key_material) + .expand(b"WhisperMessageKeys", &mut okm) + .expect("valid output length"); + + Ok(MessageKeys { + cipher_key: *array_ref![okm, 0, 32], + mac_key: *array_ref![okm, 32, 32], + iv: *array_ref![okm, 64, 16], + counter, + }) + } + + pub fn new(cipher_key: &[u8], mac_key: &[u8], iv: &[u8], counter: u32) -> Result { + if mac_key.len() != 32 { + return Err(SignalProtocolError::InvalidMacKeyLength(mac_key.len())); + } + if cipher_key.len() != 32 || iv.len() != 16 { + return Err(SignalProtocolError::InvalidCipherCryptographicParameters( + cipher_key.len(), + iv.len(), + )); + } + + Ok(MessageKeys { + cipher_key: *array_ref![cipher_key, 0, 32], + mac_key: *array_ref![mac_key, 0, 32], + iv: *array_ref![iv, 0, 16], + counter, + }) + } + + #[inline] + pub fn cipher_key(&self) -> &[u8; 32] { + &self.cipher_key + } + + #[inline] + pub fn mac_key(&self) -> &[u8; 32] { + &self.mac_key + } + + #[inline] + pub fn iv(&self) -> &[u8; 16] { + &self.iv + } + + #[inline] + pub fn counter(&self) -> u32 { + self.counter + } +} + +#[derive(Clone, Debug)] +pub struct ChainKey { + key: [u8; 32], + index: u32, +} + +impl ChainKey { + const MESSAGE_KEY_SEED: [u8; 1] = [0x01u8]; + const CHAIN_KEY_SEED: [u8; 1] = [0x02u8]; + + pub fn new(key: &[u8], index: u32) -> Result { + if key.len() != 32 { + return Err(SignalProtocolError::InvalidChainKeyLength(key.len())); + } + + Ok(Self { + key: *array_ref![key, 0, 32], + index, + }) + } + + #[inline] + pub fn key(&self) -> &[u8; 32] { + &self.key + } + + #[inline] + pub fn index(&self) -> u32 { + self.index + } + + pub fn next_chain_key(&self) -> Result { + Ok(Self { + key: self.calculate_base_material(Self::CHAIN_KEY_SEED)?, + index: self.index + 1, + }) + } + + pub fn message_keys(&self) -> Result { + MessageKeys::derive_keys( + &self.calculate_base_material(Self::MESSAGE_KEY_SEED)?, + self.index, + ) + } + + fn calculate_base_material(&self, seed: [u8; 1]) -> Result<[u8; 32]> { + crypto::hmac_sha256(&self.key, &seed) + } +} + +#[derive(Clone, Debug)] +pub struct RootKey { + key: [u8; 32], +} + +impl RootKey { + pub fn new(key: &[u8]) -> Result { + if key.len() != 32 { + return Err(SignalProtocolError::InvalidRootKeyLength(key.len())); + } + Ok(Self { + key: *array_ref![key, 0, 32], + }) + } + + pub fn key(&self) -> &[u8; 32] { + &self.key + } + + pub fn create_chain( + &self, + their_ratchet_key: &PublicKey, + our_ratchet_key: &PrivateKey, + ) -> Result<(RootKey, ChainKey)> { + let shared_secret = our_ratchet_key.calculate_agreement(their_ratchet_key)?; + let mut derived_secret_bytes = [0; 64]; + hkdf::Hkdf::::new(Some(&self.key), &shared_secret) + .expand(b"WhisperRatchet", &mut derived_secret_bytes) + .expect("valid output length"); + + Ok(( + RootKey { + key: *array_ref![derived_secret_bytes, 0, 32], + }, + ChainKey { + key: *array_ref![derived_secret_bytes, 32, 32], + index: 0, + }, + )) + } +} + +impl fmt::Display for RootKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", hex::encode(self.key)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_chain_key_derivation() -> Result<()> { + let seed = [ + 0x8au8, 0xb7, 0x2d, 0x6f, 0x4c, 0xc5, 0xac, 0x0d, 0x38, 0x7e, 0xaf, 0x46, 0x33, 0x78, + 0xdd, 0xb2, 0x8e, 0xdd, 0x07, 0x38, 0x5b, 0x1c, 0xb0, 0x12, 0x50, 0xc7, 0x15, 0x98, + 0x2e, 0x7a, 0xd4, 0x8f, + ]; + let message_key = [ + 0xbfu8, 0x51, 0xe9, 0xd7, 0x5e, 0x0e, 0x31, 0x03, 0x10, 0x51, 0xf8, 0x2a, 0x24, 0x91, + 0xff, 0xc0, 0x84, 0xfa, 0x29, 0x8b, 0x77, 0x93, 0xbd, 0x9d, 0xb6, 0x20, 0x05, 0x6f, + 0xeb, 0xf4, 0x52, 0x17, + ]; + let mac_key = [ + 0xc6u8, 0xc7, 0x7d, 0x6a, 0x73, 0xa3, 0x54, 0x33, 0x7a, 0x56, 0x43, 0x5e, 0x34, 0x60, + 0x7d, 0xfe, 0x48, 0xe3, 0xac, 0xe1, 0x4e, 0x77, 0x31, 0x4d, 0xc6, 0xab, 0xc1, 0x72, + 0xe7, 0xa7, 0x03, 0x0b, + ]; + let next_chain_key = [ + 0x28u8, 0xe8, 0xf8, 0xfe, 0xe5, 0x4b, 0x80, 0x1e, 0xef, 0x7c, 0x5c, 0xfb, 0x2f, 0x17, + 0xf3, 0x2c, 0x7b, 0x33, 0x44, 0x85, 0xbb, 0xb7, 0x0f, 0xac, 0x6e, 0xc1, 0x03, 0x42, + 0xa2, 0x46, 0xd1, 0x5d, + ]; + + let chain_key = ChainKey::new(&seed, 0)?; + assert_eq!(&seed, chain_key.key()); + assert_eq!(&message_key, chain_key.message_keys()?.cipher_key()); + assert_eq!(&mac_key, chain_key.message_keys()?.mac_key()); + assert_eq!(&next_chain_key, chain_key.next_chain_key()?.key()); + assert_eq!(0, chain_key.index()); + assert_eq!(0, chain_key.message_keys()?.counter()); + assert_eq!(1, chain_key.next_chain_key()?.index()); + assert_eq!(1, chain_key.next_chain_key()?.message_keys()?.counter()); + Ok(()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/ratchet/params.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/ratchet/params.rs new file mode 100644 index 0000000..b6144b5 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/ratchet/params.rs @@ -0,0 +1,126 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::{IdentityKey, IdentityKeyPair, KeyPair, PublicKey}; + +pub struct AliceSignalProtocolParameters { + our_identity_key_pair: IdentityKeyPair, + our_base_key_pair: KeyPair, + + their_identity_key: IdentityKey, + their_signed_pre_key: PublicKey, + their_one_time_pre_key: Option, + their_ratchet_key: PublicKey, +} + +impl AliceSignalProtocolParameters { + pub fn new( + our_identity_key_pair: IdentityKeyPair, + our_base_key_pair: KeyPair, + their_identity_key: IdentityKey, + their_signed_pre_key: PublicKey, + their_one_time_pre_key: Option, + their_ratchet_key: PublicKey, + ) -> Self { + Self { + our_identity_key_pair, + our_base_key_pair, + their_identity_key, + their_signed_pre_key, + their_one_time_pre_key, + their_ratchet_key, + } + } + + #[inline] + pub fn our_identity_key_pair(&self) -> &IdentityKeyPair { + &self.our_identity_key_pair + } + + #[inline] + pub fn our_base_key_pair(&self) -> &KeyPair { + &self.our_base_key_pair + } + + #[inline] + pub fn their_identity_key(&self) -> &IdentityKey { + &self.their_identity_key + } + + #[inline] + pub fn their_signed_pre_key(&self) -> &PublicKey { + &self.their_signed_pre_key + } + + #[inline] + pub fn their_one_time_pre_key(&self) -> Option<&PublicKey> { + self.their_one_time_pre_key.as_ref() + } + + #[inline] + pub fn their_ratchet_key(&self) -> &PublicKey { + &self.their_ratchet_key + } +} + +pub struct BobSignalProtocolParameters { + our_identity_key_pair: IdentityKeyPair, + our_signed_pre_key_pair: KeyPair, + our_one_time_pre_key_pair: Option, + our_ratchet_key_pair: KeyPair, + + their_identity_key: IdentityKey, + their_base_key: PublicKey, +} + +impl BobSignalProtocolParameters { + pub fn new( + our_identity_key_pair: IdentityKeyPair, + our_signed_pre_key_pair: KeyPair, + our_one_time_pre_key_pair: Option, + our_ratchet_key_pair: KeyPair, + their_identity_key: IdentityKey, + their_base_key: PublicKey, + ) -> Self { + Self { + our_identity_key_pair, + our_signed_pre_key_pair, + our_one_time_pre_key_pair, + our_ratchet_key_pair, + their_identity_key, + their_base_key, + } + } + + #[inline] + pub fn our_identity_key_pair(&self) -> &IdentityKeyPair { + &self.our_identity_key_pair + } + + #[inline] + pub fn our_signed_pre_key_pair(&self) -> &KeyPair { + &self.our_signed_pre_key_pair + } + + #[inline] + pub fn our_one_time_pre_key_pair(&self) -> Option<&KeyPair> { + self.our_one_time_pre_key_pair.as_ref() + } + + #[inline] + pub fn our_ratchet_key_pair(&self) -> &KeyPair { + &self.our_ratchet_key_pair + } + + #[inline] + pub fn their_identity_key(&self) -> &IdentityKey { + &self.their_identity_key + } + + #[inline] + pub fn their_base_key(&self) -> &PublicKey { + &self.their_base_key + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/sealed_sender.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/sealed_sender.rs new file mode 100644 index 0000000..8cf43bc --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/sealed_sender.rs @@ -0,0 +1,1712 @@ +// +// Copyright 2020-2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::{ + message_encrypt, CiphertextMessageType, Context, Direction, IdentityKey, IdentityKeyPair, + IdentityKeyStore, KeyPair, PreKeySignalMessage, PreKeyStore, PrivateKey, ProtocolAddress, + PublicKey, Result, SessionRecord, SessionStore, SignalMessage, SignalProtocolError, + SignedPreKeyStore, +}; + +use crate::crypto; +use crate::curve; +use crate::proto; +use crate::session_cipher; + +use aes_gcm_siv::aead::{AeadInPlace, NewAead}; +use aes_gcm_siv::Aes256GcmSiv; +use arrayref::array_ref; +use curve25519_dalek::scalar::Scalar; +use prost::Message; +use rand::{CryptoRng, Rng}; +use subtle::ConstantTimeEq; +use uuid::Uuid; + +use proto::sealed_sender::unidentified_sender_message::message::Type as ProtoMessageType; + +use std::convert::{TryFrom, TryInto}; + +#[derive(Debug, Clone)] +pub struct ServerCertificate { + serialized: Vec, + key_id: u32, + key: PublicKey, + certificate: Vec, + signature: Vec, +} + +/* +0xDEADC357 is a server certificate ID which is used to test the +revocation logic. As of this writing, no prod server certificates have +been revoked. If one ever does, add its key ID here. + +If a production server certificate is ever generated which collides +with this test certificate ID, Bad Things will happen. +*/ +const REVOKED_SERVER_CERTIFICATE_KEY_IDS: &[u32] = &[0xDEADC357]; + +impl ServerCertificate { + pub fn deserialize(data: &[u8]) -> Result { + let pb = proto::sealed_sender::ServerCertificate::decode(data)?; + + if pb.certificate.is_none() || pb.signature.is_none() { + return Err(SignalProtocolError::InvalidProtobufEncoding); + } + + let certificate = pb + .certificate + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let signature = pb + .signature + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let certificate_data = + proto::sealed_sender::server_certificate::Certificate::decode(certificate.as_ref())?; + let key = PublicKey::try_from( + &certificate_data + .key + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?[..], + )?; + let key_id = certificate_data + .id + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + + Ok(Self { + serialized: data.to_vec(), + certificate, + signature, + key, + key_id, + }) + } + + pub fn new( + key_id: u32, + key: PublicKey, + trust_root: &PrivateKey, + rng: &mut R, + ) -> Result { + let certificate_pb = proto::sealed_sender::server_certificate::Certificate { + id: Some(key_id), + key: Some(key.serialize().to_vec()), + }; + + let certificate = certificate_pb.encode_to_vec(); + + let signature = trust_root.calculate_signature(&certificate, rng)?.to_vec(); + + let serialized = proto::sealed_sender::ServerCertificate { + certificate: Some(certificate.clone()), + signature: Some(signature.clone()), + } + .encode_to_vec(); + + Ok(Self { + serialized, + certificate, + signature, + key, + key_id, + }) + } + + pub(crate) fn to_protobuf(&self) -> Result { + Ok(proto::sealed_sender::ServerCertificate { + certificate: Some(self.certificate.clone()), + signature: Some(self.signature.clone()), + }) + } + + pub fn validate(&self, trust_root: &PublicKey) -> Result { + if REVOKED_SERVER_CERTIFICATE_KEY_IDS.contains(&self.key_id()?) { + log::error!( + "received server certificate with revoked ID {:x}", + self.key_id()? + ); + return Ok(false); + } + trust_root.verify_signature(&self.certificate, &self.signature) + } + + pub fn key_id(&self) -> Result { + Ok(self.key_id) + } + + pub fn public_key(&self) -> Result { + Ok(self.key) + } + + pub fn certificate(&self) -> Result<&[u8]> { + Ok(&self.certificate) + } + + pub fn signature(&self) -> Result<&[u8]> { + Ok(&self.signature) + } + + pub fn serialized(&self) -> Result<&[u8]> { + Ok(&self.serialized) + } +} + +#[derive(Debug, Clone)] +pub struct SenderCertificate { + signer: ServerCertificate, + key: PublicKey, + sender_device_id: u32, + sender_uuid: String, + sender_e164: Option, + expiration: u64, + serialized: Vec, + certificate: Vec, + signature: Vec, +} + +impl SenderCertificate { + pub fn deserialize(data: &[u8]) -> Result { + let pb = proto::sealed_sender::SenderCertificate::decode(data)?; + let certificate = pb + .certificate + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let signature = pb + .signature + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let certificate_data = + proto::sealed_sender::sender_certificate::Certificate::decode(certificate.as_ref())?; + + let sender_device_id = certificate_data + .sender_device + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let expiration = certificate_data + .expires + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let signer_pb = certificate_data + .signer + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let sender_uuid = certificate_data + .sender_uuid + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let sender_e164 = certificate_data.sender_e164; + + let key = PublicKey::try_from( + &certificate_data + .identity_key + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?[..], + )?; + + let signer_bits = signer_pb.encode_to_vec(); + let signer = ServerCertificate::deserialize(&signer_bits)?; + + Ok(Self { + signer, + key, + sender_device_id, + sender_uuid, + sender_e164, + expiration, + serialized: data.to_vec(), + certificate, + signature, + }) + } + + pub fn new( + sender_uuid: String, + sender_e164: Option, + key: PublicKey, + sender_device_id: u32, + expiration: u64, + signer: ServerCertificate, + signer_key: &PrivateKey, + rng: &mut R, + ) -> Result { + let certificate_pb = proto::sealed_sender::sender_certificate::Certificate { + sender_uuid: Some(sender_uuid.clone()), + sender_e164: sender_e164.clone(), + sender_device: Some(sender_device_id), + expires: Some(expiration), + identity_key: Some(key.serialize().to_vec()), + signer: Some(signer.to_protobuf()?), + }; + + let certificate = certificate_pb.encode_to_vec(); + + let signature = signer_key.calculate_signature(&certificate, rng)?.to_vec(); + + let serialized = proto::sealed_sender::SenderCertificate { + certificate: Some(certificate.clone()), + signature: Some(signature.clone()), + } + .encode_to_vec(); + + Ok(Self { + signer, + key, + sender_device_id, + sender_uuid, + sender_e164, + expiration, + serialized, + certificate, + signature, + }) + } + + pub(crate) fn from_protobuf(pb: &proto::sealed_sender::SenderCertificate) -> Result { + let mut bits = vec![]; + pb.encode(&mut bits)?; + Self::deserialize(&bits) + } + + pub(crate) fn to_protobuf(&self) -> Result { + Ok(proto::sealed_sender::SenderCertificate { + certificate: Some(self.certificate.clone()), + signature: Some(self.signature.clone()), + }) + } + + pub fn validate(&self, trust_root: &PublicKey, validation_time: u64) -> Result { + if !self.signer.validate(trust_root)? { + log::error!("received server certificate not signed by trust root"); + return Ok(false); + } + + if !self + .signer + .public_key()? + .verify_signature(&self.certificate, &self.signature)? + { + log::error!("received sender certificate not signed by server"); + return Ok(false); + } + + if validation_time > self.expiration { + log::error!( + "received expired sender certificate (expiration: {}, validation_time: {})", + self.expiration, + validation_time + ); + return Ok(false); + } + + Ok(true) + } + + pub fn signer(&self) -> Result<&ServerCertificate> { + Ok(&self.signer) + } + + pub fn key(&self) -> Result { + Ok(self.key) + } + + pub fn sender_device_id(&self) -> Result { + Ok(self.sender_device_id) + } + + pub fn sender_uuid(&self) -> Result<&str> { + Ok(&self.sender_uuid) + } + + pub fn sender_e164(&self) -> Result> { + Ok(self.sender_e164.as_deref()) + } + + pub fn expiration(&self) -> Result { + Ok(self.expiration) + } + + pub fn serialized(&self) -> Result<&[u8]> { + Ok(&self.serialized) + } + + pub fn certificate(&self) -> Result<&[u8]> { + Ok(&self.certificate) + } + + pub fn signature(&self) -> Result<&[u8]> { + Ok(&self.signature) + } +} + +impl From for CiphertextMessageType { + fn from(message_type: ProtoMessageType) -> Self { + let result = match message_type { + ProtoMessageType::Message => Self::Whisper, + ProtoMessageType::PrekeyMessage => Self::PreKey, + ProtoMessageType::SenderkeyMessage => Self::SenderKey, + ProtoMessageType::PlaintextContent => Self::Plaintext, + }; + // Keep raw values in sync from now on, for efficient codegen. + assert!(result == Self::PreKey || message_type as i32 == result as i32); + result + } +} + +impl From for ProtoMessageType { + fn from(message_type: CiphertextMessageType) -> Self { + let result = match message_type { + CiphertextMessageType::PreKey => Self::PrekeyMessage, + CiphertextMessageType::Whisper => Self::Message, + CiphertextMessageType::SenderKey => Self::SenderkeyMessage, + CiphertextMessageType::Plaintext => Self::PlaintextContent, + }; + // Keep raw values in sync from now on, for efficient codegen. + assert!(result == Self::PrekeyMessage || message_type as i32 == result as i32); + result + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum ContentHint { + Default, + Resendable, + Implicit, + Unknown(u32), +} + +impl ContentHint { + fn to_proto(self) -> Option { + if self == ContentHint::Default { + None + } else { + Some(u32::from(self) as i32) + } + } + + pub const fn to_u32(self) -> u32 { + use proto::sealed_sender::unidentified_sender_message::message::ContentHint as ProtoContentHint; + match self { + ContentHint::Default => 0, + ContentHint::Resendable => ProtoContentHint::Resendable as u32, + ContentHint::Implicit => ProtoContentHint::Implicit as u32, + ContentHint::Unknown(value) => value, + } + } +} + +impl From for ContentHint { + fn from(raw_value: u32) -> Self { + use proto::sealed_sender::unidentified_sender_message::message::ContentHint as ProtoContentHint; + assert!(!ProtoContentHint::is_valid(0)); + match ProtoContentHint::from_i32(raw_value as i32) { + None if raw_value == 0 => ContentHint::Default, + None => ContentHint::Unknown(raw_value), + Some(ProtoContentHint::Resendable) => ContentHint::Resendable, + Some(ProtoContentHint::Implicit) => ContentHint::Implicit, + } + } +} + +impl From for u32 { + fn from(hint: ContentHint) -> Self { + hint.to_u32() + } +} +pub struct UnidentifiedSenderMessageContent { + serialized: Vec, + contents: Vec, + sender: SenderCertificate, + msg_type: CiphertextMessageType, + content_hint: ContentHint, + group_id: Option>, +} + +impl UnidentifiedSenderMessageContent { + pub fn deserialize(data: &[u8]) -> Result { + let pb = proto::sealed_sender::unidentified_sender_message::Message::decode(data)?; + + let msg_type = pb + .r#type + .and_then(ProtoMessageType::from_i32) + .map(CiphertextMessageType::from) + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let sender = pb + .sender_certificate + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let contents = pb + .content + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let content_hint = pb + .content_hint + .map(|raw| ContentHint::from(raw as u32)) + .unwrap_or(ContentHint::Default); + let group_id = pb.group_id; + + let sender = SenderCertificate::from_protobuf(&sender)?; + + let serialized = data.to_vec(); + + log::info!( + "deserialized UnidentifiedSenderMessageContent from {}.{} with type {:?}", + sender.sender_uuid()?, + sender.sender_device_id()?, + msg_type, + ); + + Ok(Self { + serialized, + contents, + sender, + msg_type, + content_hint, + group_id, + }) + } + + pub fn new( + msg_type: CiphertextMessageType, + sender: SenderCertificate, + contents: Vec, + content_hint: ContentHint, + group_id: Option>, + ) -> Result { + let proto_msg_type = ProtoMessageType::from(msg_type); + let msg = proto::sealed_sender::unidentified_sender_message::Message { + content: Some(contents.clone()), + r#type: Some(proto_msg_type.into()), + sender_certificate: Some(sender.to_protobuf()?), + content_hint: content_hint.to_proto(), + group_id: group_id.as_ref().and_then(|buf| { + if buf.is_empty() { + None + } else { + Some(buf.clone()) + } + }), + }; + + let serialized = msg.encode_to_vec(); + + Ok(Self { + serialized, + msg_type, + sender, + contents, + content_hint, + group_id, + }) + } + + pub fn msg_type(&self) -> Result { + Ok(self.msg_type) + } + + pub fn sender(&self) -> Result<&SenderCertificate> { + Ok(&self.sender) + } + + pub fn contents(&self) -> Result<&[u8]> { + Ok(&self.contents) + } + + pub fn content_hint(&self) -> Result { + Ok(self.content_hint) + } + + pub fn group_id(&self) -> Result> { + Ok(self.group_id.as_deref()) + } + + pub fn serialized(&self) -> Result<&[u8]> { + Ok(&self.serialized) + } +} + +enum UnidentifiedSenderMessage { + V1 { + ephemeral_public: PublicKey, + encrypted_static: Vec, + encrypted_message: Vec, + }, + V2 { + ephemeral_public: PublicKey, + encrypted_message_key: Box<[u8]>, + authentication_tag: Box<[u8]>, + encrypted_message: Box<[u8]>, + }, +} + +const SEALED_SENDER_V1_VERSION: u8 = 1; +const SEALED_SENDER_V2_VERSION: u8 = 2; + +impl UnidentifiedSenderMessage { + fn deserialize(data: &[u8]) -> Result { + if data.is_empty() { + return Err(SignalProtocolError::InvalidSealedSenderMessage( + "Message was empty".to_owned(), + )); + } + let version = data[0] >> 4; + log::debug!( + "deserializing UnidentifiedSenderMessage with version {}", + version + ); + + match version { + 0 | SEALED_SENDER_V1_VERSION => { + // XXX should we really be accepted version == 0 here? + let pb = proto::sealed_sender::UnidentifiedSenderMessage::decode(&data[1..])?; + + let ephemeral_public = pb + .ephemeral_public + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let encrypted_static = pb + .encrypted_static + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let encrypted_message = pb + .encrypted_message + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + + let ephemeral_public = PublicKey::try_from(&ephemeral_public[..])?; + + Ok(Self::V1 { + ephemeral_public, + encrypted_static, + encrypted_message, + }) + } + SEALED_SENDER_V2_VERSION => { + // Uses a flat representation: C || AT || E.pub || ciphertext + let remaining = &data[1..]; + if remaining.len() + < sealed_sender_v2::MESSAGE_KEY_LEN + + sealed_sender_v2::AUTH_TAG_LEN + + curve::curve25519::PUBLIC_KEY_LENGTH + { + return Err(SignalProtocolError::InvalidProtobufEncoding); + } + let (encrypted_message_key, remaining) = + remaining.split_at(sealed_sender_v2::MESSAGE_KEY_LEN); + let (encrypted_authentication_tag, remaining) = + remaining.split_at(sealed_sender_v2::AUTH_TAG_LEN); + let (ephemeral_public, encrypted_message) = + remaining.split_at(curve::curve25519::PUBLIC_KEY_LENGTH); + + Ok(Self::V2 { + ephemeral_public: PublicKey::from_djb_public_key_bytes(ephemeral_public)?, + encrypted_message_key: encrypted_message_key.into(), + authentication_tag: encrypted_authentication_tag.into(), + encrypted_message: encrypted_message.into(), + }) + } + _ => Err(SignalProtocolError::UnknownSealedSenderVersion(version)), + } + } +} + +mod sealed_sender_v1 { + use super::*; + + #[cfg(test)] + use std::fmt; + + /// A symmetric cipher key and a MAC key, along with a "chain key" consumed in + /// [`StaticKeys::calculate`]. + pub(super) struct EphemeralKeys { + pub(super) chain_key: [u8; 32], + pub(super) cipher_key: [u8; 32], + pub(super) mac_key: [u8; 32], + } + + const SALT_PREFIX: &[u8] = b"UnidentifiedDelivery"; + const EPHEMERAL_KEYS_KDF_LEN: usize = 96; + + impl EphemeralKeys { + /// Derive a set of symmetric keys from the key agreement between the sender and + /// recipient's identities. + pub(super) fn calculate( + our_keys: &KeyPair, + their_public: &PublicKey, + direction: Direction, + ) -> Result { + let our_pub_key = our_keys.public_key.serialize(); + let their_pub_key = their_public.serialize(); + let ephemeral_salt = match direction { + Direction::Sending => [SALT_PREFIX, &their_pub_key, &our_pub_key], + Direction::Receiving => [SALT_PREFIX, &our_pub_key, &their_pub_key], + } + .concat(); + + let shared_secret = our_keys.private_key.calculate_agreement(their_public)?; + let mut derived_values = [0; EPHEMERAL_KEYS_KDF_LEN]; + hkdf::Hkdf::::new(Some(&ephemeral_salt), &shared_secret) + .expand(&[], &mut derived_values) + .expect("valid output length"); + + Ok(Self { + chain_key: *array_ref![&derived_values, 0, 32], + cipher_key: *array_ref![&derived_values, 32, 32], + mac_key: *array_ref![&derived_values, 64, 32], + }) + } + } + + #[cfg(test)] + impl PartialEq for EphemeralKeys { + fn eq(&self, other: &Self) -> bool { + self.chain_key == other.chain_key + && self.cipher_key == other.cipher_key + && self.mac_key == other.mac_key + } + } + + #[cfg(test)] + impl Eq for EphemeralKeys {} + + #[cfg(test)] + impl fmt::Debug for EphemeralKeys { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "EphemeralKeys {{ chain_key: {:?}, cipher_key: {:?}, mac_key: {:?} }}", + self.chain_key, self.cipher_key, self.mac_key + ) + } + } + + /// A symmetric cipher key and a MAC key. + pub(super) struct StaticKeys { + pub(super) cipher_key: [u8; 32], + pub(super) mac_key: [u8; 32], + } + + impl StaticKeys { + /// Derive a set of symmetric keys from the agreement between the sender and + /// recipient's identities, as well as [`EphemeralKeys::chain_key`]. + pub(super) fn calculate( + our_keys: &IdentityKeyPair, + their_key: &PublicKey, + chain_key: &[u8; 32], + ctext: &[u8], + ) -> Result { + let salt = [chain_key, ctext].concat(); + + let shared_secret = our_keys.private_key().calculate_agreement(their_key)?; + // 96 bytes are derived, but the first 32 are discarded/unused. This is intended to + // mirror the way the EphemeralKeys are derived, even though StaticKeys does not end up + // requiring a third "chain key". + let mut derived_values = [0; 96]; + hkdf::Hkdf::::new(Some(&salt), &shared_secret) + .expand(&[], &mut derived_values) + .expect("valid output length"); + + Ok(Self { + cipher_key: *array_ref![&derived_values, 32, 32], + mac_key: *array_ref![&derived_values, 64, 32], + }) + } + } + + #[test] + fn test_agreement_and_authentication() -> Result<()> { + // The sender and recipient each have a long-term identity key pair. + let sender_identity = IdentityKeyPair::generate(&mut rand::thread_rng()); + let recipient_identity = IdentityKeyPair::generate(&mut rand::thread_rng()); + + // Generate an ephemeral key pair. + let sender_ephemeral = KeyPair::generate(&mut rand::thread_rng()); + let ephemeral_public = sender_ephemeral.public_key; + // Generate ephemeral cipher, chain, and MAC keys. + let sender_eph_keys = EphemeralKeys::calculate( + &sender_ephemeral, + recipient_identity.public_key(), + Direction::Sending, + )?; + + // Encrypt the sender's public key with AES-256 CTR and a MAC. + let sender_static_key_ctext = crypto::aes256_ctr_hmacsha256_encrypt( + &sender_identity.public_key().serialize(), + &sender_eph_keys.cipher_key, + &sender_eph_keys.mac_key, + )?; + + // Generate another cipher and MAC key. + let sender_static_keys = StaticKeys::calculate( + &sender_identity, + recipient_identity.public_key(), + &sender_eph_keys.chain_key, + &sender_static_key_ctext, + )?; + + let sender_message_contents = b"this is a binary message"; + let sender_message_data = crypto::aes256_ctr_hmacsha256_encrypt( + sender_message_contents, + &sender_static_keys.cipher_key, + &sender_static_keys.mac_key, + )?; + + // The message recipient calculates the ephemeral key and the sender's public key. + let recipient_eph_keys = EphemeralKeys::calculate( + &recipient_identity.into(), + &ephemeral_public, + Direction::Receiving, + )?; + assert_eq!(sender_eph_keys, recipient_eph_keys); + + let recipient_message_key_bytes = crypto::aes256_ctr_hmacsha256_decrypt( + &sender_static_key_ctext, + &recipient_eph_keys.cipher_key, + &recipient_eph_keys.mac_key, + )?; + let sender_public_key: PublicKey = PublicKey::try_from(&recipient_message_key_bytes[..])?; + assert_eq!(sender_identity.public_key(), &sender_public_key); + + let recipient_static_keys = StaticKeys::calculate( + &recipient_identity, + &sender_public_key, + &recipient_eph_keys.chain_key, + &sender_static_key_ctext, + )?; + + let recipient_message_contents = crypto::aes256_ctr_hmacsha256_decrypt( + &sender_message_data, + &recipient_static_keys.cipher_key, + &recipient_static_keys.mac_key, + )?; + assert_eq!(recipient_message_contents, sender_message_contents); + + Ok(()) + } +} + +/// Encrypt the plaintext message `ptext`, generate an [`UnidentifiedSenderMessageContent`], then +/// pass the result to [`sealed_sender_encrypt_from_usmc`]. +/// +/// This is a simple way to encrypt a message in a 1:1 using [Sealed Sender v1]. +/// +/// [Sealed Sender v1]: sealed_sender_encrypt_from_usmc +pub async fn sealed_sender_encrypt( + destination: &ProtocolAddress, + sender_cert: &SenderCertificate, + ptext: &[u8], + session_store: &mut dyn SessionStore, + identity_store: &mut dyn IdentityKeyStore, + ctx: Context, + rng: &mut R, +) -> Result> { + let message = message_encrypt(ptext, destination, session_store, identity_store, ctx).await?; + let usmc = UnidentifiedSenderMessageContent::new( + message.message_type(), + sender_cert.clone(), + message.serialize().to_vec(), + ContentHint::Default, + None, + )?; + sealed_sender_encrypt_from_usmc(destination, &usmc, identity_store, ctx, rng).await +} + +/// This method implements the single-key single-recipient [KEM] described in [this Signal blog +/// post], a.k.a. Sealed Sender v1. +/// +/// [KEM]: https://en.wikipedia.org/wiki/Key_encapsulation +/// [this Signal blog post]: https://signal.org/blog/sealed-sender/ +/// +/// [`sealed_sender_decrypt`] is used in the client to decrypt the Sealed Sender message produced by +/// this method. +/// +/// # Contrast with Sealed Sender v2 +/// The *single-recipient* KEM scheme implemented by this method partially derives the encryption +/// key from the recipient's identity key, which would then require re-encrypting the same message +/// multiple times to send to multiple recipients. In contrast, +/// [Sealed Sender v2](sealed_sender_multi_recipient_encrypt) uses a *multi-recipient* KEM scheme +/// which avoids this repeated work, but makes a few additional design tradeoffs. +/// +/// # High-level algorithmic overview +/// The KEM scheme implemented by this method is described in [this Signal blog post]. The +/// high-level steps of this process are listed below: +/// 1. Generate a random key pair. +/// 2. Derive a symmetric chain key, cipher key, and MAC key from the recipient's public key and the +/// sender's public/private key pair. +/// 3. Symmetrically encrypt the sender's public key using the cipher key and MAC key from (2) with +/// AES-256 in CTR mode. +/// 4. Derive a second symmetric cipher key and MAC key from the sender's private key, the +/// recipient's public key, and the chain key from (2). +/// 5. Symmetrically encrypt the underlying [`UnidentifiedSenderMessageContent`] using the cipher key +/// and MAC key from (4) with AES-256 in CTR mode. +/// 6. Send the ephemeral public key from (1) and the encrypted public key from (3) to the +/// recipient, along with the encrypted message (5). +/// +/// ## Pseudocode +///```text +/// e_pub, e_priv = X25519.generateEphemeral() +/// e_chain, e_cipherKey, e_macKey = HKDF(salt="UnidentifiedDelivery" || recipientIdentityPublic || e_pub, ikm=ECDH(recipientIdentityPublic, e_priv), info="") +/// e_ciphertext = AES_CTR(key=e_cipherKey, input=senderIdentityPublic) +/// e_mac = Hmac256(key=e_macKey, input=e_ciphertext) +/// +/// s_cipherKey, s_macKey = HKDF(salt=e_chain || e_ciphertext || e_mac, ikm=ECDH(recipientIdentityPublic, senderIdentityPrivate), info="") +/// s_ciphertext = AES_CTR(key=s_cipherKey, input=sender_certificate || message_ciphertext) +/// s_mac = Hmac256(key=s_macKey, input=s_ciphertext) +/// +/// message_to_send = s_ciphertext || s_mac +///``` +/// +/// # Wire Format +/// The output of this method is encoded as an `UnidentifiedSenderMessage.Message` from +/// `sealed_sender.proto`, prepended with an additional byte to indicate the version of Sealed +/// Sender in use (see [further documentation on the version +/// byte](sealed_sender_multi_recipient_encrypt#the-version-byte)). +pub async fn sealed_sender_encrypt_from_usmc( + destination: &ProtocolAddress, + usmc: &UnidentifiedSenderMessageContent, + identity_store: &mut dyn IdentityKeyStore, + ctx: Context, + rng: &mut R, +) -> Result> { + let our_identity = identity_store.get_identity_key_pair(ctx).await?; + let their_identity = identity_store + .get_identity(destination, ctx) + .await? + .ok_or_else(|| SignalProtocolError::SessionNotFound(format!("{}", destination)))?; + + let ephemeral = KeyPair::generate(rng); + + let eph_keys = sealed_sender_v1::EphemeralKeys::calculate( + &ephemeral, + their_identity.public_key(), + Direction::Sending, + )?; + + let static_key_ctext = crypto::aes256_ctr_hmacsha256_encrypt( + &our_identity.public_key().serialize(), + &eph_keys.cipher_key, + &eph_keys.mac_key, + )?; + + let static_keys = sealed_sender_v1::StaticKeys::calculate( + &our_identity, + their_identity.public_key(), + &eph_keys.chain_key, + &static_key_ctext, + )?; + + let message_data = crypto::aes256_ctr_hmacsha256_encrypt( + usmc.serialized()?, + &static_keys.cipher_key, + &static_keys.mac_key, + )?; + + let version = SEALED_SENDER_V1_VERSION; + let mut serialized = vec![version | (version << 4)]; + let pb = proto::sealed_sender::UnidentifiedSenderMessage { + ephemeral_public: Some(ephemeral.public_key.serialize().to_vec()), + encrypted_static: Some(static_key_ctext), + encrypted_message: Some(message_data), + }; + pb.encode(&mut serialized)?; // appends to buffer + + Ok(serialized) +} + +mod sealed_sender_v2 { + use super::*; + + // Static byte strings used as part of a MAC in HKDF. + const LABEL_R: &[u8] = b"Sealed Sender v2: r"; + const LABEL_K: &[u8] = b"Sealed Sender v2: K"; + const LABEL_DH: &[u8] = b"Sealed Sender v2: DH"; + const LABEL_DH_S: &[u8] = b"Sealed Sender v2: DH-sender"; + + pub const MESSAGE_KEY_LEN: usize = 32; + pub const AUTH_TAG_LEN: usize = 16; + + /// An asymmetric and a symmetric cipher key. + pub(super) struct DerivedKeys { + /// Asymmetric key pair. + pub(super) e: KeyPair, + /// Symmetric key used to instantiate [`Aes256GcmSiv::new_from_slice`]. + pub(super) k: [u8; MESSAGE_KEY_LEN], + } + + impl DerivedKeys { + /// Derive a set of ephemeral keys from a slice of random bytes `m`. + pub(super) fn calculate(m: &[u8]) -> DerivedKeys { + let kdf = hkdf::Hkdf::::new(None, m); + let mut r = [0; 64]; + kdf.expand(LABEL_R, &mut r).expect("valid output length"); + let mut k = [0; MESSAGE_KEY_LEN]; + kdf.expand(LABEL_K, &mut k).expect("valid output length"); + let e_raw = Scalar::from_bytes_mod_order_wide(&r); + let e = PrivateKey::try_from(&e_raw.as_bytes()[..]).expect("valid PrivateKey"); + let e = KeyPair::try_from(e).expect("can derive public key"); + DerivedKeys { e, k } + } + } + + /// Encrypt or decrypt a slice of random bytes `input` using a shared secret derived from + /// `our_keys` and `their_key`. + /// + /// The output of this method when called with [`Direction::Sending`] can be inverted to produce + /// the original `input` bytes if called with [`Direction::Receiving`] with `our_keys` and + /// `their_key` swapped. + pub(super) fn apply_agreement_xor( + our_keys: &KeyPair, + their_key: &PublicKey, + direction: Direction, + input: &[u8; MESSAGE_KEY_LEN], + ) -> Result<[u8; MESSAGE_KEY_LEN]> { + let agreement = our_keys.calculate_agreement(their_key)?; + let agreement_key_input = match direction { + Direction::Sending => [ + agreement, + our_keys.public_key.serialize(), + their_key.serialize(), + ], + Direction::Receiving => [ + agreement, + their_key.serialize(), + our_keys.public_key.serialize(), + ], + } + .concat(); + + let mut result = [0; MESSAGE_KEY_LEN]; + hkdf::Hkdf::::new(None, &agreement_key_input) + .expand(LABEL_DH, &mut result) + .expect("valid output length"); + result + .iter_mut() + .zip(input) + .for_each(|(result_byte, input_byte)| *result_byte ^= input_byte); + Ok(result) + } + + /// Compute an [authentication tag] for the bytes `encrypted_message_key` using a shared secret + /// derived from `our_keys` and `their_key`. + /// + /// [authentication tag]: https://en.wikipedia.org/wiki/Message_authentication_code + /// + /// The output of this method with [`Direction::Sending`] should be the same bytes produced by + /// calling this method with [`Direction::Receiving`] with `our_keys` and `their_key` + /// swapped, if `ephemeral_pub_key` and `encrypted_message_key` are the same. + pub(super) fn compute_authentication_tag( + our_keys: &IdentityKeyPair, + their_key: &IdentityKey, + direction: Direction, + ephemeral_pub_key: &PublicKey, + encrypted_message_key: &[u8; MESSAGE_KEY_LEN], + ) -> Result<[u8; AUTH_TAG_LEN]> { + let agreement = our_keys + .private_key() + .calculate_agreement(their_key.public_key())?; + let mut agreement_key_input = agreement.into_vec(); + agreement_key_input.extend_from_slice(&ephemeral_pub_key.serialize()); + agreement_key_input.extend_from_slice(encrypted_message_key); + match direction { + Direction::Sending => { + agreement_key_input.extend_from_slice(&our_keys.public_key().serialize()); + agreement_key_input.extend_from_slice(&their_key.serialize()); + } + Direction::Receiving => { + agreement_key_input.extend_from_slice(&their_key.serialize()); + agreement_key_input.extend_from_slice(&our_keys.public_key().serialize()); + } + } + + let mut result = [0; AUTH_TAG_LEN]; + hkdf::Hkdf::::new(None, &agreement_key_input) + .expand(LABEL_DH_S, &mut result) + .expect("valid output length"); + Ok(result) + } + + #[test] + fn test_agreement_and_authentication() -> Result<()> { + // The sender and recipient each have a long-term identity key pair. + let sender_identity = IdentityKeyPair::generate(&mut rand::thread_rng()); + let recipient_identity = IdentityKeyPair::generate(&mut rand::thread_rng()); + + // Generate random bytes used for our multi-recipient encoding scheme. + let m: [u8; MESSAGE_KEY_LEN] = rand::thread_rng().gen(); + // Derive an ephemeral key pair from those random bytes. + let ephemeral_keys = DerivedKeys::calculate(&m); + let ephemeral_public_key = ephemeral_keys.e.public_key; + + // Encrypt the ephemeral key pair. + let sender_c_0: [u8; MESSAGE_KEY_LEN] = apply_agreement_xor( + &ephemeral_keys.e, + recipient_identity.public_key(), + Direction::Sending, + &m, + )?; + // Compute an authentication tag for the encrypted key pair. + let sender_at_0 = compute_authentication_tag( + &sender_identity, + recipient_identity.identity_key(), + Direction::Sending, + &ephemeral_public_key, + &sender_c_0, + )?; + + // The message recipient calculates the original random bytes and authenticates the result. + let recv_m = apply_agreement_xor( + &recipient_identity.into(), + &ephemeral_public_key, + Direction::Receiving, + &sender_c_0, + )?; + assert_eq!(&recv_m, &m); + + let recv_at_0 = compute_authentication_tag( + &recipient_identity, + sender_identity.identity_key(), + Direction::Receiving, + &ephemeral_public_key, + &sender_c_0, + )?; + assert_eq!(&recv_at_0, &sender_at_0); + + Ok(()) + } +} + +/// This method implements a single-key multi-recipient [KEM] as defined in Manuel Barbosa's +/// ["Randomness Reuse: Extensions and Improvements"], a.k.a. Sealed Sender v2. +/// +/// [KEM]: https://en.wikipedia.org/wiki/Key_encapsulation +/// ["Randomness Reuse: Extensions and Improvements"]: https://haslab.uminho.pt/mbb/files/reuse.pdf +/// +/// # Contrast with Sealed Sender v1 +/// The KEM scheme implemented by this method uses the "Generic Construction" in `4.1` of [Barbosa's +/// paper]["Randomness Reuse: Extensions and Improvements"], instantiated with [ElGamal +/// encryption]. This technique enables reusing a single sequence of random bytes across multiple +/// messages with the same content, which reduces computation time for clients sending the same +/// message to multiple recipients (without compromising the message security). +/// +/// There are a few additional design tradeoffs this method makes vs [Sealed Sender v1] +/// which may make it comparatively unwieldy for certain scenarios: +/// 1. it requires a [`SessionRecord`] to exist already for the recipient, i.e. that a Double +/// Ratchet message chain has previously been established in the [`SessionStore`] via +/// [`process_prekey_bundle`][crate::process_prekey_bundle] after an initial +/// [`PreKeySignalMessage`][crate::PreKeySignalMessage] is received. +/// 2. it ferries a lot of additional information in its encoding which makes the resulting message +/// bulkier than the message produced by [Sealed Sender v1]. For sending, this will generally +/// still be more compact than sending the same message N times, but on the receiver side the +/// message is slightly larger. +/// 3. unlike other message types sent over the wire, the encoded message returned by this method +/// does not use protobuf, in order to avoid inefficiencies produced by protobuf's packing (see +/// **[Wire Format]**). +/// +/// [ElGamal encryption]: https://en.wikipedia.org/wiki/ElGamal_encryption +/// [Sealed Sender v1]: sealed_sender_encrypt_from_usmc +/// [Wire Format]: #wire-format +/// +/// # High-level algorithmic overview +/// The high-level steps of this process are summarized below: +/// 1. Generate a series of random bytes. +/// 2. Derive an ephemeral key pair from (1). +/// 3. *Once per recipient:* Encrypt (1) using a shared secret derived from the private ephemeral +/// key (2) and the recipient's public identity key. +/// 4. *Once per recipient:* Add an authentication tag for (3) using a secret derived from the +/// sender's private identity key and the recipient's public identity key. +/// 5. Generate a symmetric key from (1) and use it to symmetrically encrypt the underlying +/// [`UnidentifiedSenderMessageContent`] via [AEAD encryption]. *This step is only performed once +/// per message, regardless of the number of recipients.* +/// 6. Send the public ephemeral key (2) to the server, along with the sequence of encrypted random +/// bytes (3) and authentication tags (4), and the single encrypted message (5). +/// +/// [AEAD encryption]: https://en.wikipedia.org/wiki/Authenticated_encryption#Authenticated_encryption_with_associated_data_(AEAD) +/// +/// ## Pseudocode +///```text +/// ENCRYPT(message, R_i): +/// M = Random(32) +/// r = KDF(label_r, M, len=64) +/// K = KDF(label_K, M, len=32) +/// E = DeriveKeyPair(r) +/// for i in num_recipients: +/// C_i = KDF(label_DH, DH(E, R_i) || E.public || R_i.public, len=32) XOR M +/// AT_i = KDF(label_DH_s, DH(S, R_i) || E.public || C_i || S.public || R_i.public, len=16) +/// ciphertext = AEAD_Encrypt(K, message) +/// return E.public, C_i, AT_i, ciphertext +/// +/// DECRYPT(E.public, C, AT, ciphertext): +/// M = KDF(label_DH, DH(E, R) || E.public || R.public, len=32) xor C +/// r = KDF(label_r, M, len=64) +/// K = KDF(label_K, M, len=32) +/// E' = DeriveKeyPair(r) +/// if E.public != E'.public: +/// return DecryptionError +/// message = AEAD_Decrypt(K, ciphertext) // includes S.public +/// AT' = KDF(label_DH_s, DH(S, R) || E.public || C || S.public || R.public, len=16) +/// if AT != AT': +/// return DecryptionError +/// return message +///``` +/// +/// # Routing messages to recipients +/// +/// The server will split up the set of messages and securely route each individual [received +/// message][receiving] to its intended recipient. +/// +/// For testing purposes, [`sealed_sender_multi_recipient_fan_out`] can be used to convert such +/// a bulk message produced by Sealed Sender v2 into a sequence of [received messages][receiving]; +/// however, in doing so it will drop all of the metadata necessary to identify the message's +/// intended recipients. +/// +/// # Wire Format +/// Multi-recipient sealed-sender does not use protobufs for its payload format. Instead, it uses +/// a flat format marked with a [version byte](#the-version-byte). The format is different for +/// [sending] and [receiving]. The decrypted content is +/// a protobuf-encoded `UnidentifiedSenderMessage.Message` from `sealed_sender.proto`. +/// +/// The public key used in Sealed Sender v2 is always a Curve25519 DJB key. +/// +/// [sending]: #sent-messages +/// [receiving]: #received-messages +/// +/// ## The version byte +/// +/// Sealed sender messages (v1 and v2) in serialized form begin with a version [byte][u8]. +/// This byte has the form: +/// +/// ```text +/// (requiredVersion << 4) | currentVersion +/// ``` +/// +/// v1 messages thus have a version byte of `0x11`. v2 messages have a version byte +/// of `0x22`. A hypothetical version byte `0x34` would indicate a message encoded +/// as Sealed Sender v4, but decodable by any client that supports Sealed Sender v3. +/// +/// ## Received messages +/// +/// ```text +/// ReceivedMessage { +/// version_byte: u8, +/// c: [u8; 32], +/// at: [u8; 16], +/// e_pub: [u8; 32], +/// message: [u8] // remaining bytes +/// } +/// ``` +/// +/// Each individual Sealed Sender message received from the server is decoded in the Signal +/// client by calling [`sealed_sender_decrypt`]. +/// +/// ## Sent messages +/// +/// ```text +/// PerRecipientData { +/// uuid: [u8; 16], +/// device_id: varint, +/// registration_id: u16, +/// c: [u8; 32], +/// at: [u8; 16], +/// } +/// +/// SentMessage { +/// version_byte: u8, +/// count: varint, +/// recipients: [PerRecipientData; count], +/// e_pub: [u8; 32], +/// message: [u8] // remaining bytes +/// } +/// ``` +/// +/// The varint encoding used is the same as [protobuf's][varint]. Values are unsigned. UUIDs are +/// encoded per [RFC 4122], with the first eight bytes considered "most significant". [^1] +/// Fixed-width integers are unaligned and in network byte order (big-endian). +/// +/// [varint]: https://developers.google.com/protocol-buffers/docs/encoding#varints +/// [RFC 4122]: https://tools.ietf.org/html/rfc4122#section-4.1.2 +/// +/// [^1]: RFC 4122 guarantees the encoding order of the fields in a +/// UUID, but the representation of each field may vary based on the UUID's +/// "variant". For Sealed Sender's purposes, this is not important except for +/// debug-printing, since UUIDs are always treated as opaque identifiers matched +/// byte-for-byte. +pub async fn sealed_sender_multi_recipient_encrypt( + destinations: &[&ProtocolAddress], + destination_sessions: &[&SessionRecord], + usmc: &UnidentifiedSenderMessageContent, + identity_store: &mut dyn IdentityKeyStore, + ctx: Context, + rng: &mut R, +) -> Result> { + if destinations.len() != destination_sessions.len() { + return Err(SignalProtocolError::InvalidArgument( + "must have the same number of destination sessions as addresses".to_string(), + )); + } + + let m: [u8; sealed_sender_v2::MESSAGE_KEY_LEN] = rng.gen(); + let keys = sealed_sender_v2::DerivedKeys::calculate(&m); + let e_pub = &keys.e.public_key; + + let ciphertext = { + let mut ciphertext = usmc.serialized()?.to_vec(); + let symmetric_authentication_tag = Aes256GcmSiv::new_from_slice(&keys.k) + .and_then(|aes_gcm_siv| { + aes_gcm_siv.encrypt_in_place_detached( + // There's no nonce because the key is already one-use. + &aes_gcm_siv::Nonce::default(), + // And there's no associated data. + &[], + &mut ciphertext, + ) + }) + .map_err(|err| { + log::error!("failed to encrypt using AES-GCM-SIV: {}", err); + SignalProtocolError::InternalError("failed to encrypt using AES-GCM-SIV") + })?; + // AES-GCM-SIV expects the authentication tag to be at the end of the ciphertext + // when decrypting. + ciphertext.extend_from_slice(&symmetric_authentication_tag); + ciphertext + }; + + // Uses a flat representation: count || UUID_i || deviceId_i || registrationId_i || C_i || AT_i || ... || E.pub || ciphertext + let version = SEALED_SENDER_V2_VERSION; + let mut serialized: Vec = vec![(version | (version << 4))]; + + prost::encode_length_delimiter(destinations.len(), &mut serialized) + .expect("cannot fail encoding to Vec"); + + let our_identity = identity_store.get_identity_key_pair(ctx).await?; + let mut previous_their_identity = None; + for (&destination, session) in destinations.iter().zip(destination_sessions) { + let their_uuid = Uuid::parse_str(destination.name()).map_err(|_| { + SignalProtocolError::InvalidArgument(format!( + "multi-recipient sealed sender requires UUID recipients (not {})", + destination.name() + )) + })?; + + let their_identity = identity_store + .get_identity(destination, ctx) + .await? + .ok_or_else(|| SignalProtocolError::SessionNotFound(format!("{}", destination)))?; + + let their_registration_id = session.remote_registration_id().map_err(|_| { + SignalProtocolError::InvalidState( + "sealed_sender_multi_recipient_encrypt", + format!( + concat!( + "cannot get registration ID from session with {} ", + "(maybe it was recently archived)" + ), + destination + ), + ) + })?; + // Valid registration IDs fit in 14 bits. + // TODO: move this into a RegistrationId strong type. + if their_registration_id & 0x3FFF != their_registration_id { + return Err(SignalProtocolError::InvalidRegistrationId( + destination.clone(), + their_registration_id, + )); + } + let their_registration_id = + u16::try_from(their_registration_id).expect("just checked range"); + + let end_of_previous_recipient_data = serialized.len(); + + serialized.extend_from_slice(their_uuid.as_bytes()); + prost::encode_length_delimiter(destination.device_id() as usize, &mut serialized) + .expect("cannot fail encoding to Vec"); + serialized.extend_from_slice(&their_registration_id.to_be_bytes()); + + if Some(their_identity) == previous_their_identity { + // We often send to the same user multiple times, once per device. + // Since the encoding of the message key and attachment tag only depends + // on the identity key, we can reuse the work from the previous destination. + let start_of_previous_recipient_c_and_at = end_of_previous_recipient_data + - sealed_sender_v2::MESSAGE_KEY_LEN + - sealed_sender_v2::AUTH_TAG_LEN; + serialized.extend_from_within( + start_of_previous_recipient_c_and_at..end_of_previous_recipient_data, + ) + } else { + let c_i = sealed_sender_v2::apply_agreement_xor( + &keys.e, + their_identity.public_key(), + Direction::Sending, + &m, + )?; + serialized.extend_from_slice(&c_i); + + let at_i = sealed_sender_v2::compute_authentication_tag( + &our_identity, + &their_identity, + Direction::Sending, + e_pub, + &c_i, + )?; + serialized.extend_from_slice(&at_i); + } + + previous_their_identity = Some(their_identity); + } + + serialized.extend_from_slice(e_pub.public_key_bytes()?); + serialized.extend_from_slice(&ciphertext); + + Ok(serialized) +} + +/// Split out the encoded message from [`sealed_sender_multi_recipient_encrypt`] into a sequence of +/// individual encrypted [`UnidentifiedSenderMessageContent`]s. **Note: this method is only used in +/// testing.** +/// +/// This method strips recipients' metadata and splits a bulk v2 sealed-sender message into byte +/// strings which can be processed by [`sealed_sender_decrypt_to_usmc`]. For the Signal app, this +/// process of splitting out a v2 sealed-sender message into individual messages and using the +/// metadata to correctly route the result to recipients is performed by the Signal server (see +/// **[Routing messages to recipients]**). +/// +/// [Routing messages to recipients]: sealed_sender_multi_recipient_encrypt#routing-messages-to-recipients +pub fn sealed_sender_multi_recipient_fan_out(data: &[u8]) -> Result>> { + let version = data[0] >> 4; + if version != SEALED_SENDER_V2_VERSION { + return Err(SignalProtocolError::UnknownSealedSenderVersion(version)); + } + + fn advance<'a>(buf: &mut &'a [u8], n: usize) -> Result<&'a [u8]> { + if n > buf.len() { + return Err(SignalProtocolError::InvalidProtobufEncoding); + } + let (prefix, remaining) = buf.split_at(n); + *buf = remaining; + Ok(prefix) + } + fn decode_varint(buf: &mut &[u8]) -> Result { + let result: usize = prost::decode_length_delimiter(*buf)?; + let _ = advance(buf, prost::length_delimiter_len(result)) + .expect("just decoded that many bytes"); + result + .try_into() + .map_err(|_| SignalProtocolError::InvalidProtobufEncoding) + } + + let mut remaining = &data[1..]; + let recipient_count = decode_varint(&mut remaining)?; + + let mut messages: Vec> = Vec::new(); + for _ in 0..recipient_count { + // Skip UUID. + let _ = advance(&mut remaining, 16)?; + // Skip device ID. + let _ = decode_varint(&mut remaining)?; + // Skip registration ID. + let _ = advance(&mut remaining, 2)?; + // Read C_i and AT_i. + let c_and_at = advance( + &mut remaining, + sealed_sender_v2::MESSAGE_KEY_LEN + sealed_sender_v2::AUTH_TAG_LEN, + )?; + + let mut next_message = vec![data[0]]; + next_message.extend_from_slice(c_and_at); + messages.push(next_message); + } + + // Remaining data is shared among all messages. + for message in messages.iter_mut() { + message.extend_from_slice(remaining) + } + + Ok(messages) +} + +/// Decrypt the payload of a sealed-sender message in either the v1 or v2 format. +/// +/// [`sealed_sender_decrypt`] consumes the output of this method to validate the sender's identity +/// before decrypting the underlying message. +pub async fn sealed_sender_decrypt_to_usmc( + ciphertext: &[u8], + identity_store: &mut dyn IdentityKeyStore, + ctx: Context, +) -> Result { + let our_identity = identity_store.get_identity_key_pair(ctx).await?; + + match UnidentifiedSenderMessage::deserialize(ciphertext)? { + UnidentifiedSenderMessage::V1 { + ephemeral_public, + encrypted_static, + encrypted_message, + } => { + let eph_keys = sealed_sender_v1::EphemeralKeys::calculate( + &our_identity.into(), + &ephemeral_public, + Direction::Receiving, + )?; + + let message_key_bytes = crypto::aes256_ctr_hmacsha256_decrypt( + &encrypted_static, + &eph_keys.cipher_key, + &eph_keys.mac_key, + )?; + + let static_key = PublicKey::try_from(&message_key_bytes[..])?; + + let static_keys = sealed_sender_v1::StaticKeys::calculate( + &our_identity, + &static_key, + &eph_keys.chain_key, + &encrypted_static, + )?; + + let message_bytes = crypto::aes256_ctr_hmacsha256_decrypt( + &encrypted_message, + &static_keys.cipher_key, + &static_keys.mac_key, + )?; + + let usmc = UnidentifiedSenderMessageContent::deserialize(&message_bytes)?; + + if !bool::from(message_key_bytes.ct_eq(&usmc.sender()?.key()?.serialize())) { + return Err(SignalProtocolError::InvalidSealedSenderMessage( + "sender certificate key does not match message key".to_string(), + )); + } + + Ok(usmc) + } + UnidentifiedSenderMessage::V2 { + ephemeral_public, + encrypted_message_key, + authentication_tag, + encrypted_message, + } => { + let encrypted_message_key: [u8; sealed_sender_v2::MESSAGE_KEY_LEN] = + encrypted_message_key.as_ref().try_into().map_err(|_| { + SignalProtocolError::InvalidSealedSenderMessage(format!( + "encrypted message key had incorrect length {} (should be {})", + encrypted_message_key.len(), + sealed_sender_v2::MESSAGE_KEY_LEN + )) + })?; + let m = sealed_sender_v2::apply_agreement_xor( + &our_identity.into(), + &ephemeral_public, + Direction::Receiving, + &encrypted_message_key, + )?; + + let keys = sealed_sender_v2::DerivedKeys::calculate(&m); + if !bool::from(keys.e.public_key.ct_eq(&ephemeral_public)) { + return Err(SignalProtocolError::InvalidSealedSenderMessage( + "derived ephemeral key did not match key provided in message".to_string(), + )); + } + + let mut message_bytes = encrypted_message.into_vec(); + Aes256GcmSiv::new_from_slice(&keys.k) + .and_then(|aes_gcm_siv| { + aes_gcm_siv.decrypt_in_place( + // There's no nonce because the key is already one-use. + &aes_gcm_siv::Nonce::default(), + // And there's no associated data. + &[], + &mut message_bytes, + ) + }) + .map_err(|err| { + SignalProtocolError::InvalidSealedSenderMessage(format!( + "failed to decrypt inner message: {}", + err + )) + })?; + + let usmc = UnidentifiedSenderMessageContent::deserialize(&message_bytes)?; + + let at = sealed_sender_v2::compute_authentication_tag( + &our_identity, + &usmc.sender()?.key()?.into(), + Direction::Receiving, + &ephemeral_public, + &encrypted_message_key, + )?; + if !bool::from(authentication_tag.ct_eq(&at)) { + return Err(SignalProtocolError::InvalidSealedSenderMessage( + "sender certificate key does not match authentication tag".to_string(), + )); + } + + Ok(usmc) + } + } +} + +#[derive(Debug)] +pub struct SealedSenderDecryptionResult { + pub sender_uuid: String, + pub sender_e164: Option, + pub device_id: u32, + pub message: Vec, +} + +impl SealedSenderDecryptionResult { + pub fn sender_uuid(&self) -> Result<&str> { + Ok(self.sender_uuid.as_ref()) + } + + pub fn sender_e164(&self) -> Result> { + Ok(self.sender_e164.as_deref()) + } + + pub fn device_id(&self) -> Result { + Ok(self.device_id) + } + + pub fn message(&self) -> Result<&[u8]> { + Ok(self.message.as_ref()) + } +} + +/// Decrypt a Sealed Sender message `ciphertext` in either the v1 or v2 format, validate its sender +/// certificate, and then decrypt the inner message payload. +/// +/// This method calls [`sealed_sender_decrypt_to_usmc`] to extract the sender information, including +/// the embedded [`SenderCertificate`]. The sender certificate (signed by the [`ServerCertificate`]) +/// is then validated against the `trust_root` baked into the client to ensure that the sender's +/// identity was not forged. +#[allow(clippy::too_many_arguments)] +pub async fn sealed_sender_decrypt( + ciphertext: &[u8], + trust_root: &PublicKey, + timestamp: u64, + local_e164: Option, + local_uuid: String, + local_device_id: u32, + identity_store: &mut dyn IdentityKeyStore, + session_store: &mut dyn SessionStore, + pre_key_store: &mut dyn PreKeyStore, + signed_pre_key_store: &mut dyn SignedPreKeyStore, + ctx: Context, +) -> Result { + let usmc = sealed_sender_decrypt_to_usmc(ciphertext, identity_store, ctx).await?; + + if !usmc.sender()?.validate(trust_root, timestamp)? { + return Err(SignalProtocolError::InvalidSealedSenderMessage( + "trust root validation failed".to_string(), + )); + } + + let is_local_uuid = local_uuid == usmc.sender()?.sender_uuid()?; + + let is_local_e164 = match (local_e164, usmc.sender()?.sender_e164()?) { + (Some(l), Some(s)) => l == s, + (_, _) => false, + }; + + if (is_local_e164 || is_local_uuid) && usmc.sender()?.sender_device_id()? == local_device_id { + return Err(SignalProtocolError::SealedSenderSelfSend); + } + + let mut rng = rand::rngs::OsRng; + + let remote_address = ProtocolAddress::new( + usmc.sender()?.sender_uuid()?.to_string(), + usmc.sender()?.sender_device_id()?, + ); + + let message = match usmc.msg_type()? { + CiphertextMessageType::Whisper => { + let ctext = SignalMessage::try_from(usmc.contents()?)?; + session_cipher::message_decrypt_signal( + &ctext, + &remote_address, + session_store, + identity_store, + &mut rng, + ctx, + ) + .await? + } + CiphertextMessageType::PreKey => { + let ctext = PreKeySignalMessage::try_from(usmc.contents()?)?; + session_cipher::message_decrypt_prekey( + &ctext, + &remote_address, + session_store, + identity_store, + pre_key_store, + signed_pre_key_store, + &mut rng, + ctx, + ) + .await? + } + msg_type => { + return Err(SignalProtocolError::InvalidSealedSenderMessage(format!( + "Unexpected message type {}", + msg_type as i32, + ))) + } + }; + + Ok(SealedSenderDecryptionResult { + sender_uuid: usmc.sender()?.sender_uuid()?.to_string(), + sender_e164: usmc.sender()?.sender_e164()?.map(|s| s.to_string()), + device_id: usmc.sender()?.sender_device_id()?, + message, + }) +} + +#[test] +fn test_lossless_round_trip() -> Result<()> { + let trust_root = PrivateKey::deserialize(&[0u8; 32])?; + + // To test a hypothetical addition of a new field: + // + // Step 1: tempororarily add a new field to the .proto. + // + // --- a/rust/protocol/src/proto/sealed_sender.proto + // +++ b/rust/protocol/src/proto/sealed_sender.proto + // @@ -26,3 +26,4 @@ message SenderCertificate { + // optional bytes identityKey = 4; + // optional ServerCertificate signer = 5; + // + optional string someFakeField = 999; + // } + // + // Step 2: Add `some_fake_field: None` to the above construction of + // proto::sealed_sender::sender_certificate::Certificate. + // + // Step 3: Serialize and print out the new fixture data (uncomment the following) + // + // let mut rng = rand::rngs::OsRng; + // let server_key = KeyPair::generate(&mut rng); + // let sender_key = KeyPair::generate(&mut rng); + // + // let server_cert = + // ServerCertificate::new(1, server_key.public_key, &trust_root, &mut rng)?; + // + // let sender_cert = proto::sealed_sender::sender_certificate::Certificate { + // sender_uuid: Some("aaaaaaaa-7000-11eb-b32a-33b8a8a487a6".to_string()), + // sender_e164: None, + // sender_device: Some(1), + // expires: Some(31337), + // identity_key: Some(sender_key.public_key.serialize().to_vec()), + // signer: Some(server_cert.to_protobuf()?), + // some_fake_field: Some("crashing right down".to_string()), + // }; + // + // eprintln!(""); + // let serialized_certificate_data = sender_cert.encode_to_vec(); + // let certificate_data_encoded = hex::encode(&serialized_certificate_data); + // eprintln!("let certificate_data_encoded = \"{}\";", certificate_data_encoded); + // + // let certificate_signature = server_key.calculate_signature(&serialized_certificate_data, &mut rng)?; + // let certificate_signature_encoded = hex::encode(certificate_signature); + // eprintln!("let certificate_signature_encoded = \"{}\";", certificate_signature_encoded); + + // Step 4: update the following *_encoded fixture data with the new values from above. + let certificate_data_encoded = "100119697a0000000000002221056c9d1f8deb82b9a898f9c277a1b74989ec009afb5c0acb5e8e69e3d5ca29d6322a690a2508011221053b03ca070e6f6b2f271d32f27321689cdf4e59b106c10b58fbe15063ed868a5a124024bc92954e52ad1a105b5bda85c9db410dcfeb42a671b45a523b3a46e9594a8bde0efc671d8e8e046b32c67f59b80a46ffdf24071850779bc21325107902af89322461616161616161612d373030302d313165622d623332612d333362386138613438376136ba3e136372617368696e6720726967687420646f776e"; + let certificate_signature_encoded = "a22d8f86f5d00794f319add821e342c6ffffb6b34f741e569f8b321ab0255f2d1757ecf648e53a3602cae8f09b3fc80dcf27534d67efd272b6739afc31f75c8c"; + + // The rest of the test should be stable. + let certificate_data = hex::decode(certificate_data_encoded).expect("valid hex"); + let certificate_signature = hex::decode(certificate_signature_encoded).expect("valid hex"); + + let sender_certificate_data = proto::sealed_sender::SenderCertificate { + certificate: Some(certificate_data), + signature: Some(certificate_signature), + }; + + let sender_certificate = SenderCertificate::from_protobuf(&sender_certificate_data)?; + assert!(sender_certificate.validate(&trust_root.public_key()?, 31336)?); + Ok(()) +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/sender_keys.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/sender_keys.rs new file mode 100644 index 0000000..c6eeec4 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/sender_keys.rs @@ -0,0 +1,631 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use std::collections::VecDeque; +use std::convert::TryFrom; + +use itertools::Itertools; +use prost::Message; +use uuid::Uuid; + +use crate::consts; +use crate::crypto::hmac_sha256; +use crate::proto::storage as storage_proto; +use crate::{PrivateKey, PublicKey, Result, SignalProtocolError}; + +#[derive(Debug, Clone)] +pub struct SenderMessageKey { + iteration: u32, + iv: Vec, + cipher_key: Vec, + seed: Vec, +} + +impl SenderMessageKey { + pub fn new(iteration: u32, seed: Vec) -> Result { + let mut derived = [0; 48]; + hkdf::Hkdf::::new(None, &seed) + .expand(b"WhisperGroup", &mut derived) + .expect("valid output length"); + Ok(Self { + iteration, + seed, + iv: derived[0..16].to_vec(), + cipher_key: derived[16..48].to_vec(), + }) + } + + pub fn from_protobuf( + smk: storage_proto::sender_key_state_structure::SenderMessageKey, + ) -> Result { + Self::new(smk.iteration, smk.seed) + } + + pub fn iteration(&self) -> Result { + Ok(self.iteration) + } + + pub fn iv(&self) -> Result> { + Ok(self.iv.clone()) + } + + pub fn cipher_key(&self) -> Result> { + Ok(self.cipher_key.clone()) + } + + pub fn seed(&self) -> Result> { + Ok(self.seed.clone()) + } + + pub fn as_protobuf( + &self, + ) -> Result { + Ok( + storage_proto::sender_key_state_structure::SenderMessageKey { + iteration: self.iteration, + seed: self.seed.clone(), + }, + ) + } +} + +#[derive(Debug, Clone)] +pub struct SenderChainKey { + iteration: u32, + chain_key: Vec, +} + +impl SenderChainKey { + const MESSAGE_KEY_SEED: u8 = 0x01; + const CHAIN_KEY_SEED: u8 = 0x02; + + pub fn new(iteration: u32, chain_key: Vec) -> Result { + Ok(Self { + iteration, + chain_key, + }) + } + + pub fn iteration(&self) -> Result { + Ok(self.iteration) + } + + pub fn seed(&self) -> Result> { + Ok(self.chain_key.clone()) + } + + pub fn next(&self) -> Result { + SenderChainKey::new( + self.iteration + 1, + self.get_derivative(Self::CHAIN_KEY_SEED)?, + ) + } + + pub fn sender_message_key(&self) -> Result { + SenderMessageKey::new(self.iteration, self.get_derivative(Self::MESSAGE_KEY_SEED)?) + } + + fn get_derivative(&self, label: u8) -> Result> { + let label = [label]; + Ok(hmac_sha256(&self.chain_key, &label)?.to_vec()) + } + + pub fn as_protobuf(&self) -> Result { + Ok(storage_proto::sender_key_state_structure::SenderChainKey { + iteration: self.iteration, + seed: self.chain_key.clone(), + }) + } +} + +#[derive(Debug, Clone)] +pub struct SenderKeyState { + state: storage_proto::SenderKeyStateStructure, +} + +impl SenderKeyState { + pub fn new( + message_version: u8, + chain_id: u32, + iteration: u32, + chain_key: &[u8], + signature_key: PublicKey, + signature_private_key: Option, + ) -> Result { + let state = storage_proto::SenderKeyStateStructure { + message_version: message_version as u32, + chain_id, + sender_chain_key: Some( + SenderChainKey::new(iteration, chain_key.to_vec())?.as_protobuf()?, + ), + sender_signing_key: Some( + storage_proto::sender_key_state_structure::SenderSigningKey { + public: signature_key.serialize().to_vec(), + private: match signature_private_key { + None => vec![], + Some(k) => k.serialize().to_vec(), + }, + }, + ), + sender_message_keys: vec![], + }; + + Ok(Self { state }) + } + + pub fn deserialize(buf: &[u8]) -> Result { + let state = storage_proto::SenderKeyStateStructure::decode(buf)?; + Ok(Self { state }) + } + + pub fn from_protobuf(state: storage_proto::SenderKeyStateStructure) -> Self { + Self { state } + } + + pub fn serialize(&self) -> Result> { + Ok(self.state.encode_to_vec()) + } + + pub fn message_version(&self) -> Result { + match self.state.message_version { + 0 => Ok(3), // the first SenderKey version + v => Ok(v), + } + } + + pub fn chain_id(&self) -> Result { + Ok(self.state.chain_id) + } + + pub fn sender_chain_key(&self) -> Result { + let sender_chain = self + .state + .sender_chain_key + .as_ref() + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + SenderChainKey::new(sender_chain.iteration, sender_chain.seed.clone()) + } + + pub fn set_sender_chain_key(&mut self, chain_key: SenderChainKey) -> Result<()> { + self.state.sender_chain_key = Some(chain_key.as_protobuf()?); + Ok(()) + } + + pub fn signing_key_public(&self) -> Result { + if let Some(ref signing_key) = self.state.sender_signing_key { + Ok(PublicKey::try_from(&signing_key.public[..])?) + } else { + Err(SignalProtocolError::InvalidProtobufEncoding) + } + } + + pub fn signing_key_private(&self) -> Result { + if let Some(ref signing_key) = self.state.sender_signing_key { + Ok(PrivateKey::deserialize(&signing_key.private)?) + } else { + Err(SignalProtocolError::InvalidProtobufEncoding) + } + } + + pub fn has_sender_message_key(&self, iteration: u32) -> Result { + for sender_message_key in &self.state.sender_message_keys { + if sender_message_key.iteration == iteration { + return Ok(true); + } + } + Ok(false) + } + + pub fn as_protobuf(&self) -> Result { + Ok(self.state.clone()) + } + + pub fn add_sender_message_key(&mut self, sender_message_key: &SenderMessageKey) -> Result<()> { + self.state + .sender_message_keys + .push(sender_message_key.as_protobuf()?); + while self.state.sender_message_keys.len() > consts::MAX_MESSAGE_KEYS { + self.state.sender_message_keys.remove(0); + } + Ok(()) + } + + pub fn remove_sender_message_key( + &mut self, + iteration: u32, + ) -> Result> { + if let Some(index) = self + .state + .sender_message_keys + .iter() + .position(|x| x.iteration == iteration) + { + let smk = self.state.sender_message_keys.remove(index); + Ok(Some(SenderMessageKey::from_protobuf(smk)?)) + } else { + Ok(None) + } + } +} + +#[derive(Debug, Clone)] +pub struct SenderKeyRecord { + states: VecDeque, +} + +impl SenderKeyRecord { + pub fn new_empty() -> Self { + Self { + states: VecDeque::with_capacity(consts::MAX_SENDER_KEY_STATES), + } + } + + pub fn deserialize(buf: &[u8]) -> Result { + let skr = storage_proto::SenderKeyRecordStructure::decode(buf)?; + + let mut states = VecDeque::with_capacity(skr.sender_key_states.len()); + for state in skr.sender_key_states { + states.push_back(SenderKeyState::from_protobuf(state)) + } + Ok(Self { states }) + } + + pub fn is_empty(&self) -> Result { + Ok(self.states.is_empty()) + } + + pub fn sender_key_state(&mut self) -> Result<&mut SenderKeyState> { + if !self.states.is_empty() { + return Ok(&mut self.states[0]); + } + Err(SignalProtocolError::NoSenderKeyState) + } + + pub fn sender_key_state_for_chain_id( + &mut self, + chain_id: u32, + distribution_id: Uuid, + ) -> Result<&mut SenderKeyState> { + for i in 0..self.states.len() { + if self.states[i].chain_id()? == chain_id { + return Ok(&mut self.states[i]); + } + } + log::error!( + "SenderKey distribution {} could not find chain ID {} (known chain IDs: {:?})", + distribution_id, + chain_id, + self.states + .iter() + .map(|state| state.chain_id().expect("accessed successfully above")) + .collect::>() + ); + Err(SignalProtocolError::NoSenderKeyState) + } + + pub fn add_sender_key_state( + &mut self, + message_version: u8, + chain_id: u32, + iteration: u32, + chain_key: &[u8], + signature_key: PublicKey, + signature_private_key: Option, + ) -> Result<()> { + let existing_state = self.remove_state(chain_id, signature_key); + + if self.remove_states_with_chain_id(chain_id) > 0 { + log::warn!( + "Removed a matching chain_id ({}) found with a different public key", + chain_id + ); + } + + let state = match existing_state { + None => SenderKeyState::new( + message_version, + chain_id, + iteration, + chain_key, + signature_key, + signature_private_key, + )?, + Some(state) => state, + }; + + while self.states.len() >= consts::MAX_SENDER_KEY_STATES { + self.states.pop_back(); + } + + self.states.push_front(state); + + Ok(()) + } + + /// Remove the state with the matching `chain_id` and `signature_key`. + /// + /// Skips any bad protobufs. + fn remove_state(&mut self, chain_id: u32, signature_key: PublicKey) -> Option { + let (index, _state) = self.states.iter().find_position(|state| { + state.chain_id().ok() == Some(chain_id) + && state.signing_key_public().ok() == Some(signature_key) + })?; + + self.states.remove(index) + } + + /// Returns the number of removed states. + /// + /// Skips any bad protobufs. + fn remove_states_with_chain_id(&mut self, chain_id: u32) -> usize { + let initial_length = self.states.len(); + self.states + .retain(|state| state.chain_id().ok() != Some(chain_id)); + initial_length - self.states.len() + } + + pub fn set_sender_key_state( + &mut self, + message_version: u8, + chain_id: u32, + iteration: u32, + chain_key: &[u8], + signature_key: PublicKey, + signature_private_key: Option, + ) -> Result<()> { + self.states.clear(); + self.add_sender_key_state( + message_version, + chain_id, + iteration, + chain_key, + signature_key, + signature_private_key, + ) + } + + pub fn as_protobuf(&self) -> Result { + let mut states = Vec::with_capacity(self.states.len()); + for state in &self.states { + states.push(state.as_protobuf()?); + } + + Ok(storage_proto::SenderKeyRecordStructure { + sender_key_states: states, + }) + } + + pub fn serialize(&self) -> Result> { + Ok(self.as_protobuf()?.encode_to_vec()) + } +} + +#[cfg(test)] +mod sender_key_record_add_sender_key_state_tests { + use itertools::Itertools; + use rand::rngs::OsRng; + + use crate::KeyPair; + + use super::*; + + fn random_public_key() -> PublicKey { + KeyPair::generate(&mut OsRng).public_key + } + + fn chain_key(i: u128) -> Vec { + i.to_be_bytes().to_vec() + } + + struct TestContext { + sender_key_record: SenderKeyRecord, + } + + impl TestContext { + fn new() -> Self { + Self { + sender_key_record: SenderKeyRecord::new_empty(), + } + } + + /// Associates the `record_key` with the `chain_key` via `add_sender_key_state` which is the + /// method under test in this module. + fn add_sender_key_state_record(&mut self, record_key: (PublicKey, u32), chain_key: &[u8]) { + let (public_key, chain_id) = record_key; + self.sender_key_record + .add_sender_key_state(1, chain_id, 1, chain_key, public_key, None) + .expect("to be able to add new state"); + } + + fn assert_number_of_states(&self, expected: usize) { + assert_eq!(expected, self.sender_key_record.states.len()); + } + + /// Asserts that for the supplied `record_key` the chain key is as expected when looked up + /// by both `chain_id` and `public_key` and `chain_id`. + fn assert_records_chain_key( + &mut self, + record_key: (PublicKey, u32), + expected_chain_key: &[u8], + ) { + let (public_key, chain_id) = record_key; + let found_chain_key = self + .sender_key_record + .sender_key_state_for_chain_id(chain_id, Uuid::default()) + .expect("Expect to find chain id") + .sender_chain_key() + .expect("Expect to find chain key") + .chain_key; + + assert_eq!(found_chain_key, expected_chain_key); + + let matching_state = self + .sender_key_record + .states + .iter() + .filter(|state| { + state.chain_id().expect("expect chain id") == chain_id + && state.signing_key_public().expect("expect public key") == public_key + }) + .exactly_one() + .expect("Expected exactly one record key match"); + + assert_eq!( + &matching_state + .sender_chain_key() + .expect("Expect to find chain key") + .chain_key, + expected_chain_key + ); + } + + fn assert_record_order(&self, order: Vec<(PublicKey, u32)>) { + let record_keys = self + .sender_key_record + .states + .iter() + .map(|state| { + ( + state.signing_key_public().expect("expect public key"), + state.chain_id().expect("expect chain id"), + ) + }) + .collect::>(); + + assert_eq!(record_keys, order); + } + } + + #[test] + fn add_single_state() { + let mut context = TestContext::new(); + + let public_key = random_public_key(); + let chain_id = 1; + let chain_key = chain_key(1); + let record_key = (public_key, chain_id); + + context.add_sender_key_state_record(record_key, &chain_key); + + context.assert_number_of_states(1); + context.assert_records_chain_key(record_key, &chain_key); + } + + #[test] + fn add_second_state() { + let mut context = TestContext::new(); + + let chain_id_1 = 1; + let chain_id_2 = 2; + let record_key_1 = (random_public_key(), chain_id_1); + let record_key_2 = (random_public_key(), chain_id_2); + let chain_key_1 = chain_key(1); + let chain_key_2 = chain_key(2); + + context.add_sender_key_state_record(record_key_1, &chain_key_1); + context.add_sender_key_state_record(record_key_2, &chain_key_2); + + context.assert_number_of_states(2); + context.assert_records_chain_key(record_key_1, &chain_key_1); + context.assert_records_chain_key(record_key_2, &chain_key_2); + } + + #[test] + fn when_exceed_maximum_states_then_oldest_is_ejected() { + assert_eq!( + 5, + consts::MAX_SENDER_KEY_STATES, + "Test written to expect this limit" + ); + + let mut context = TestContext::new(); + + let record_key_1 = (random_public_key(), 1); + let record_key_2 = (random_public_key(), 2); + let record_key_3 = (random_public_key(), 3); + let record_key_4 = (random_public_key(), 4); + let record_key_5 = (random_public_key(), 5); + let record_key_6 = (random_public_key(), 6); + + context.add_sender_key_state_record(record_key_1, &chain_key(1)); + context.add_sender_key_state_record(record_key_2, &chain_key(2)); + context.add_sender_key_state_record(record_key_3, &chain_key(3)); + context.add_sender_key_state_record(record_key_4, &chain_key(4)); + context.add_sender_key_state_record(record_key_5, &chain_key(5)); + + context.assert_record_order(vec![ + record_key_5, + record_key_4, + record_key_3, + record_key_2, + record_key_1, + ]); + + context.add_sender_key_state_record(record_key_6, &chain_key(6)); + + context.assert_record_order(vec![ + record_key_6, + record_key_5, + record_key_4, + record_key_3, + record_key_2, + ]); + } + + #[test] + fn when_second_state_with_same_public_key_and_chain_id_added_then_it_keeps_first_data() { + let mut context = TestContext::new(); + + let chain_id = 1; + let record_key = (random_public_key(), chain_id); + let chain_key_1 = chain_key(1); + let chain_key_2 = chain_key(2); + + context.add_sender_key_state_record(record_key, &chain_key_1); + context.add_sender_key_state_record(record_key, &chain_key_2); + + context.assert_number_of_states(1); + context.assert_records_chain_key(record_key, &chain_key_1); + } + + #[test] + fn when_second_state_with_different_public_key_but_same_chain_id_added_then_it_gets_replaced() { + let mut context = TestContext::new(); + + let chain_id = 1; + let record_key_1 = (random_public_key(), chain_id); + let record_key_2 = (random_public_key(), chain_id); + let chain_key_1 = chain_key(1); + let chain_key_2 = chain_key(2); + + context.add_sender_key_state_record(record_key_1, &chain_key_1); + context.add_sender_key_state_record(record_key_2, &chain_key_2); + + context.assert_number_of_states(1); + context.assert_records_chain_key(record_key_2, &chain_key_2); + } + + #[test] + fn when_second_state_with_same_public_key_and_chain_id_added_then_it_becomes_the_most_recent() { + let mut context = TestContext::new(); + + let chain_id_1 = 1; + let chain_id_2 = 2; + let record_key_1 = (random_public_key(), chain_id_1); + let record_key_2 = (random_public_key(), chain_id_2); + let chain_key_1 = chain_key(1); + let chain_key_2 = chain_key(2); + let chain_key_3 = chain_key(3); + + context.add_sender_key_state_record(record_key_1, &chain_key_1); + context.add_sender_key_state_record(record_key_2, &chain_key_2); + + context.assert_record_order(vec![record_key_2, record_key_1]); + + context.add_sender_key_state_record(record_key_1, &chain_key_3); + + context.assert_record_order(vec![record_key_1, record_key_2]); + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/session.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/session.rs new file mode 100644 index 0000000..a2e9b30 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/session.rs @@ -0,0 +1,205 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::{ + Context, Direction, IdentityKeyStore, KeyPair, PreKeyBundle, PreKeySignalMessage, PreKeyStore, + ProtocolAddress, Result, SessionRecord, SessionStore, SignalProtocolError, SignedPreKeyStore, +}; + +use crate::ratchet; +use crate::ratchet::{AliceSignalProtocolParameters, BobSignalProtocolParameters}; +use crate::state::PreKeyId; +use rand::{CryptoRng, Rng}; + +/* +These functions are on SessionBuilder in Java + +However using SessionBuilder + SessionCipher at the same time causes +&mut sharing issues. And as SessionBuilder has no actual state beyond +its reference to the various data stores, instead the functions are +free standing. + */ + +pub async fn process_prekey( + message: &PreKeySignalMessage, + remote_address: &ProtocolAddress, + session_record: &mut SessionRecord, + identity_store: &mut dyn IdentityKeyStore, + pre_key_store: &mut dyn PreKeyStore, + signed_prekey_store: &mut dyn SignedPreKeyStore, + ctx: Context, +) -> Result> { + let their_identity_key = message.identity_key(); + + if !identity_store + .is_trusted_identity( + remote_address, + their_identity_key, + Direction::Receiving, + ctx, + ) + .await? + { + return Err(SignalProtocolError::UntrustedIdentity( + remote_address.clone(), + )); + } + + let unsigned_pre_key_id = process_prekey_v3( + message, + remote_address, + session_record, + signed_prekey_store, + pre_key_store, + identity_store, + ctx, + ) + .await?; + + identity_store + .save_identity(remote_address, their_identity_key, ctx) + .await?; + + Ok(unsigned_pre_key_id) +} + +async fn process_prekey_v3( + message: &PreKeySignalMessage, + remote_address: &ProtocolAddress, + session_record: &mut SessionRecord, + signed_prekey_store: &mut dyn SignedPreKeyStore, + pre_key_store: &mut dyn PreKeyStore, + identity_store: &mut dyn IdentityKeyStore, + ctx: Context, +) -> Result> { + if session_record.has_session_state( + message.message_version() as u32, + &message.base_key().serialize(), + )? { + // We've already setup a session for this V3 message, letting bundled message fall through + return Ok(None); + } + + let our_signed_pre_key_pair = signed_prekey_store + .get_signed_pre_key(message.signed_pre_key_id(), ctx) + .await? + .key_pair()?; + + let our_one_time_pre_key_pair = if let Some(pre_key_id) = message.pre_key_id() { + log::info!("processing PreKey message from {}", remote_address); + Some( + pre_key_store + .get_pre_key(pre_key_id, ctx) + .await? + .key_pair()?, + ) + } else { + log::warn!( + "processing PreKey message from {} which had no one-time prekey", + remote_address + ); + None + }; + + let parameters = BobSignalProtocolParameters::new( + identity_store.get_identity_key_pair(ctx).await?, + our_signed_pre_key_pair, // signed pre key + our_one_time_pre_key_pair, + our_signed_pre_key_pair, // ratchet key + *message.identity_key(), + *message.base_key(), + ); + + session_record.archive_current_state()?; + + let mut new_session = ratchet::initialize_bob_session(¶meters)?; + + new_session.set_local_registration_id(identity_store.get_local_registration_id(ctx).await?)?; + new_session.set_remote_registration_id(message.registration_id())?; + new_session.set_alice_base_key(&message.base_key().serialize())?; + + session_record.promote_state(new_session)?; + + Ok(message.pre_key_id()) +} + +pub async fn process_prekey_bundle( + remote_address: &ProtocolAddress, + session_store: &mut dyn SessionStore, + identity_store: &mut dyn IdentityKeyStore, + bundle: &PreKeyBundle, + mut csprng: &mut R, + ctx: Context, +) -> Result<()> { + let their_identity_key = bundle.identity_key()?; + + if !identity_store + .is_trusted_identity(remote_address, their_identity_key, Direction::Sending, ctx) + .await? + { + return Err(SignalProtocolError::UntrustedIdentity( + remote_address.clone(), + )); + } + + if !their_identity_key.public_key().verify_signature( + &bundle.signed_pre_key_public()?.serialize(), + bundle.signed_pre_key_signature()?, + )? { + return Err(SignalProtocolError::SignatureValidationFailed); + } + + let mut session_record = session_store + .load_session(remote_address, ctx) + .await? + .unwrap_or_else(SessionRecord::new_fresh); + + let our_base_key_pair = KeyPair::generate(&mut csprng); + let their_signed_prekey = bundle.signed_pre_key_public()?; + + let their_one_time_prekey = bundle.pre_key_public()?; + let their_one_time_prekey_id = bundle.pre_key_id()?; + + let our_identity_key_pair = identity_store.get_identity_key_pair(ctx).await?; + + let parameters = AliceSignalProtocolParameters::new( + our_identity_key_pair, + our_base_key_pair, + *their_identity_key, + their_signed_prekey, + their_one_time_prekey, + their_signed_prekey, + ); + + let mut session = ratchet::initialize_alice_session(¶meters, csprng)?; + + log::info!( + "set_unacknowledged_pre_key_message for: {} with preKeyId: {}", + remote_address, + their_one_time_prekey_id.map_or_else(|| "".to_string(), |id| id.to_string()) + ); + + session.set_unacknowledged_pre_key_message( + their_one_time_prekey_id, + bundle.signed_pre_key_id()?, + &our_base_key_pair.public_key, + )?; + + session.set_local_registration_id(identity_store.get_local_registration_id(ctx).await?)?; + session.set_remote_registration_id(bundle.registration_id()?)?; + session.set_alice_base_key(&our_base_key_pair.public_key.serialize())?; + + identity_store + .save_identity(remote_address, their_identity_key, ctx) + .await?; + + session_record.promote_state(session)?; + + session_store + .store_session(remote_address, &session_record, ctx) + .await?; + + Ok(()) +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/session_cipher.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/session_cipher.rs new file mode 100644 index 0000000..0625a0a --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/session_cipher.rs @@ -0,0 +1,636 @@ +// +// Copyright 2020-2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::{ + CiphertextMessage, Context, Direction, IdentityKeyStore, KeyPair, PreKeySignalMessage, + PreKeyStore, ProtocolAddress, PublicKey, Result, SessionRecord, SessionStore, SignalMessage, + SignalProtocolError, SignedPreKeyStore, +}; + +use crate::consts::MAX_FORWARD_JUMPS; +use crate::crypto; +use crate::ratchet::{ChainKey, MessageKeys}; +use crate::session; +use crate::state::SessionState; + +use rand::{CryptoRng, Rng}; + +pub async fn message_encrypt( + ptext: &[u8], + remote_address: &ProtocolAddress, + session_store: &mut dyn SessionStore, + identity_store: &mut dyn IdentityKeyStore, + ctx: Context, +) -> Result { + let mut session_record = session_store + .load_session(remote_address, ctx) + .await? + .ok_or_else(|| SignalProtocolError::SessionNotFound(format!("{}", remote_address)))?; + let session_state = session_record.session_state_mut()?; + + let chain_key = session_state.get_sender_chain_key()?; + + let message_keys = chain_key.message_keys()?; + + let sender_ephemeral = session_state.sender_ratchet_key()?; + let previous_counter = session_state.previous_counter()?; + let session_version = session_state.session_version()? as u8; + + let local_identity_key = session_state.local_identity_key()?; + let their_identity_key = session_state + .remote_identity_key()? + .ok_or(SignalProtocolError::InvalidSessionStructure)?; + + let ctext = crypto::aes_256_cbc_encrypt(ptext, message_keys.cipher_key(), message_keys.iv())?; + + let message = if let Some(items) = session_state.unacknowledged_pre_key_message_items()? { + let local_registration_id = session_state.local_registration_id()?; + + log::info!( + "Building PreKeyWhisperMessage for: {} with preKeyId: {}", + remote_address, + items + .pre_key_id()? + .map_or_else(|| "".to_string(), |id| id.to_string()) + ); + + let message = SignalMessage::new( + session_version, + message_keys.mac_key(), + sender_ephemeral, + chain_key.index(), + previous_counter, + &ctext, + &local_identity_key, + &their_identity_key, + )?; + + CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::new( + session_version, + local_registration_id, + items.pre_key_id()?, + items.signed_pre_key_id()?, + *items.base_key()?, + local_identity_key, + message, + )?) + } else { + CiphertextMessage::SignalMessage(SignalMessage::new( + session_version, + message_keys.mac_key(), + sender_ephemeral, + chain_key.index(), + previous_counter, + &ctext, + &local_identity_key, + &their_identity_key, + )?) + }; + + session_state.set_sender_chain_key(&chain_key.next_chain_key()?)?; + + // XXX why is this check after everything else?!! + if !identity_store + .is_trusted_identity(remote_address, &their_identity_key, Direction::Sending, ctx) + .await? + { + log::warn!( + "Identity key {} is not trusted for remote address {}", + their_identity_key + .public_key() + .public_key_bytes() + .map_or_else(|e| format!("", e), hex::encode), + remote_address, + ); + return Err(SignalProtocolError::UntrustedIdentity( + remote_address.clone(), + )); + } + + // XXX this could be combined with the above call to the identity store (in a new API) + identity_store + .save_identity(remote_address, &their_identity_key, ctx) + .await?; + + session_store + .store_session(remote_address, &session_record, ctx) + .await?; + Ok(message) +} + +pub async fn message_decrypt( + ciphertext: &CiphertextMessage, + remote_address: &ProtocolAddress, + session_store: &mut dyn SessionStore, + identity_store: &mut dyn IdentityKeyStore, + pre_key_store: &mut dyn PreKeyStore, + signed_pre_key_store: &mut dyn SignedPreKeyStore, + csprng: &mut R, + ctx: Context, +) -> Result> { + match ciphertext { + CiphertextMessage::SignalMessage(m) => { + message_decrypt_signal( + m, + remote_address, + session_store, + identity_store, + csprng, + ctx, + ) + .await + } + CiphertextMessage::PreKeySignalMessage(m) => { + message_decrypt_prekey( + m, + remote_address, + session_store, + identity_store, + pre_key_store, + signed_pre_key_store, + csprng, + ctx, + ) + .await + } + _ => Err(SignalProtocolError::InvalidArgument( + "SessionCipher::decrypt cannot decrypt this message type".to_owned(), + )), + } +} + +pub async fn message_decrypt_prekey( + ciphertext: &PreKeySignalMessage, + remote_address: &ProtocolAddress, + session_store: &mut dyn SessionStore, + identity_store: &mut dyn IdentityKeyStore, + pre_key_store: &mut dyn PreKeyStore, + signed_pre_key_store: &mut dyn SignedPreKeyStore, + csprng: &mut R, + ctx: Context, +) -> Result> { + let mut session_record = session_store + .load_session(remote_address, ctx) + .await? + .unwrap_or_else(SessionRecord::new_fresh); + + // Make sure we log the session state if we fail to process the pre-key. + let pre_key_id_or_err = session::process_prekey( + ciphertext, + remote_address, + &mut session_record, + identity_store, + pre_key_store, + signed_pre_key_store, + ctx, + ) + .await; + + let pre_key_id = match pre_key_id_or_err { + Ok(id) => id, + Err(e) => { + let errs = [e]; + log::error!( + "{}", + create_decryption_failure_log( + remote_address, + &errs, + &session_record, + ciphertext.message() + )? + ); + let [e] = errs; + return Err(e); + } + }; + + let ptext = decrypt_message_with_record( + remote_address, + &mut session_record, + ciphertext.message(), + csprng, + )?; + + session_store + .store_session(remote_address, &session_record, ctx) + .await?; + + if let Some(pre_key_id) = pre_key_id { + pre_key_store.remove_pre_key(pre_key_id, ctx).await?; + } + + Ok(ptext) +} + +pub async fn message_decrypt_signal( + ciphertext: &SignalMessage, + remote_address: &ProtocolAddress, + session_store: &mut dyn SessionStore, + identity_store: &mut dyn IdentityKeyStore, + csprng: &mut R, + ctx: Context, +) -> Result> { + let mut session_record = session_store + .load_session(remote_address, ctx) + .await? + .ok_or_else(|| SignalProtocolError::SessionNotFound(format!("{}", remote_address)))?; + + let ptext = + decrypt_message_with_record(remote_address, &mut session_record, ciphertext, csprng)?; + + // Why are we performing this check after decryption instead of before? + let their_identity_key = session_record + .session_state()? + .remote_identity_key()? + .ok_or(SignalProtocolError::InvalidSessionStructure)?; + + if !identity_store + .is_trusted_identity( + remote_address, + &their_identity_key, + Direction::Receiving, + ctx, + ) + .await? + { + log::warn!( + "Identity key {} is not trusted for remote address {}", + their_identity_key + .public_key() + .public_key_bytes() + .map_or_else(|e| format!("", e), hex::encode), + remote_address, + ); + return Err(SignalProtocolError::UntrustedIdentity( + remote_address.clone(), + )); + } + + identity_store + .save_identity(remote_address, &their_identity_key, ctx) + .await?; + + session_store + .store_session(remote_address, &session_record, ctx) + .await?; + + Ok(ptext) +} + +fn create_decryption_failure_log( + remote_address: &ProtocolAddress, + mut errs: &[SignalProtocolError], + record: &SessionRecord, + ciphertext: &SignalMessage, +) -> Result { + fn append_session_summary( + lines: &mut Vec, + idx: usize, + state: Result<&SessionState>, + err: Option<&SignalProtocolError>, + ) { + let chains = state.and_then(|state| state.all_receiver_chain_logging_info()); + match (err, &chains) { + (Some(err), Ok(chains)) => { + lines.push(format!( + "Candidate session {} failed with '{}', had {} receiver chains", + idx, + err, + chains.len() + )); + } + (Some(err), Err(state_err)) => { + lines.push(format!( + "Candidate session {} failed with '{}'; cannot get receiver chain info ({})", + idx, err, state_err, + )); + } + (None, Ok(chains)) => { + lines.push(format!( + "Candidate session {} had {} receiver chains", + idx, + chains.len() + )); + } + (None, Err(state_err)) => { + lines.push(format!( + "Candidate session {}: cannot get receiver chain info ({})", + idx, state_err, + )); + } + } + + if let Ok(chains) = chains { + for chain in chains { + let chain_idx = match chain.1 { + Some(i) => i.to_string(), + None => "missing in protobuf".to_string(), + }; + + lines.push(format!( + "Receiver chain with sender ratchet public key {} chain key index {}", + hex::encode(chain.0), + chain_idx + )); + } + } + } + + let mut lines = vec![]; + + lines.push(format!( + "Message from {} failed to decrypt; sender ratchet public key {} message counter {}", + remote_address, + hex::encode(ciphertext.sender_ratchet_key().public_key_bytes()?), + ciphertext.counter() + )); + + if let Ok(current_session) = record.session_state() { + let err = errs.first(); + if err.is_some() { + errs = &errs[1..]; + } + append_session_summary(&mut lines, 0, Ok(current_session), err); + } else { + lines.push("No current session".to_string()); + } + + for (idx, (state, err)) in record + .previous_session_states() + .zip(errs.iter().map(Some).chain(std::iter::repeat(None))) + .enumerate() + { + let state = match state { + Ok(ref state) => Ok(state), + Err(err) => Err(err), + }; + append_session_summary(&mut lines, idx + 1, state, err); + } + + Ok(lines.join("\n")) +} + +fn decrypt_message_with_record( + remote_address: &ProtocolAddress, + record: &mut SessionRecord, + ciphertext: &SignalMessage, + csprng: &mut R, +) -> Result> { + let log_decryption_failure = |state: &SessionState, error: &SignalProtocolError| { + // A warning rather than an error because we try multiple sessions. + log::warn!( + "Failed to decrypt whisper message with ratchet key: {} and counter: {}. \ + Session loaded for {}. Local session has base key: {} and counter: {}. {}", + ciphertext + .sender_ratchet_key() + .public_key_bytes() + .map_or_else(|e| format!("", e), hex::encode), + ciphertext.counter(), + remote_address, + state + .sender_ratchet_key_for_logging() + .unwrap_or_else(|e| format!("", e)), + state.previous_counter().unwrap_or(u32::MAX), + error + ); + }; + + let mut errs = vec![]; + + if let Ok(current_state) = record.session_state() { + let mut current_state = current_state.clone(); + let result = + decrypt_message_with_state(&mut current_state, ciphertext, remote_address, csprng); + + match result { + Ok(ptext) => { + log::info!( + "decrypted message from {} with current session state (base key {})", + remote_address, + current_state + .sender_ratchet_key_for_logging() + .expect("successful decrypt always has a valid base key"), + ); + record.set_session_state(current_state)?; // update the state + return Ok(ptext); + } + Err(SignalProtocolError::DuplicatedMessage(_, _)) => { + return result; + } + Err(e) => { + log_decryption_failure(¤t_state, &e); + errs.push(e); + } + } + } + + // Try some old sessions: + let mut updated_session = None; + + for (idx, previous) in record.previous_session_states().enumerate() { + let mut previous = previous?; + + let result = decrypt_message_with_state(&mut previous, ciphertext, remote_address, csprng); + + match result { + Ok(ptext) => { + log::info!( + "decrypted message from {} with PREVIOUS session state (base key {})", + remote_address, + previous + .sender_ratchet_key_for_logging() + .expect("successful decrypt always has a valid base key"), + ); + updated_session = Some((ptext, idx, previous)); + break; + } + Err(SignalProtocolError::DuplicatedMessage(_, _)) => { + return result; + } + Err(e) => { + log_decryption_failure(&previous, &e); + errs.push(e); + } + } + } + + if let Some((ptext, idx, updated_session)) = updated_session { + record.promote_old_session(idx, updated_session)?; + Ok(ptext) + } else { + let previous_state_count = || record.previous_session_states().len(); + + if let Ok(current_state) = record.session_state() { + log::error!( + "No valid session for recipient: {}, current session base key {}, number of previous states: {}", + remote_address, + current_state.sender_ratchet_key_for_logging() + .unwrap_or_else(|e| format!("", e)), + previous_state_count(), + ); + } else { + log::error!( + "No valid session for recipient: {}, (no current session state), number of previous states: {}", + remote_address, + previous_state_count(), + ); + } + log::error!( + "{}", + create_decryption_failure_log(remote_address, &errs, record, ciphertext)? + ); + Err(SignalProtocolError::InvalidMessage( + "Message decryption failed", + )) + } +} + +fn decrypt_message_with_state( + state: &mut SessionState, + ciphertext: &SignalMessage, + remote_address: &ProtocolAddress, + csprng: &mut R, +) -> Result> { + if !state.has_sender_chain()? { + return Err(SignalProtocolError::InvalidMessage( + "No session available to decrypt", + )); + } + + let ciphertext_version = ciphertext.message_version() as u32; + if ciphertext_version != state.session_version()? { + return Err(SignalProtocolError::UnrecognizedMessageVersion( + ciphertext_version, + )); + } + + let their_ephemeral = ciphertext.sender_ratchet_key(); + let counter = ciphertext.counter(); + let chain_key = get_or_create_chain_key(state, their_ephemeral, remote_address, csprng)?; + let message_keys = + get_or_create_message_key(state, their_ephemeral, remote_address, &chain_key, counter)?; + + let their_identity_key = state + .remote_identity_key()? + .ok_or(SignalProtocolError::InvalidSessionStructure)?; + + let mac_valid = ciphertext.verify_mac( + &their_identity_key, + &state.local_identity_key()?, + message_keys.mac_key(), + )?; + + if !mac_valid { + return Err(SignalProtocolError::InvalidCiphertext); + } + + let ptext = crypto::aes_256_cbc_decrypt( + ciphertext.body(), + message_keys.cipher_key(), + message_keys.iv(), + )?; + + state.clear_unacknowledged_pre_key_message()?; + + Ok(ptext) +} + +fn get_or_create_chain_key( + state: &mut SessionState, + their_ephemeral: &PublicKey, + remote_address: &ProtocolAddress, + csprng: &mut R, +) -> Result { + if let Some(chain) = state.get_receiver_chain_key(their_ephemeral)? { + log::debug!("{} has existing receiver chain.", remote_address); + return Ok(chain); + } + + log::info!("{} creating new chains.", remote_address); + + let root_key = state.root_key()?; + let our_ephemeral = state.sender_ratchet_private_key()?; + let receiver_chain = root_key.create_chain(their_ephemeral, &our_ephemeral)?; + let our_new_ephemeral = KeyPair::generate(csprng); + let sender_chain = receiver_chain + .0 + .create_chain(their_ephemeral, &our_new_ephemeral.private_key)?; + + state.set_root_key(&sender_chain.0)?; + state.add_receiver_chain(their_ephemeral, &receiver_chain.1)?; + + let current_index = state.get_sender_chain_key()?.index(); + let previous_index = if current_index > 0 { + current_index - 1 + } else { + 0 + }; + state.set_previous_counter(previous_index)?; + state.set_sender_chain(&our_new_ephemeral, &sender_chain.1)?; + + Ok(receiver_chain.1) +} + +fn get_or_create_message_key( + state: &mut SessionState, + their_ephemeral: &PublicKey, + remote_address: &ProtocolAddress, + chain_key: &ChainKey, + counter: u32, +) -> Result { + let chain_index = chain_key.index(); + + if chain_index > counter { + return match state.get_message_keys(their_ephemeral, counter)? { + Some(keys) => Ok(keys), + None => { + log::info!( + "{} Duplicate message for counter: {}", + remote_address, + counter + ); + Err(SignalProtocolError::DuplicatedMessage(chain_index, counter)) + } + }; + } + + assert!(chain_index <= counter); + + let jump = (counter - chain_index) as usize; + + if jump > MAX_FORWARD_JUMPS { + if state.session_with_self()? { + log::info!( + "{} Jumping ahead {} messages (index: {}, counter: {})", + remote_address, + jump, + chain_index, + counter + ); + } else { + log::error!( + "{} Exceeded future message limit: {}, index: {}, counter: {})", + remote_address, + MAX_FORWARD_JUMPS, + chain_index, + counter + ); + return Err(SignalProtocolError::InvalidMessage( + "message from too far into the future", + )); + } + } + + let mut chain_key = chain_key.clone(); + + while chain_key.index() < counter { + let message_keys = chain_key.message_keys()?; + state.set_message_keys(their_ephemeral, &message_keys)?; + chain_key = chain_key.next_chain_key()?; + } + + state.set_receiver_chain_key(their_ephemeral, &chain_key.next_chain_key()?)?; + chain_key.message_keys() +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/state.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/state.rs new file mode 100644 index 0000000..cf9fa1d --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/state.rs @@ -0,0 +1,15 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +mod bundle; +mod prekey; +mod session; +mod signed_prekey; + +pub use bundle::PreKeyBundle; +pub use prekey::{PreKeyId, PreKeyRecord}; +pub use session::SessionRecord; +pub(crate) use session::SessionState; +pub use signed_prekey::{SignedPreKeyId, SignedPreKeyRecord}; diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/state/bundle.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/state/bundle.rs new file mode 100644 index 0000000..e306528 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/state/bundle.rs @@ -0,0 +1,79 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::state::{PreKeyId, SignedPreKeyId}; +use crate::{IdentityKey, PublicKey, Result}; + +#[derive(Debug, Clone)] +pub struct PreKeyBundle { + registration_id: u32, + device_id: u32, + pre_key_id: Option, + pre_key_public: Option, + signed_pre_key_id: SignedPreKeyId, + signed_pre_key_public: PublicKey, + signed_pre_key_signature: Vec, + identity_key: IdentityKey, +} + +impl PreKeyBundle { + pub fn new( + registration_id: u32, + device_id: u32, + pre_key: Option<(PreKeyId, PublicKey)>, + signed_pre_key_id: SignedPreKeyId, + signed_pre_key_public: PublicKey, + signed_pre_key_signature: Vec, + identity_key: IdentityKey, + ) -> Result { + let (pre_key_id, pre_key_public) = match pre_key { + None => (None, None), + Some((id, key)) => (Some(id), Some(key)), + }; + + Ok(Self { + registration_id, + device_id, + pre_key_id, + pre_key_public, + signed_pre_key_id, + signed_pre_key_public, + signed_pre_key_signature, + identity_key, + }) + } + + pub fn registration_id(&self) -> Result { + Ok(self.registration_id) + } + + pub fn device_id(&self) -> Result { + Ok(self.device_id) + } + + pub fn pre_key_id(&self) -> Result> { + Ok(self.pre_key_id) + } + + pub fn pre_key_public(&self) -> Result> { + Ok(self.pre_key_public) + } + + pub fn signed_pre_key_id(&self) -> Result { + Ok(self.signed_pre_key_id) + } + + pub fn signed_pre_key_public(&self) -> Result { + Ok(self.signed_pre_key_public) + } + + pub fn signed_pre_key_signature(&self) -> Result<&[u8]> { + Ok(self.signed_pre_key_signature.as_ref()) + } + + pub fn identity_key(&self) -> Result<&IdentityKey> { + Ok(&self.identity_key) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/state/prekey.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/state/prekey.rs new file mode 100644 index 0000000..5927a79 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/state/prekey.rs @@ -0,0 +1,55 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::proto::storage::PreKeyRecordStructure; +use crate::{KeyPair, PrivateKey, PublicKey, Result}; +use prost::Message; + +pub type PreKeyId = u32; + +#[derive(Debug, Clone)] +pub struct PreKeyRecord { + pre_key: PreKeyRecordStructure, +} + +impl PreKeyRecord { + pub fn new(id: PreKeyId, key: &KeyPair) -> Self { + let public_key = key.public_key.serialize().to_vec(); + let private_key = key.private_key.serialize().to_vec(); + Self { + pre_key: PreKeyRecordStructure { + id, + public_key, + private_key, + }, + } + } + + pub fn deserialize(data: &[u8]) -> Result { + Ok(Self { + pre_key: PreKeyRecordStructure::decode(data)?, + }) + } + + pub fn id(&self) -> Result { + Ok(self.pre_key.id) + } + + pub fn key_pair(&self) -> Result { + KeyPair::from_public_and_private(&self.pre_key.public_key, &self.pre_key.private_key) + } + + pub fn public_key(&self) -> Result { + PublicKey::deserialize(&self.pre_key.public_key) + } + + pub fn private_key(&self) -> Result { + PrivateKey::deserialize(&self.pre_key.private_key) + } + + pub fn serialize(&self) -> Result> { + Ok(self.pre_key.encode_to_vec()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/state/session.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/state/session.rs new file mode 100644 index 0000000..252fd00 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/state/session.rs @@ -0,0 +1,640 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use prost::Message; + +use crate::ratchet::{ChainKey, MessageKeys, RootKey}; +use crate::{IdentityKey, KeyPair, PrivateKey, PublicKey, Result, SignalProtocolError}; + +use crate::consts; +use crate::proto::storage::session_structure; +use crate::proto::storage::{RecordStructure, SessionStructure}; +use crate::state::{PreKeyId, SignedPreKeyId}; + +#[derive(Debug, Clone)] +pub(crate) struct UnacknowledgedPreKeyMessageItems { + pre_key_id: Option, + signed_pre_key_id: SignedPreKeyId, + base_key: PublicKey, +} + +impl UnacknowledgedPreKeyMessageItems { + fn new( + pre_key_id: Option, + signed_pre_key_id: SignedPreKeyId, + base_key: PublicKey, + ) -> Self { + Self { + pre_key_id, + signed_pre_key_id, + base_key, + } + } + + pub(crate) fn pre_key_id(&self) -> Result> { + Ok(self.pre_key_id) + } + + pub(crate) fn signed_pre_key_id(&self) -> Result { + Ok(self.signed_pre_key_id) + } + + pub(crate) fn base_key(&self) -> Result<&PublicKey> { + Ok(&self.base_key) + } +} + +#[derive(Clone, Debug)] +pub(crate) struct SessionState { + session: SessionStructure, +} + +impl SessionState { + pub(crate) fn new(session: SessionStructure) -> Self { + Self { session } + } + + pub(crate) fn alice_base_key(&self) -> Result<&[u8]> { + // Check the length before returning? + Ok(&self.session.alice_base_key) + } + + pub(crate) fn set_alice_base_key(&mut self, key: &[u8]) -> Result<()> { + // Should we check the length? + self.session.alice_base_key = key.to_vec(); + Ok(()) + } + + pub fn session_version(&self) -> Result { + match self.session.session_version { + 0 => Ok(2), + v => Ok(v), + } + } + + pub(crate) fn remote_identity_key(&self) -> Result> { + match self.session.remote_identity_public.len() { + 0 => Ok(None), + _ => Ok(Some(IdentityKey::decode( + &self.session.remote_identity_public, + )?)), + } + } + + pub(crate) fn remote_identity_key_bytes(&self) -> Result>> { + Ok(self.remote_identity_key()?.map(|k| k.serialize().to_vec())) + } + + pub(crate) fn local_identity_key(&self) -> Result { + IdentityKey::decode(&self.session.local_identity_public) + } + + pub(crate) fn local_identity_key_bytes(&self) -> Result> { + Ok(self.local_identity_key()?.serialize().to_vec()) + } + + pub(crate) fn session_with_self(&self) -> Result { + if let Some(remote_id) = self.remote_identity_key_bytes()? { + let local_id = self.local_identity_key_bytes()?; + return Ok(remote_id == local_id); + } + + // If remote ID is not set then we can't be sure but treat as non-self + Ok(false) + } + + pub(crate) fn previous_counter(&self) -> Result { + Ok(self.session.previous_counter) + } + + pub(crate) fn set_previous_counter(&mut self, ctr: u32) -> Result<()> { + self.session.previous_counter = ctr; + Ok(()) + } + + pub(crate) fn root_key(&self) -> Result { + if self.session.root_key.len() != 32 { + return Err(SignalProtocolError::InvalidProtobufEncoding); + } + RootKey::new(&self.session.root_key) + } + + pub(crate) fn set_root_key(&mut self, root_key: &RootKey) -> Result<()> { + self.session.root_key = root_key.key().to_vec(); + Ok(()) + } + + pub(crate) fn sender_ratchet_key(&self) -> Result { + match self.session.sender_chain { + None => Err(SignalProtocolError::InvalidProtobufEncoding), + Some(ref c) => PublicKey::deserialize(&c.sender_ratchet_key), + } + } + + pub(crate) fn sender_ratchet_key_for_logging(&self) -> Result { + self.sender_ratchet_key()? + .public_key_bytes() + .map(hex::encode) + } + + pub(crate) fn sender_ratchet_private_key(&self) -> Result { + match self.session.sender_chain { + None => Err(SignalProtocolError::InvalidProtobufEncoding), + Some(ref c) => PrivateKey::deserialize(&c.sender_ratchet_key_private), + } + } + + pub fn has_sender_chain(&self) -> Result { + Ok(self.session.sender_chain.is_some()) + } + + pub(crate) fn all_receiver_chain_logging_info(&self) -> Result, Option)>> { + let mut results = vec![]; + for chain in self.session.receiver_chains.iter() { + let sender_ratchet_public = chain.sender_ratchet_key.clone(); + + let chain_key_idx = chain.chain_key.as_ref().map(|chain_key| chain_key.index); + + results.push((sender_ratchet_public, chain_key_idx)) + } + Ok(results) + } + + pub(crate) fn get_receiver_chain( + &self, + sender: &PublicKey, + ) -> Result> { + let sender_bytes = sender.serialize(); + + for (idx, chain) in self.session.receiver_chains.iter().enumerate() { + /* + If we compared bytes directly without a deserialize + serialize pair it would + be faster, but may miss non-canonical points. It's unclear if supporting such + points is desirable. + */ + let this_point = PublicKey::deserialize(&chain.sender_ratchet_key)?.serialize(); + + if this_point == sender_bytes { + return Ok(Some((chain.clone(), idx))); + } + } + + Ok(None) + } + + pub(crate) fn get_receiver_chain_key(&self, sender: &PublicKey) -> Result> { + match self.get_receiver_chain(sender)? { + None => Ok(None), + Some((chain, _)) => match chain.chain_key { + None => Err(SignalProtocolError::InvalidProtobufEncoding), + Some(c) => { + if c.key.len() != 32 { + return Err(SignalProtocolError::InvalidProtobufEncoding); + } + Ok(Some(ChainKey::new(&c.key, c.index)?)) + } + }, + } + } + + pub(crate) fn add_receiver_chain( + &mut self, + sender: &PublicKey, + chain_key: &ChainKey, + ) -> Result<()> { + let chain_key = session_structure::chain::ChainKey { + index: chain_key.index(), + key: chain_key.key().to_vec(), + }; + + let chain = session_structure::Chain { + sender_ratchet_key: sender.serialize().to_vec(), + sender_ratchet_key_private: vec![], + chain_key: Some(chain_key), + message_keys: vec![], + }; + + self.session.receiver_chains.push(chain); + + if self.session.receiver_chains.len() > consts::MAX_RECEIVER_CHAINS { + log::info!( + "Trimming excessive receiver_chain for session with base key {}, chain count: {}", + self.sender_ratchet_key_for_logging() + .unwrap_or_else(|e| format!("", e)), + self.session.receiver_chains.len() + ); + self.session.receiver_chains.remove(0); + } + + Ok(()) + } + + pub(crate) fn set_sender_chain( + &mut self, + sender: &KeyPair, + next_chain_key: &ChainKey, + ) -> Result<()> { + let chain_key = session_structure::chain::ChainKey { + index: next_chain_key.index(), + key: next_chain_key.key().to_vec(), + }; + + let new_chain = session_structure::Chain { + sender_ratchet_key: sender.public_key.serialize().to_vec(), + sender_ratchet_key_private: sender.private_key.serialize().to_vec(), + chain_key: Some(chain_key), + message_keys: vec![], + }; + + self.session.sender_chain = Some(new_chain); + + Ok(()) + } + + pub(crate) fn get_sender_chain_key(&self) -> Result { + let sender_chain = self.session.sender_chain.as_ref().ok_or_else(|| { + SignalProtocolError::InvalidState("get_sender_chain_key", "No chain".to_owned()) + })?; + + let chain_key = sender_chain.chain_key.as_ref().ok_or_else(|| { + SignalProtocolError::InvalidState("get_sender_chain_key", "No chain key".to_owned()) + })?; + + ChainKey::new(&chain_key.key, chain_key.index) + } + + pub(crate) fn get_sender_chain_key_bytes(&self) -> Result> { + Ok(self.get_sender_chain_key()?.key().to_vec()) + } + + pub(crate) fn set_sender_chain_key(&mut self, next_chain_key: &ChainKey) -> Result<()> { + let chain_key = session_structure::chain::ChainKey { + index: next_chain_key.index(), + key: next_chain_key.key().to_vec(), + }; + + // Is it actually valid to call this function with sender_chain == None? + + let new_chain = match self.session.sender_chain.take() { + None => session_structure::Chain { + sender_ratchet_key: vec![], + sender_ratchet_key_private: vec![], + chain_key: Some(chain_key), + message_keys: vec![], + }, + Some(mut c) => { + c.chain_key = Some(chain_key); + c + } + }; + + self.session.sender_chain = Some(new_chain); + + Ok(()) + } + + pub(crate) fn get_message_keys( + &mut self, + sender: &PublicKey, + counter: u32, + ) -> Result> { + if let Some(mut chain_and_index) = self.get_receiver_chain(sender)? { + let message_key_idx = chain_and_index + .0 + .message_keys + .iter() + .position(|m| m.index == counter); + if let Some(position) = message_key_idx { + let message_key = chain_and_index.0.message_keys.remove(position); + + let keys = MessageKeys::new( + &message_key.cipher_key, + &message_key.mac_key, + &message_key.iv, + counter, + )?; + + // Update with message key removed + self.session.receiver_chains[chain_and_index.1] = chain_and_index.0; + return Ok(Some(keys)); + } + } + + Ok(None) + } + + pub(crate) fn set_message_keys( + &mut self, + sender: &PublicKey, + message_keys: &MessageKeys, + ) -> Result<()> { + let new_keys = session_structure::chain::MessageKey { + cipher_key: message_keys.cipher_key().to_vec(), + mac_key: message_keys.mac_key().to_vec(), + iv: message_keys.iv().to_vec(), + index: message_keys.counter(), + }; + + if let Some(chain_and_index) = self.get_receiver_chain(sender)? { + let mut updated_chain = chain_and_index.0; + updated_chain.message_keys.insert(0, new_keys); + + if updated_chain.message_keys.len() > consts::MAX_MESSAGE_KEYS { + updated_chain.message_keys.pop(); + } + + self.session.receiver_chains[chain_and_index.1] = updated_chain; + Ok(()) + } else { + Err(SignalProtocolError::InvalidState( + "set_message_keys", + "No receiver".to_string(), + )) + } + } + + pub(crate) fn set_receiver_chain_key( + &mut self, + sender: &PublicKey, + chain_key: &ChainKey, + ) -> Result<()> { + if let Some(chain_and_index) = self.get_receiver_chain(sender)? { + let mut updated_chain = chain_and_index.0; + updated_chain.chain_key = Some(session_structure::chain::ChainKey { + index: chain_key.index(), + key: chain_key.key().to_vec(), + }); + + self.session.receiver_chains[chain_and_index.1] = updated_chain; + return Ok(()); + } + + Err(SignalProtocolError::InvalidState( + "set_receiver_chain_key", + "No receiver".to_string(), + )) + } + + pub(crate) fn set_unacknowledged_pre_key_message( + &mut self, + pre_key_id: Option, + signed_pre_key_id: SignedPreKeyId, + base_key: &PublicKey, + ) -> Result<()> { + let pending = session_structure::PendingPreKey { + pre_key_id: pre_key_id.unwrap_or(0), + signed_pre_key_id: signed_pre_key_id as i32, + base_key: base_key.serialize().to_vec(), + }; + self.session.pending_pre_key = Some(pending); + Ok(()) + } + + pub(crate) fn unacknowledged_pre_key_message_items( + &self, + ) -> Result> { + if let Some(ref pending_pre_key) = self.session.pending_pre_key { + Ok(Some(UnacknowledgedPreKeyMessageItems::new( + match pending_pre_key.pre_key_id { + 0 => None, + v => Some(v), + }, + pending_pre_key.signed_pre_key_id as SignedPreKeyId, + PublicKey::deserialize(&pending_pre_key.base_key)?, + ))) + } else { + Ok(None) + } + } + + pub(crate) fn clear_unacknowledged_pre_key_message(&mut self) -> Result<()> { + self.session.pending_pre_key = None; + Ok(()) + } + + pub(crate) fn set_remote_registration_id(&mut self, registration_id: u32) -> Result<()> { + self.session.remote_registration_id = registration_id; + Ok(()) + } + + pub(crate) fn remote_registration_id(&self) -> Result { + Ok(self.session.remote_registration_id) + } + + pub(crate) fn set_local_registration_id(&mut self, registration_id: u32) -> Result<()> { + self.session.local_registration_id = registration_id; + Ok(()) + } + + pub(crate) fn local_registration_id(&self) -> Result { + Ok(self.session.local_registration_id) + } +} + +impl From for SessionState { + fn from(value: SessionStructure) -> SessionState { + SessionState::new(value) + } +} + +impl From for SessionStructure { + fn from(value: SessionState) -> SessionStructure { + value.session + } +} + +impl From<&SessionState> for SessionStructure { + fn from(value: &SessionState) -> SessionStructure { + value.session.clone() + } +} + +#[derive(Clone, Debug)] +pub struct SessionRecord { + current_session: Option, + previous_sessions: Vec>, +} + +impl SessionRecord { + pub fn new_fresh() -> Self { + Self { + current_session: None, + previous_sessions: Vec::new(), + } + } + + pub(crate) fn new(state: SessionState) -> Self { + Self { + current_session: Some(state), + previous_sessions: Vec::new(), + } + } + + pub fn deserialize(bytes: &[u8]) -> Result { + let record = RecordStructure::decode(bytes)?; + + Ok(Self { + current_session: record.current_session.map(|s| s.into()), + previous_sessions: record.previous_sessions, + }) + } + + pub fn from_single_session_state(bytes: &[u8]) -> Result { + let session = SessionState::new(SessionStructure::decode(bytes)?); + Ok(Self { + current_session: Some(session), + previous_sessions: Vec::new(), + }) + } + + pub(crate) fn has_session_state(&self, version: u32, alice_base_key: &[u8]) -> Result { + if let Some(current_session) = &self.current_session { + if current_session.session_version()? == version + && alice_base_key == current_session.alice_base_key()? + { + return Ok(true); + } + } + + for previous in self.previous_session_states() { + let previous = previous?; + if previous.session_version()? == version + && alice_base_key == previous.alice_base_key()? + { + return Ok(true); + } + } + + Ok(false) + } + + pub fn has_current_session_state(&self) -> bool { + self.current_session.is_some() + } + + pub(crate) fn session_state(&self) -> Result<&SessionState> { + if let Some(ref session) = self.current_session { + Ok(session) + } else { + Err(SignalProtocolError::InvalidState( + "session_state", + "No session".into(), + )) + } + } + + pub(crate) fn session_state_mut(&mut self) -> Result<&mut SessionState> { + if let Some(ref mut session) = self.current_session { + Ok(session) + } else { + Err(SignalProtocolError::InvalidState( + "session_state", + "No session".into(), + )) + } + } + + pub(crate) fn set_session_state(&mut self, session: SessionState) -> Result<()> { + self.current_session = Some(session); + Ok(()) + } + + pub(crate) fn previous_session_states( + &self, + ) -> impl ExactSizeIterator> + '_ { + self.previous_sessions + .iter() + .map(|bytes| Ok(SessionStructure::decode(&bytes[..])?.into())) + } + + pub(crate) fn promote_old_session( + &mut self, + old_session: usize, + updated_session: SessionState, + ) -> Result<()> { + if old_session >= self.previous_sessions.len() { + return Err(SignalProtocolError::InvalidState( + "promote_old_session", + "out of range".into(), + )); + } + self.previous_sessions.remove(old_session); + self.promote_state(updated_session) + } + + pub(crate) fn promote_state(&mut self, new_state: SessionState) -> Result<()> { + self.archive_current_state()?; + self.current_session = Some(new_state); + Ok(()) + } + + pub fn archive_current_state(&mut self) -> Result<()> { + if let Some(current_session) = self.current_session.take() { + if self.previous_sessions.len() >= consts::ARCHIVED_STATES_MAX_LENGTH { + self.previous_sessions.pop(); + } + self.previous_sessions + .insert(0, current_session.session.encode_to_vec()); + } else { + log::info!("Skipping archive, current session state is fresh",); + } + + Ok(()) + } + + pub fn serialize(&self) -> Result> { + let record = RecordStructure { + current_session: self.current_session.as_ref().map(|s| s.into()), + previous_sessions: self.previous_sessions.clone(), + }; + Ok(record.encode_to_vec()) + } + + pub fn remote_registration_id(&self) -> Result { + self.session_state()?.remote_registration_id() + } + + pub fn local_registration_id(&self) -> Result { + self.session_state()?.local_registration_id() + } + + pub fn session_version(&self) -> Result { + self.session_state()?.session_version() + } + + pub fn local_identity_key_bytes(&self) -> Result> { + self.session_state()?.local_identity_key_bytes() + } + + pub fn remote_identity_key_bytes(&self) -> Result>> { + self.session_state()?.remote_identity_key_bytes() + } + + pub fn has_sender_chain(&self) -> Result { + match &self.current_session { + Some(session) => session.has_sender_chain(), + None => Ok(false), + } + } + + pub fn alice_base_key(&self) -> Result<&[u8]> { + self.session_state()?.alice_base_key() + } + + pub fn get_receiver_chain_key(&self, sender: &PublicKey) -> Result> { + self.session_state()?.get_receiver_chain_key(sender) + } + + pub fn get_sender_chain_key_bytes(&self) -> Result> { + self.session_state()?.get_sender_chain_key_bytes() + } + + pub fn current_ratchet_key_matches(&self, key: &PublicKey) -> Result { + match &self.current_session { + Some(session) => Ok(&session.sender_ratchet_key()? == key), + None => Ok(false), + } + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/state/signed_prekey.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/state/signed_prekey.rs new file mode 100644 index 0000000..b6f3575 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/state/signed_prekey.rs @@ -0,0 +1,69 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::proto::storage::SignedPreKeyRecordStructure; +use crate::{KeyPair, PrivateKey, PublicKey, Result}; +use prost::Message; + +pub type SignedPreKeyId = u32; + +#[derive(Debug, Clone)] +pub struct SignedPreKeyRecord { + signed_pre_key: SignedPreKeyRecordStructure, +} + +impl SignedPreKeyRecord { + pub fn new(id: SignedPreKeyId, timestamp: u64, key: &KeyPair, signature: &[u8]) -> Self { + let public_key = key.public_key.serialize().to_vec(); + let private_key = key.private_key.serialize().to_vec(); + let signature = signature.to_vec(); + Self { + signed_pre_key: SignedPreKeyRecordStructure { + id, + timestamp, + public_key, + private_key, + signature, + }, + } + } + + pub fn deserialize(data: &[u8]) -> Result { + Ok(Self { + signed_pre_key: SignedPreKeyRecordStructure::decode(data)?, + }) + } + + pub fn id(&self) -> Result { + Ok(self.signed_pre_key.id) + } + + pub fn timestamp(&self) -> Result { + Ok(self.signed_pre_key.timestamp) + } + + pub fn signature(&self) -> Result> { + Ok(self.signed_pre_key.signature.clone()) + } + + pub fn public_key(&self) -> Result { + PublicKey::deserialize(&self.signed_pre_key.public_key) + } + + pub fn private_key(&self) -> Result { + PrivateKey::deserialize(&self.signed_pre_key.private_key) + } + + pub fn key_pair(&self) -> Result { + KeyPair::from_public_and_private( + &self.signed_pre_key.public_key, + &self.signed_pre_key.private_key, + ) + } + + pub fn serialize(&self) -> Result> { + Ok(self.signed_pre_key.encode_to_vec()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/storage.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/storage.rs new file mode 100644 index 0000000..5ab1ed5 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/storage.rs @@ -0,0 +1,18 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +mod inmem; +mod traits; + +pub use { + inmem::{ + InMemIdentityKeyStore, InMemPreKeyStore, InMemSenderKeyStore, InMemSessionStore, + InMemSignalProtocolStore, InMemSignedPreKeyStore, + }, + traits::{ + Context, Direction, IdentityKeyStore, PreKeyStore, ProtocolStore, SenderKeyStore, + SessionStore, SignedPreKeyStore, + }, +}; diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/storage/inmem.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/storage/inmem.rs new file mode 100644 index 0000000..3567ac0 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/storage/inmem.rs @@ -0,0 +1,454 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use crate::{ + IdentityKey, IdentityKeyPair, PreKeyRecord, ProtocolAddress, Result, SenderKeyRecord, + SessionRecord, SignalProtocolError, SignedPreKeyRecord, +}; + +use crate::state::{PreKeyId, SignedPreKeyId}; +use crate::storage::traits; +use crate::storage::Context; + +use async_trait::async_trait; +use std::borrow::Cow; +use std::collections::HashMap; +use uuid::Uuid; + +#[derive(Clone)] +pub struct InMemIdentityKeyStore { + key_pair: IdentityKeyPair, + id: u32, + known_keys: HashMap, +} + +impl InMemIdentityKeyStore { + pub fn new(key_pair: IdentityKeyPair, id: u32) -> Self { + Self { + key_pair, + id, + known_keys: HashMap::new(), + } + } + + pub fn reset(&mut self) { + self.known_keys.clear(); + } +} + +#[async_trait(?Send)] +impl traits::IdentityKeyStore for InMemIdentityKeyStore { + async fn get_identity_key_pair(&self, _ctx: Context) -> Result { + Ok(self.key_pair) + } + + async fn get_local_registration_id(&self, _ctx: Context) -> Result { + Ok(self.id) + } + + async fn save_identity( + &mut self, + address: &ProtocolAddress, + identity: &IdentityKey, + _ctx: Context, + ) -> Result { + match self.known_keys.get(address) { + None => { + self.known_keys.insert(address.clone(), *identity); + Ok(false) // new key + } + Some(k) if k == identity => { + Ok(false) // same key + } + Some(_k) => { + self.known_keys.insert(address.clone(), *identity); + Ok(true) // overwrite + } + } + } + + async fn is_trusted_identity( + &self, + address: &ProtocolAddress, + identity: &IdentityKey, + _direction: traits::Direction, + _ctx: Context, + ) -> Result { + match self.known_keys.get(address) { + None => { + Ok(true) // first use + } + Some(k) => Ok(k == identity), + } + } + + async fn get_identity( + &self, + address: &ProtocolAddress, + _ctx: Context, + ) -> Result> { + match self.known_keys.get(address) { + None => Ok(None), + Some(k) => Ok(Some(k.to_owned())), + } + } +} + +#[derive(Clone)] +pub struct InMemPreKeyStore { + pre_keys: HashMap, +} + +impl InMemPreKeyStore { + pub fn new() -> Self { + Self { + pre_keys: HashMap::new(), + } + } +} + +impl Default for InMemPreKeyStore { + fn default() -> Self { + Self::new() + } +} + +#[async_trait(?Send)] +impl traits::PreKeyStore for InMemPreKeyStore { + async fn get_pre_key(&self, id: PreKeyId, _ctx: Context) -> Result { + Ok(self + .pre_keys + .get(&id) + .ok_or(SignalProtocolError::InvalidPreKeyId)? + .clone()) + } + + async fn save_pre_key( + &mut self, + id: PreKeyId, + record: &PreKeyRecord, + _ctx: Context, + ) -> Result<()> { + // This overwrites old values, which matches Java behavior, but is it correct? + self.pre_keys.insert(id, record.to_owned()); + Ok(()) + } + + async fn remove_pre_key(&mut self, id: PreKeyId, _ctx: Context) -> Result<()> { + // If id does not exist this silently does nothing + self.pre_keys.remove(&id); + Ok(()) + } +} + +#[derive(Clone)] +pub struct InMemSignedPreKeyStore { + signed_pre_keys: HashMap, +} + +impl InMemSignedPreKeyStore { + pub fn new() -> Self { + Self { + signed_pre_keys: HashMap::new(), + } + } +} + +impl Default for InMemSignedPreKeyStore { + fn default() -> Self { + Self::new() + } +} + +#[async_trait(?Send)] +impl traits::SignedPreKeyStore for InMemSignedPreKeyStore { + async fn get_signed_pre_key( + &self, + id: SignedPreKeyId, + _ctx: Context, + ) -> Result { + Ok(self + .signed_pre_keys + .get(&id) + .ok_or(SignalProtocolError::InvalidSignedPreKeyId)? + .clone()) + } + + async fn save_signed_pre_key( + &mut self, + id: SignedPreKeyId, + record: &SignedPreKeyRecord, + _ctx: Context, + ) -> Result<()> { + // This overwrites old values, which matches Java behavior, but is it correct? + self.signed_pre_keys.insert(id, record.to_owned()); + Ok(()) + } +} + +#[derive(Clone)] +pub struct InMemSessionStore { + sessions: HashMap, +} + +impl InMemSessionStore { + pub fn new() -> Self { + Self { + sessions: HashMap::new(), + } + } + + /// Bulk version of [`SessionStore::load_session`]. + /// + /// Useful for [crate::sealed_sender_multi_recipient_encrypt]. + /// + /// [`SessionStore::load_session`]: crate::SessionStore::load_session + pub fn load_existing_sessions( + &self, + addresses: &[&ProtocolAddress], + ) -> Result> { + addresses + .iter() + .map(|address| { + self.sessions + .get(address) + .ok_or_else(|| SignalProtocolError::SessionNotFound(address.to_string())) + }) + .collect() + } +} + +impl Default for InMemSessionStore { + fn default() -> Self { + Self::new() + } +} + +#[async_trait(?Send)] +impl traits::SessionStore for InMemSessionStore { + async fn load_session( + &self, + address: &ProtocolAddress, + _ctx: Context, + ) -> Result> { + match self.sessions.get(address) { + None => Ok(None), + Some(s) => Ok(Some(s.clone())), + } + } + + async fn store_session( + &mut self, + address: &ProtocolAddress, + record: &SessionRecord, + _ctx: Context, + ) -> Result<()> { + self.sessions.insert(address.clone(), record.clone()); + Ok(()) + } +} + +#[derive(Clone)] +pub struct InMemSenderKeyStore { + // We use Cow keys in order to store owned values but compare to referenced ones. + // See https://users.rust-lang.org/t/hashmap-with-tuple-keys/12711/6. + keys: HashMap<(Cow<'static, ProtocolAddress>, Uuid), SenderKeyRecord>, +} + +impl InMemSenderKeyStore { + pub fn new() -> Self { + Self { + keys: HashMap::new(), + } + } +} + +impl Default for InMemSenderKeyStore { + fn default() -> Self { + Self::new() + } +} + +#[async_trait(?Send)] +impl traits::SenderKeyStore for InMemSenderKeyStore { + async fn store_sender_key( + &mut self, + sender: &ProtocolAddress, + distribution_id: Uuid, + record: &SenderKeyRecord, + _ctx: Context, + ) -> Result<()> { + self.keys.insert( + (Cow::Owned(sender.clone()), distribution_id), + record.clone(), + ); + Ok(()) + } + + async fn load_sender_key( + &mut self, + sender: &ProtocolAddress, + distribution_id: Uuid, + _ctx: Context, + ) -> Result> { + Ok(self + .keys + .get(&(Cow::Borrowed(sender), distribution_id)) + .cloned()) + } +} + +#[derive(Clone)] +pub struct InMemSignalProtocolStore { + pub session_store: InMemSessionStore, + pub pre_key_store: InMemPreKeyStore, + pub signed_pre_key_store: InMemSignedPreKeyStore, + pub identity_store: InMemIdentityKeyStore, + pub sender_key_store: InMemSenderKeyStore, +} + +impl InMemSignalProtocolStore { + pub fn new(key_pair: IdentityKeyPair, registration_id: u32) -> Result { + Ok(Self { + session_store: InMemSessionStore::new(), + pre_key_store: InMemPreKeyStore::new(), + signed_pre_key_store: InMemSignedPreKeyStore::new(), + identity_store: InMemIdentityKeyStore::new(key_pair, registration_id), + sender_key_store: InMemSenderKeyStore::new(), + }) + } +} + +#[async_trait(?Send)] +impl traits::IdentityKeyStore for InMemSignalProtocolStore { + async fn get_identity_key_pair(&self, ctx: Context) -> Result { + self.identity_store.get_identity_key_pair(ctx).await + } + + async fn get_local_registration_id(&self, ctx: Context) -> Result { + self.identity_store.get_local_registration_id(ctx).await + } + + async fn save_identity( + &mut self, + address: &ProtocolAddress, + identity: &IdentityKey, + ctx: Context, + ) -> Result { + self.identity_store + .save_identity(address, identity, ctx) + .await + } + + async fn is_trusted_identity( + &self, + address: &ProtocolAddress, + identity: &IdentityKey, + direction: traits::Direction, + ctx: Context, + ) -> Result { + self.identity_store + .is_trusted_identity(address, identity, direction, ctx) + .await + } + + async fn get_identity( + &self, + address: &ProtocolAddress, + ctx: Context, + ) -> Result> { + self.identity_store.get_identity(address, ctx).await + } +} + +#[async_trait(?Send)] +impl traits::PreKeyStore for InMemSignalProtocolStore { + async fn get_pre_key(&self, id: PreKeyId, ctx: Context) -> Result { + self.pre_key_store.get_pre_key(id, ctx).await + } + + async fn save_pre_key( + &mut self, + id: PreKeyId, + record: &PreKeyRecord, + ctx: Context, + ) -> Result<()> { + self.pre_key_store.save_pre_key(id, record, ctx).await + } + + async fn remove_pre_key(&mut self, id: PreKeyId, ctx: Context) -> Result<()> { + self.pre_key_store.remove_pre_key(id, ctx).await + } +} + +#[async_trait(?Send)] +impl traits::SignedPreKeyStore for InMemSignalProtocolStore { + async fn get_signed_pre_key( + &self, + id: SignedPreKeyId, + ctx: Context, + ) -> Result { + self.signed_pre_key_store.get_signed_pre_key(id, ctx).await + } + + async fn save_signed_pre_key( + &mut self, + id: SignedPreKeyId, + record: &SignedPreKeyRecord, + ctx: Context, + ) -> Result<()> { + self.signed_pre_key_store + .save_signed_pre_key(id, record, ctx) + .await + } +} + +#[async_trait(?Send)] +impl traits::SessionStore for InMemSignalProtocolStore { + async fn load_session( + &self, + address: &ProtocolAddress, + ctx: Context, + ) -> Result> { + self.session_store.load_session(address, ctx).await + } + + async fn store_session( + &mut self, + address: &ProtocolAddress, + record: &SessionRecord, + ctx: Context, + ) -> Result<()> { + self.session_store.store_session(address, record, ctx).await + } +} + +#[async_trait(?Send)] +impl traits::SenderKeyStore for InMemSignalProtocolStore { + async fn store_sender_key( + &mut self, + sender: &ProtocolAddress, + distribution_id: Uuid, + record: &SenderKeyRecord, + ctx: Context, + ) -> Result<()> { + self.sender_key_store + .store_sender_key(sender, distribution_id, record, ctx) + .await + } + + async fn load_sender_key( + &mut self, + sender: &ProtocolAddress, + distribution_id: Uuid, + ctx: Context, + ) -> Result> { + self.sender_key_store + .load_sender_key(sender, distribution_id, ctx) + .await + } +} + +impl traits::ProtocolStore for InMemSignalProtocolStore {} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/storage/traits.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/storage/traits.rs new file mode 100644 index 0000000..e3c1572 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/storage/traits.rs @@ -0,0 +1,115 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use async_trait::async_trait; +use uuid::Uuid; + +use crate::state::{PreKeyId, SignedPreKeyId}; +use crate::{ + IdentityKey, IdentityKeyPair, PreKeyRecord, ProtocolAddress, Result, SenderKeyRecord, + SessionRecord, SignedPreKeyRecord, +}; + +pub type Context = Option<*mut std::ffi::c_void>; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Direction { + Sending, + Receiving, +} + +#[async_trait(?Send)] +pub trait IdentityKeyStore { + async fn get_identity_key_pair(&self, ctx: Context) -> Result; + + async fn get_local_registration_id(&self, ctx: Context) -> Result; + + async fn save_identity( + &mut self, + address: &ProtocolAddress, + identity: &IdentityKey, + ctx: Context, + ) -> Result; + + async fn is_trusted_identity( + &self, + address: &ProtocolAddress, + identity: &IdentityKey, + direction: Direction, + ctx: Context, + ) -> Result; + + async fn get_identity( + &self, + address: &ProtocolAddress, + ctx: Context, + ) -> Result>; +} + +#[async_trait(?Send)] +pub trait PreKeyStore { + async fn get_pre_key(&self, prekey_id: PreKeyId, ctx: Context) -> Result; + + async fn save_pre_key( + &mut self, + prekey_id: PreKeyId, + record: &PreKeyRecord, + ctx: Context, + ) -> Result<()>; + + async fn remove_pre_key(&mut self, prekey_id: PreKeyId, ctx: Context) -> Result<()>; +} + +#[async_trait(?Send)] +pub trait SignedPreKeyStore { + async fn get_signed_pre_key( + &self, + signed_prekey_id: SignedPreKeyId, + ctx: Context, + ) -> Result; + + async fn save_signed_pre_key( + &mut self, + signed_prekey_id: SignedPreKeyId, + record: &SignedPreKeyRecord, + ctx: Context, + ) -> Result<()>; +} + +#[async_trait(?Send)] +pub trait SessionStore { + async fn load_session( + &self, + address: &ProtocolAddress, + ctx: Context, + ) -> Result>; + + async fn store_session( + &mut self, + address: &ProtocolAddress, + record: &SessionRecord, + ctx: Context, + ) -> Result<()>; +} + +#[async_trait(?Send)] +pub trait SenderKeyStore { + async fn store_sender_key( + &mut self, + sender: &ProtocolAddress, + distribution_id: Uuid, + record: &SenderKeyRecord, + ctx: Context, + ) -> Result<()>; + + async fn load_sender_key( + &mut self, + sender: &ProtocolAddress, + distribution_id: Uuid, + ctx: Context, + ) -> Result>; +} + +pub trait ProtocolStore: SessionStore + PreKeyStore + SignedPreKeyStore + IdentityKeyStore {} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/src/utils.rs b/net/gurk-rs/files/vendor/libsignal-protocol/src/utils.rs new file mode 100644 index 0000000..67a108c --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/src/utils.rs @@ -0,0 +1,141 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use std::cmp::Ordering; + +fn expand_top_bit(a: u8) -> u8 { + //if (a >> 7) == 1 { 0xFF } else { 0 } + 0u8.wrapping_sub(a >> 7) +} + +fn ct_is_zero(a: u8) -> u8 { + //if a == 0 { 0xFF } else { 0 } + expand_top_bit(!a & a.wrapping_sub(1)) +} + +fn ct_is_eq(a: u8, b: u8) -> u8 { + //if a == b { 0xFF } else { 0 } + ct_is_zero(a ^ b) +} + +fn ct_is_lt(a: u8, b: u8) -> u8 { + //if a < b { 0xFF } else { 0 } + expand_top_bit(a ^ ((a ^ b) | ((a.wrapping_sub(b)) ^ a))) +} + +fn ct_select(mask: u8, a: u8, b: u8) -> u8 { + debug_assert!(mask == 0 || mask == 0xFF); + //if mask == 0xFF { a } else if mask == 0x00 { b } else { unreachable!(); } + b ^ (mask & (a ^ b)) +} + +/* +* If x and y are different lengths, this leaks information about +* their relative sizes. This is irrelevant as we always invoke it +* with two inputs of the same size. +* +* In addition it will leak the final comparison result, when the +* integer is translated to the Ordering enum. This seems unavoidable. +* +* The primary goal of this function is to not leak any additional +* information, besides the ordering, about the value of the two keys, +* say due to an early exit of the loop. +* +* It would be possible to instead have this function SHA-256 hash both +* inputs, then compare the resulting hashes in the usual non-const +* time way. We avoid this approach at the moment since it is not clear +* if applications will rely on public key ordering being defined in +* some particular way or not. + */ + +pub(crate) fn constant_time_cmp(x: &[u8], y: &[u8]) -> Ordering { + if x.len() < y.len() { + return Ordering::Less; + } + if x.len() > y.len() { + return Ordering::Greater; + } + + let mut result: u8 = 0; + + for i in 0..x.len() { + let a = x[x.len() - 1 - i]; + let b = y[x.len() - 1 - i]; + + let is_eq = ct_is_eq(a, b); + let is_lt = ct_is_lt(a, b); + + result = ct_select(is_eq, result, ct_select(is_lt, 1, 255)); + } + + debug_assert!(result == 0 || result == 1 || result == 255); + + if result == 0 { + Ordering::Equal + } else if result == 1 { + Ordering::Less + } else { + Ordering::Greater + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_constant_time_cmp() { + use rand::Rng; + + assert_eq!(constant_time_cmp(&[1], &[1]), Ordering::Equal); + assert_eq!(constant_time_cmp(&[0, 1], &[1]), Ordering::Greater); + assert_eq!(constant_time_cmp(&[1], &[0, 1]), Ordering::Less); + assert_eq!(constant_time_cmp(&[2], &[1, 0, 1]), Ordering::Less); + + let mut rng = rand::rngs::OsRng; + for len in 1..320 { + let x: Vec = (0..len).map(|_| rng.gen()).collect(); + let y: Vec = (0..len).map(|_| rng.gen()).collect(); + let expected = x.cmp(&y); + let result = constant_time_cmp(&x, &y); + assert_eq!(result, expected); + + let expected = y.cmp(&x); + let result = constant_time_cmp(&y, &x); + assert_eq!(result, expected); + } + } + + #[test] + fn test_ct_is_zero() { + assert_eq!(ct_is_zero(0), 0xFF); + + for i in 1..255 { + assert_eq!(ct_is_zero(i), 0x00); + } + } + + #[test] + fn test_ct_is_lt() { + for x in 0..255 { + for y in 0..255 { + let expected = if x < y { 0xFF } else { 0 }; + let result = ct_is_lt(x, y); + assert_eq!(result, expected); + } + } + } + + #[test] + fn test_ct_is_eq() { + for x in 0..255 { + for y in 0..255 { + let expected = if x == y { 0xFF } else { 0 }; + let result = ct_is_eq(x, y); + assert_eq!(result, expected); + } + } + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/tests/groups.rs b/net/gurk-rs/files/vendor/libsignal-protocol/tests/groups.rs new file mode 100644 index 0000000..87b5039 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/tests/groups.rs @@ -0,0 +1,874 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +mod support; + +use async_trait::async_trait; +use futures_util::FutureExt; +use libsignal_protocol::*; +use rand::rngs::OsRng; +use rand::seq::SliceRandom; +use rand::Rng; +use std::convert::TryFrom; +use support::*; +use uuid::Uuid; + +#[test] +fn group_no_send_session() -> Result<(), SignalProtocolError> { + let mut csprng = OsRng; + + let sender_address = ProtocolAddress::new("+14159999111".to_owned(), 1); + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let mut alice_store = test_in_memory_protocol_store()?; + + assert!(group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + "space camp?".as_bytes(), + &mut csprng, + None, + ) + .now_or_never() + .expect("sync") + .is_err()); + + Ok(()) +} + +pub struct ContextUsingSenderKeyStore { + store: InMemSenderKeyStore, + expected_context: Context, +} + +impl ContextUsingSenderKeyStore { + pub fn new(expected_context: Context) -> Self { + Self { + store: InMemSenderKeyStore::new(), + expected_context, + } + } +} + +#[async_trait(?Send)] +impl SenderKeyStore for ContextUsingSenderKeyStore { + async fn store_sender_key( + &mut self, + sender: &ProtocolAddress, + distribution_id: Uuid, + record: &SenderKeyRecord, + ctx: Context, + ) -> Result<(), SignalProtocolError> { + assert_eq!(ctx, self.expected_context); + self.store + .store_sender_key(sender, distribution_id, record, ctx) + .await + } + + async fn load_sender_key( + &mut self, + sender: &ProtocolAddress, + distribution_id: Uuid, + ctx: Context, + ) -> Result, SignalProtocolError> { + assert_eq!(ctx, self.expected_context); + self.store + .load_sender_key(sender, distribution_id, ctx) + .await + } +} + +#[test] +fn group_using_context_arg() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let sender_address = ProtocolAddress::new("+14159999111".to_owned(), 1); + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let x = Box::new(1); + + let context = Some(Box::into_raw(x) as _); + + let mut alice_store = ContextUsingSenderKeyStore::new(context); + + let _sent_distribution_message = create_sender_key_distribution_message( + &sender_address, + distribution_id, + &mut alice_store, + &mut csprng, + context, + ) + .await?; + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn group_no_recv_session() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let sender_address = ProtocolAddress::new("+14159999111".to_owned(), 1); + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let mut alice_store = test_in_memory_protocol_store()?; + let mut bob_store = test_in_memory_protocol_store()?; + + let sent_distribution_message = create_sender_key_distribution_message( + &sender_address, + distribution_id, + &mut alice_store, + &mut csprng, + None, + ) + .await?; + + let _recv_distribution_message = + SenderKeyDistributionMessage::try_from(sent_distribution_message.serialized())?; + + let alice_ciphertext = group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + "space camp?".as_bytes(), + &mut csprng, + None, + ) + .await?; + + let bob_plaintext = group_decrypt( + alice_ciphertext.serialized(), + &mut bob_store, + &sender_address, + None, + ) + .await; + + assert!(bob_plaintext.is_err()); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn group_basic_encrypt_decrypt() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let sender_address = ProtocolAddress::new("+14159999111".to_owned(), 1); + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let mut alice_store = test_in_memory_protocol_store()?; + let mut bob_store = test_in_memory_protocol_store()?; + + let sent_distribution_message = create_sender_key_distribution_message( + &sender_address, + distribution_id, + &mut alice_store, + &mut csprng, + None, + ) + .await?; + + let recv_distribution_message = + SenderKeyDistributionMessage::try_from(sent_distribution_message.serialized())?; + + let alice_ciphertext = group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + "space camp?".as_bytes(), + &mut csprng, + None, + ) + .await?; + + process_sender_key_distribution_message( + &sender_address, + &recv_distribution_message, + &mut bob_store, + None, + ) + .await?; + + let bob_plaintext = group_decrypt( + alice_ciphertext.serialized(), + &mut bob_store, + &sender_address, + None, + ) + .await?; + + assert_eq!( + String::from_utf8(bob_plaintext).expect("valid utf8"), + "space camp?" + ); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn group_sealed_sender() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let alice_device_id = 23; + let bob_device_id = 42; + + let alice_e164 = "+14151111111".to_owned(); + + let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string(); + let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string(); + let carol_uuid = "38381c3b-2606-4ca7-9310-7cb927f2ab4a".to_string(); + + let alice_uuid_address = ProtocolAddress::new(alice_uuid.clone(), alice_device_id); + let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id); + let carol_uuid_address = ProtocolAddress::new(carol_uuid.clone(), 1); + + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + let mut carol_store = support::test_in_memory_protocol_store()?; + + let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key(); + + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut csprng).await?; + let carol_pre_key_bundle = create_pre_key_bundle(&mut carol_store, &mut csprng).await?; + + process_prekey_bundle( + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + process_prekey_bundle( + &carol_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &carol_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + let sent_distribution_message = create_sender_key_distribution_message( + &alice_uuid_address, + distribution_id, + &mut alice_store, + &mut csprng, + None, + ) + .await?; + + let recv_distribution_message = + SenderKeyDistributionMessage::try_from(sent_distribution_message.serialized())?; + + process_sender_key_distribution_message( + &alice_uuid_address, + &recv_distribution_message, + &mut bob_store, + None, + ) + .await?; + process_sender_key_distribution_message( + &alice_uuid_address, + &recv_distribution_message, + &mut carol_store, + None, + ) + .await?; + + let trust_root = KeyPair::generate(&mut csprng); + let server_key = KeyPair::generate(&mut csprng); + + let server_cert = ServerCertificate::new( + 1, + server_key.public_key, + &trust_root.private_key, + &mut csprng, + )?; + + let expires = 1605722925; + + let sender_cert = SenderCertificate::new( + alice_uuid.clone(), + Some(alice_e164.clone()), + alice_pubkey, + alice_device_id, + expires, + server_cert, + &server_key.private_key, + &mut csprng, + )?; + + let alice_message = group_encrypt( + &mut alice_store, + &alice_uuid_address, + distribution_id, + "space camp?".as_bytes(), + &mut csprng, + None, + ) + .await?; + + let alice_usmc = UnidentifiedSenderMessageContent::new( + CiphertextMessageType::SenderKey, + sender_cert.clone(), + alice_message.serialized().to_vec(), + ContentHint::Implicit, + Some([42].to_vec()), + )?; + + let recipients = [&bob_uuid_address, &carol_uuid_address]; + let alice_ctext = sealed_sender_multi_recipient_encrypt( + &recipients, + &alice_store + .session_store + .load_existing_sessions(&recipients)?, + &alice_usmc, + &mut alice_store.identity_store, + None, + &mut csprng, + ) + .await?; + + let [bob_ctext, carol_ctext] = + <[_; 2]>::try_from(sealed_sender_multi_recipient_fan_out(&alice_ctext)?).unwrap(); + + let bob_usmc = + sealed_sender_decrypt_to_usmc(&bob_ctext, &mut bob_store.identity_store, None).await?; + + assert_eq!(bob_usmc.sender()?.sender_uuid()?, alice_uuid); + assert_eq!(bob_usmc.sender()?.sender_e164()?, Some(alice_e164.as_ref())); + assert_eq!(bob_usmc.sender()?.sender_device_id()?, alice_device_id); + assert_eq!(bob_usmc.content_hint()?, ContentHint::Implicit); + assert_eq!(bob_usmc.group_id()?, Some(&[42][..])); + + let bob_plaintext = group_decrypt( + bob_usmc.contents()?, + &mut bob_store, + &alice_uuid_address, + None, + ) + .await?; + + assert_eq!( + String::from_utf8(bob_plaintext).expect("valid utf8"), + "space camp?" + ); + + let carol_usmc = + sealed_sender_decrypt_to_usmc(&carol_ctext, &mut carol_store.identity_store, None) + .await?; + + assert_eq!(carol_usmc.serialized()?, bob_usmc.serialized()?); + + let carol_plaintext = group_decrypt( + carol_usmc.contents()?, + &mut carol_store, + &alice_uuid_address, + None, + ) + .await?; + + assert_eq!( + String::from_utf8(carol_plaintext).expect("valid utf8"), + "space camp?" + ); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn group_large_messages() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let sender_address = ProtocolAddress::new("+14159999111".to_owned(), 1); + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let mut alice_store = test_in_memory_protocol_store()?; + let mut bob_store = test_in_memory_protocol_store()?; + + let sent_distribution_message = create_sender_key_distribution_message( + &sender_address, + distribution_id, + &mut alice_store, + &mut csprng, + None, + ) + .await?; + + let recv_distribution_message = + SenderKeyDistributionMessage::try_from(sent_distribution_message.serialized())?; + + let mut large_message: Vec = Vec::with_capacity(1024); + for _ in 0..large_message.capacity() { + large_message.push(csprng.gen()); + } + + let alice_ciphertext = group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + &large_message, + &mut csprng, + None, + ) + .await?; + + process_sender_key_distribution_message( + &sender_address, + &recv_distribution_message, + &mut bob_store, + None, + ) + .await?; + + let bob_plaintext = group_decrypt( + alice_ciphertext.serialized(), + &mut bob_store, + &sender_address, + None, + ) + .await?; + + assert_eq!(bob_plaintext, large_message); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn group_basic_ratchet() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let sender_address = ProtocolAddress::new("+14159999111".to_owned(), 1); + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let mut alice_store = test_in_memory_protocol_store()?; + let mut bob_store = test_in_memory_protocol_store()?; + + let sent_distribution_message = create_sender_key_distribution_message( + &sender_address, + distribution_id, + &mut alice_store, + &mut csprng, + None, + ) + .await?; + + let recv_distribution_message = + SenderKeyDistributionMessage::try_from(sent_distribution_message.serialized())?; + + process_sender_key_distribution_message( + &sender_address, + &recv_distribution_message, + &mut bob_store, + None, + ) + .await?; + + let alice_ciphertext1 = group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + "swim camp".as_bytes(), + &mut csprng, + None, + ) + .await?; + let alice_ciphertext2 = group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + "robot camp".as_bytes(), + &mut csprng, + None, + ) + .await?; + let alice_ciphertext3 = group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + "ninja camp".as_bytes(), + &mut csprng, + None, + ) + .await?; + + let bob_plaintext1 = group_decrypt( + alice_ciphertext1.serialized(), + &mut bob_store, + &sender_address, + None, + ) + .await?; + assert_eq!( + String::from_utf8(bob_plaintext1).expect("valid utf8"), + "swim camp" + ); + + assert!(matches!( + group_decrypt( + alice_ciphertext1.serialized(), + &mut bob_store, + &sender_address, + None + ) + .await, + Err(SignalProtocolError::DuplicatedMessage(1, 0)) + )); + + let bob_plaintext3 = group_decrypt( + alice_ciphertext3.serialized(), + &mut bob_store, + &sender_address, + None, + ) + .await?; + assert_eq!( + String::from_utf8(bob_plaintext3).expect("valid utf8"), + "ninja camp" + ); + + let bob_plaintext2 = group_decrypt( + alice_ciphertext2.serialized(), + &mut bob_store, + &sender_address, + None, + ) + .await?; + assert_eq!( + String::from_utf8(bob_plaintext2).expect("valid utf8"), + "robot camp" + ); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn group_late_join() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let sender_address = ProtocolAddress::new("+14159999111".to_owned(), 1); + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let mut alice_store = test_in_memory_protocol_store()?; + let mut bob_store = test_in_memory_protocol_store()?; + + let sent_distribution_message = create_sender_key_distribution_message( + &sender_address, + distribution_id, + &mut alice_store, + &mut csprng, + None, + ) + .await?; + + let recv_distribution_message = + SenderKeyDistributionMessage::try_from(sent_distribution_message.serialized())?; + + for i in 0..100 { + group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + format!("nefarious plotting {}/100", i).as_bytes(), + &mut csprng, + None, + ) + .await?; + } + + // now bob joins: + process_sender_key_distribution_message( + &sender_address, + &recv_distribution_message, + &mut bob_store, + None, + ) + .await?; + + let alice_ciphertext = group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + "welcome bob".as_bytes(), + &mut csprng, + None, + ) + .await?; + + let bob_plaintext = group_decrypt( + alice_ciphertext.serialized(), + &mut bob_store, + &sender_address, + None, + ) + .await?; + assert_eq!( + String::from_utf8(bob_plaintext).expect("valid utf8"), + "welcome bob" + ); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn group_out_of_order() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let sender_address = ProtocolAddress::new("+14159999111".to_owned(), 1); + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let mut alice_store = test_in_memory_protocol_store()?; + let mut bob_store = test_in_memory_protocol_store()?; + + let sent_distribution_message = create_sender_key_distribution_message( + &sender_address, + distribution_id, + &mut alice_store, + &mut csprng, + None, + ) + .await?; + + let recv_distribution_message = + SenderKeyDistributionMessage::try_from(sent_distribution_message.serialized())?; + + process_sender_key_distribution_message( + &sender_address, + &recv_distribution_message, + &mut bob_store, + None, + ) + .await?; + + let mut ciphertexts = Vec::with_capacity(100); + + for i in 0..ciphertexts.capacity() { + ciphertexts.push( + group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + format!("nefarious plotting {:02}/100", i).as_bytes(), + &mut csprng, + None, + ) + .await?, + ); + } + + ciphertexts.shuffle(&mut csprng); + + let mut plaintexts = Vec::with_capacity(ciphertexts.len()); + + for ciphertext in ciphertexts { + plaintexts.push( + group_decrypt( + ciphertext.serialized(), + &mut bob_store, + &sender_address, + None, + ) + .await?, + ); + } + + plaintexts.sort(); + + for (i, plaintext) in plaintexts.iter().enumerate() { + assert_eq!( + String::from_utf8(plaintext.to_vec()).expect("valid utf8"), + format!("nefarious plotting {:02}/100", i) + ); + } + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +#[ignore = "slow to run locally"] +fn group_too_far_in_the_future() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let sender_address = ProtocolAddress::new("+14159999111".to_owned(), 1); + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let mut alice_store = test_in_memory_protocol_store()?; + let mut bob_store = test_in_memory_protocol_store()?; + + let sent_distribution_message = create_sender_key_distribution_message( + &sender_address, + distribution_id, + &mut alice_store, + &mut csprng, + None, + ) + .await?; + + let recv_distribution_message = + SenderKeyDistributionMessage::try_from(sent_distribution_message.serialized())?; + + process_sender_key_distribution_message( + &sender_address, + &recv_distribution_message, + &mut bob_store, + None, + ) + .await?; + + for i in 0..25001 { + group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + format!("nefarious plotting {}", i).as_bytes(), + &mut csprng, + None, + ) + .await?; + } + + let alice_ciphertext = group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + "you got the plan?".as_bytes(), + &mut csprng, + None, + ) + .await?; + + assert!(group_decrypt( + alice_ciphertext.serialized(), + &mut bob_store, + &sender_address, + None + ) + .await + .is_err()); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn group_message_key_limit() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let sender_address = ProtocolAddress::new("+14159999111".to_owned(), 1); + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let mut alice_store = test_in_memory_protocol_store()?; + let mut bob_store = test_in_memory_protocol_store()?; + + let sent_distribution_message = create_sender_key_distribution_message( + &sender_address, + distribution_id, + &mut alice_store, + &mut csprng, + None, + ) + .await?; + + let recv_distribution_message = + SenderKeyDistributionMessage::try_from(sent_distribution_message.serialized())?; + + process_sender_key_distribution_message( + &sender_address, + &recv_distribution_message, + &mut bob_store, + None, + ) + .await?; + + let mut ciphertexts = Vec::with_capacity(2010); + + for _ in 0..ciphertexts.capacity() { + ciphertexts.push( + group_encrypt( + &mut alice_store, + &sender_address, + distribution_id, + "too many messages".as_bytes(), + &mut csprng, + None, + ) + .await? + .serialized() + .to_vec(), + ); + } + + assert_eq!( + String::from_utf8( + group_decrypt(&ciphertexts[1000], &mut bob_store, &sender_address, None,).await? + ) + .expect("valid utf8"), + "too many messages" + ); + assert_eq!( + String::from_utf8( + group_decrypt( + &ciphertexts[ciphertexts.len() - 1], + &mut bob_store, + &sender_address, + None, + ) + .await? + ) + .expect("valid utf8"), + "too many messages" + ); + assert!( + group_decrypt(&ciphertexts[0], &mut bob_store, &sender_address, None) + .await + .is_err() + ); + + Ok(()) + } + .now_or_never() + .expect("sync") +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/tests/ratchet.rs b/net/gurk-rs/files/vendor/libsignal-protocol/tests/ratchet.rs new file mode 100644 index 0000000..33895c9 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/tests/ratchet.rs @@ -0,0 +1,173 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use libsignal_protocol::*; + +#[test] +fn test_ratcheting_session_as_bob() -> Result<(), SignalProtocolError> { + let bob_ephemeral_public = + hex::decode("052cb49776b8770205745a3a6e24f579cdb4ba7a89041005928ebbadc9c05ad458") + .expect("valid hex"); + + let bob_ephemeral_private = + hex::decode("a1cab48f7c893fafa9880a28c3b4999d28d6329562d27a4ea4e22e9ff1bdd65a") + .expect("valid hex"); + + let bob_identity_public = + hex::decode("05f1f43874f6966956c2dd473f8fa15adeb71d1cb991b2341692324cefb1c5e626") + .expect("valid hex"); + + let bob_identity_private = + hex::decode("4875cc69ddf8ea0719ec947d61081135868d5fd801f02c0225e516df2156605e") + .expect("valid hex"); + + let alice_base_public = + hex::decode("05472d1fb1a9862c3af6beaca8920277e2b26f4a79213ec7c906aeb35e03cf8950") + .expect("valid hex"); + + let alice_identity_public = + hex::decode("05b4a8455660ada65b401007f615e654041746432e3339c6875149bceefcb42b4a") + .expect("valid hex"); + + let bob_signed_prekey_public = + hex::decode("05ac248a8f263be6863576eb0362e28c828f0107a3379d34bab1586bf8c770cd67") + .expect("valid hex"); + + let bob_signed_prekey_private = + hex::decode("583900131fb727998b7803fe6ac22cc591f342e4e42a8c8d5d78194209b8d253") + .expect("valid hex"); + + let expected_sender_chain = "9797caca53c989bbe229a40ca7727010eb2604fc14945d77958a0aeda088b44d"; + + let bob_identity_key_public = IdentityKey::decode(&bob_identity_public)?; + + let bob_identity_key_private = PrivateKey::deserialize(&bob_identity_private)?; + + let bob_identity_key_pair = + IdentityKeyPair::new(bob_identity_key_public, bob_identity_key_private); + + let bob_ephemeral_pair = + KeyPair::from_public_and_private(&bob_ephemeral_public, &bob_ephemeral_private)?; + + let bob_signed_prekey_pair = + KeyPair::from_public_and_private(&bob_signed_prekey_public, &bob_signed_prekey_private)?; + + let alice_base_public_key = PublicKey::deserialize(&alice_base_public)?; + + let bob_parameters = BobSignalProtocolParameters::new( + bob_identity_key_pair, + bob_signed_prekey_pair, + None, // one time pre key pair + bob_ephemeral_pair, + IdentityKey::decode(&alice_identity_public)?, + alice_base_public_key, + ); + + let bob_record = initialize_bob_session_record(&bob_parameters)?; + + assert_eq!( + hex::encode(bob_record.local_identity_key_bytes()?), + hex::encode(bob_identity_public) + ); + assert_eq!( + hex::encode( + bob_record + .remote_identity_key_bytes()? + .expect("value exists") + ), + hex::encode(alice_identity_public) + ); + assert_eq!( + hex::encode(bob_record.get_sender_chain_key_bytes()?), + expected_sender_chain + ); + + Ok(()) +} + +#[test] +fn test_ratcheting_session_as_alice() -> Result<(), SignalProtocolError> { + let bob_ephemeral_public = + hex::decode("052cb49776b8770205745a3a6e24f579cdb4ba7a89041005928ebbadc9c05ad458") + .expect("valid hex"); + + let bob_identity_public = + hex::decode("05f1f43874f6966956c2dd473f8fa15adeb71d1cb991b2341692324cefb1c5e626") + .expect("valid hex"); + + let alice_base_public = + hex::decode("05472d1fb1a9862c3af6beaca8920277e2b26f4a79213ec7c906aeb35e03cf8950") + .expect("valid hex"); + + let alice_base_private = + hex::decode("11ae7c64d1e61cd596b76a0db5012673391cae66edbfcf073b4da80516a47449") + .expect("valid hex"); + + let bob_signed_prekey_public = + hex::decode("05ac248a8f263be6863576eb0362e28c828f0107a3379d34bab1586bf8c770cd67") + .expect("valid hex"); + + let alice_identity_public = + hex::decode("05b4a8455660ada65b401007f615e654041746432e3339c6875149bceefcb42b4a") + .expect("valid hex"); + + let alice_identity_private = + hex::decode("9040f0d4e09cf38f6dc7c13779c908c015a1da4fa78737a080eb0a6f4f5f8f58") + .expect("valid hex"); + + // This differs from the Java test and needs investigation + let expected_receiver_chain = + "ab9be50e5cb22a925446ab90ee5670545f4fd32902459ec274b6ad0ae5d6031a"; + + let alice_identity_key_public = IdentityKey::decode(&alice_identity_public)?; + + let bob_ephemeral_public = PublicKey::deserialize(&bob_ephemeral_public)?; + + let alice_identity_key_private = PrivateKey::deserialize(&alice_identity_private)?; + + let bob_signed_prekey_public = PublicKey::deserialize(&bob_signed_prekey_public)?; + + let alice_identity_key_pair = + IdentityKeyPair::new(alice_identity_key_public, alice_identity_key_private); + + let alice_base_key = KeyPair::from_public_and_private(&alice_base_public, &alice_base_private)?; + + let alice_parameters = AliceSignalProtocolParameters::new( + alice_identity_key_pair, + alice_base_key, + IdentityKey::decode(&bob_identity_public)?, + bob_signed_prekey_public, + None, // one-time prekey + bob_ephemeral_public, + ); + + let mut csprng = rand::rngs::OsRng; + let alice_record = initialize_alice_session_record(&alice_parameters, &mut csprng)?; + + assert_eq!( + hex::encode(alice_record.local_identity_key_bytes()?), + hex::encode(alice_identity_public), + ); + assert_eq!( + hex::encode( + alice_record + .remote_identity_key_bytes()? + .expect("value exists") + ), + hex::encode(bob_identity_public) + ); + + assert_eq!( + hex::encode( + alice_record + .get_receiver_chain_key(&bob_ephemeral_public)? + .expect("value exists") + .key() + ), + expected_receiver_chain + ); + + Ok(()) +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/tests/sealed_sender.rs b/net/gurk-rs/files/vendor/libsignal-protocol/tests/sealed_sender.rs new file mode 100644 index 0000000..d836406 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/tests/sealed_sender.rs @@ -0,0 +1,1005 @@ +// +// Copyright 2020-2021 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +mod support; +use support::*; + +use futures_util::FutureExt; +use libsignal_protocol::*; +use rand::rngs::OsRng; +use std::convert::TryFrom; +use uuid::Uuid; + +#[test] +fn test_server_cert() -> Result<(), SignalProtocolError> { + let mut rng = OsRng; + let trust_root = KeyPair::generate(&mut rng); + let server_key = KeyPair::generate(&mut rng); + + let server_cert = + ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?; + + let serialized = server_cert.serialized()?.to_vec(); + + let recovered = ServerCertificate::deserialize(&serialized)?; + + assert!(recovered.validate(&trust_root.public_key)?); + + let mut cert_data = serialized; + let cert_bits = cert_data.len() * 8; + + for b in 0..cert_bits { + cert_data[b / 8] ^= 1u8 << (b % 8); // flip a bit + let cert = ServerCertificate::deserialize(&cert_data); + cert_data[b / 8] ^= 1u8 << (b % 8); // flip the bit back + + match cert { + Ok(cert) => { + assert!(!cert.validate(&trust_root.public_key)?); + } + Err(e) => match e { + SignalProtocolError::InvalidProtobufEncoding + | SignalProtocolError::ProtobufDecodingError(_) + | SignalProtocolError::BadKeyType(_) + | SignalProtocolError::BadKeyLength(_, _) => {} + + unexpected_err => { + panic!("unexpected error {:?}", unexpected_err) + } + }, + } + } + + Ok(()) +} + +#[test] +fn test_revoked_server_cert() -> Result<(), SignalProtocolError> { + let mut rng = OsRng; + let trust_root = KeyPair::generate(&mut rng); + let server_key = KeyPair::generate(&mut rng); + + let revoked_id = 0xDEADC357; + + let server_cert = ServerCertificate::new( + revoked_id, + server_key.public_key, + &trust_root.private_key, + &mut rng, + )?; + + let serialized = server_cert.serialized()?.to_vec(); + + let recovered = ServerCertificate::deserialize(&serialized)?; + + assert!(!recovered.validate(&trust_root.public_key)?); + + Ok(()) +} + +#[test] +fn test_sender_cert() -> Result<(), SignalProtocolError> { + let mut rng = OsRng; + let trust_root = KeyPair::generate(&mut rng); + let server_key = KeyPair::generate(&mut rng); + let key = KeyPair::generate(&mut rng); + + let server_cert = + ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?; + + let device_id = 42; + let expires = 1605722925; + + let sender_cert = SenderCertificate::new( + "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string(), + Some("+14152222222".to_string()), + key.public_key, + device_id, + expires, + server_cert, + &server_key.private_key, + &mut rng, + )?; + + assert!(sender_cert.validate(&trust_root.public_key, expires)?); + assert!(!sender_cert.validate(&trust_root.public_key, expires + 1)?); // expired + + let mut sender_cert_data = sender_cert.serialized()?.to_vec(); + let sender_cert_bits = sender_cert_data.len() * 8; + + for b in 0..sender_cert_bits { + sender_cert_data[b / 8] ^= 1u8 << (b % 8); // flip a bit + let cert = SenderCertificate::deserialize(&sender_cert_data); + sender_cert_data[b / 8] ^= 1u8 << (b % 8); // flip the bit back + + match cert { + Ok(cert) => { + assert!(!cert.validate(&trust_root.public_key, expires)?); + } + Err(e) => match e { + SignalProtocolError::InvalidProtobufEncoding + | SignalProtocolError::ProtobufDecodingError(_) + | SignalProtocolError::BadKeyLength(_, _) + | SignalProtocolError::BadKeyType(_) => {} + + unexpected_err => { + panic!("unexpected error {:?}", unexpected_err) + } + }, + } + } + + Ok(()) +} + +#[test] +fn test_sealed_sender() -> Result<(), SignalProtocolError> { + async { + let mut rng = OsRng; + + let alice_device_id = 23; + let bob_device_id = 42; + + let alice_e164 = "+14151111111".to_owned(); + let bob_e164 = "+14151114444".to_owned(); + + let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string(); + let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string(); + + let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key(); + + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut rng).await?; + + process_prekey_bundle( + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut rng, + None, + ) + .await?; + + let trust_root = KeyPair::generate(&mut rng); + let server_key = KeyPair::generate(&mut rng); + + let server_cert = + ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?; + + let expires = 1605722925; + + let sender_cert = SenderCertificate::new( + alice_uuid.clone(), + Some(alice_e164.clone()), + alice_pubkey, + alice_device_id, + expires, + server_cert, + &server_key.private_key, + &mut rng, + )?; + + let alice_ptext = vec![1, 2, 3, 23, 99]; + let alice_ctext = sealed_sender_encrypt( + &bob_uuid_address, + &sender_cert, + &alice_ptext, + &mut alice_store.session_store, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .await?; + + let bob_ptext = sealed_sender_decrypt( + &alice_ctext, + &trust_root.public_key, + expires - 1, + Some(bob_e164.clone()), + bob_uuid.clone(), + bob_device_id, + &mut bob_store.identity_store, + &mut bob_store.session_store, + &mut bob_store.pre_key_store, + &mut bob_store.signed_pre_key_store, + None, + ) + .await?; + + assert_eq!(bob_ptext.message, alice_ptext); + assert_eq!(bob_ptext.sender_uuid, alice_uuid); + assert_eq!(bob_ptext.sender_e164, Some(alice_e164)); + assert_eq!(bob_ptext.device_id, alice_device_id); + + // Now test but with an expired cert: + + let alice_ctext = sealed_sender_encrypt( + &bob_uuid_address, + &sender_cert, + &alice_ptext, + &mut alice_store.session_store, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .await?; + + let bob_ptext = sealed_sender_decrypt( + &alice_ctext, + &trust_root.public_key, + expires + 11, + Some(bob_e164.clone()), + bob_uuid.clone(), + bob_device_id, + &mut bob_store.identity_store, + &mut bob_store.session_store, + &mut bob_store.pre_key_store, + &mut bob_store.signed_pre_key_store, + None, + ) + .await; + + match bob_ptext { + Err(SignalProtocolError::InvalidSealedSenderMessage(_)) => { /* ok */ } + Err(err) => { + panic!("Unexpected error {}", err) + } + Ok(_) => { + panic!("Shouldn't have decrypted") + } + } + + // Now test but try to verify using some other trust root + + let alice_ctext = sealed_sender_encrypt( + &bob_uuid_address, + &sender_cert, + &alice_ptext, + &mut alice_store.session_store, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .await?; + + let wrong_trust_root = KeyPair::generate(&mut rng); + + let bob_ptext = sealed_sender_decrypt( + &alice_ctext, + &wrong_trust_root.public_key, + expires - 1, + Some(bob_e164.clone()), + bob_uuid.clone(), + bob_device_id, + &mut bob_store.identity_store, + &mut bob_store.session_store, + &mut bob_store.pre_key_store, + &mut bob_store.signed_pre_key_store, + None, + ) + .await; + + match bob_ptext { + Err(SignalProtocolError::InvalidSealedSenderMessage(_)) => { /* ok */ } + Err(err) => { + panic!("Unexpected error {}", err) + } + Ok(_) => { + panic!("Shouldn't have decrypted") + } + } + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn test_sender_key_in_sealed_sender() -> Result<(), SignalProtocolError> { + async { + let mut rng = OsRng; + + let alice_device_id = 23; + let bob_device_id = 42; + + let alice_e164 = "+14151111111".to_owned(); + + let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string(); + let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string(); + + let distribution_id = Uuid::from_u128(0xd1d1d1d1_7000_11eb_b32a_33b8a8a487a6); + + let alice_uuid_address = ProtocolAddress::new(alice_uuid.clone(), 1); + let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key(); + + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut rng).await?; + + process_prekey_bundle( + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut rng, + None, + ) + .await?; + + let trust_root = KeyPair::generate(&mut rng); + let server_key = KeyPair::generate(&mut rng); + + let server_cert = + ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?; + + let expires = 1605722925; + + let sender_cert = SenderCertificate::new( + alice_uuid.clone(), + Some(alice_e164.clone()), + alice_pubkey, + alice_device_id, + expires, + server_cert, + &server_key.private_key, + &mut rng, + )?; + + let distribution_message = create_sender_key_distribution_message( + &alice_uuid_address, + distribution_id, + &mut alice_store, + &mut rng, + None, + ) + .await?; + + process_sender_key_distribution_message( + &alice_uuid_address, + &distribution_message, + &mut bob_store, + None, + ) + .await?; + + let alice_message = group_encrypt( + &mut alice_store, + &alice_uuid_address, + distribution_id, + "swim camp".as_bytes(), + &mut rng, + None, + ) + .await?; + let alice_usmc = UnidentifiedSenderMessageContent::new( + CiphertextMessageType::SenderKey, + sender_cert.clone(), + alice_message.serialized().to_vec(), + ContentHint::Default, + None, + )?; + + let alice_ctext = sealed_sender_encrypt_from_usmc( + &bob_uuid_address, + &alice_usmc, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .await?; + + let bob_usmc = + sealed_sender_decrypt_to_usmc(&alice_ctext, &mut bob_store.identity_store, None) + .await?; + + assert!(matches!( + bob_usmc.msg_type()?, + CiphertextMessageType::SenderKey, + )); + + let bob_plaintext = group_decrypt( + bob_usmc.contents()?, + &mut bob_store, + &alice_uuid_address, + None, + ) + .await?; + + assert_eq!( + String::from_utf8(bob_plaintext).expect("valid UTF-8"), + "swim camp" + ); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn test_sealed_sender_multi_recipient() -> Result<(), SignalProtocolError> { + async { + let mut rng = OsRng; + + let alice_device_id = 23; + let bob_device_id = 42; + + let alice_e164 = "+14151111111".to_owned(); + let bob_e164 = "+14151114444".to_owned(); + + let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string(); + let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string(); + + let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key(); + + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut rng).await?; + + process_prekey_bundle( + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut rng, + None, + ) + .await?; + + let trust_root = KeyPair::generate(&mut rng); + let server_key = KeyPair::generate(&mut rng); + + let server_cert = + ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?; + + let expires = 1605722925; + + let sender_cert = SenderCertificate::new( + alice_uuid.clone(), + Some(alice_e164.clone()), + alice_pubkey, + alice_device_id, + expires, + server_cert, + &server_key.private_key, + &mut rng, + )?; + + let alice_ptext = vec![1, 2, 3, 23, 99]; + let alice_message = message_encrypt( + &alice_ptext, + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + None, + ) + .await?; + + let alice_usmc = UnidentifiedSenderMessageContent::new( + alice_message.message_type(), + sender_cert.clone(), + alice_message.serialize().to_vec(), + ContentHint::Default, + None, + )?; + + let recipients = [&bob_uuid_address]; + let alice_ctext = sealed_sender_multi_recipient_encrypt( + &recipients, + &alice_store + .session_store + .load_existing_sessions(&recipients)?, + &alice_usmc, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .await?; + + let [bob_ctext] = <[_; 1]>::try_from(sealed_sender_multi_recipient_fan_out(&alice_ctext)?) + .expect("only one recipient"); + + let bob_ptext = sealed_sender_decrypt( + &bob_ctext, + &trust_root.public_key, + expires - 1, + Some(bob_e164.clone()), + bob_uuid.clone(), + bob_device_id, + &mut bob_store.identity_store, + &mut bob_store.session_store, + &mut bob_store.pre_key_store, + &mut bob_store.signed_pre_key_store, + None, + ) + .await?; + + assert_eq!(bob_ptext.message, alice_ptext); + assert_eq!(bob_ptext.sender_uuid, alice_uuid); + assert_eq!(bob_ptext.sender_e164, Some(alice_e164)); + assert_eq!(bob_ptext.device_id, alice_device_id); + + // Now test but with an expired cert: + let alice_message = message_encrypt( + &alice_ptext, + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + None, + ) + .await?; + + let alice_usmc = UnidentifiedSenderMessageContent::new( + alice_message.message_type(), + sender_cert.clone(), + alice_message.serialize().to_vec(), + ContentHint::Default, + None, + )?; + + let recipients = [&bob_uuid_address]; + let alice_ctext = sealed_sender_multi_recipient_encrypt( + &recipients, + &alice_store + .session_store + .load_existing_sessions(&recipients)?, + &alice_usmc, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .await?; + + let [bob_ctext] = <[_; 1]>::try_from(sealed_sender_multi_recipient_fan_out(&alice_ctext)?) + .expect("only one recipient"); + + let bob_ptext = sealed_sender_decrypt( + &bob_ctext, + &trust_root.public_key, + expires + 11, + Some(bob_e164.clone()), + bob_uuid.clone(), + bob_device_id, + &mut bob_store.identity_store, + &mut bob_store.session_store, + &mut bob_store.pre_key_store, + &mut bob_store.signed_pre_key_store, + None, + ) + .await; + + match bob_ptext { + Err(SignalProtocolError::InvalidSealedSenderMessage(_)) => { /* ok */ } + Err(err) => { + panic!("Unexpected error {}", err) + } + Ok(_) => { + panic!("Shouldn't have decrypted") + } + } + + // Now test but try to verify using some other trust root + + let alice_message = message_encrypt( + &alice_ptext, + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + None, + ) + .await?; + + let alice_usmc = UnidentifiedSenderMessageContent::new( + alice_message.message_type(), + sender_cert.clone(), + alice_message.serialize().to_vec(), + ContentHint::Default, + None, + )?; + + let recipients = [&bob_uuid_address]; + let alice_ctext = sealed_sender_multi_recipient_encrypt( + &recipients, + &alice_store + .session_store + .load_existing_sessions(&recipients)?, + &alice_usmc, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .await?; + + let wrong_trust_root = KeyPair::generate(&mut rng); + + let [bob_ctext] = <[_; 1]>::try_from(sealed_sender_multi_recipient_fan_out(&alice_ctext)?) + .expect("only one recipient"); + + let bob_ptext = sealed_sender_decrypt( + &bob_ctext, + &wrong_trust_root.public_key, + expires - 1, + Some(bob_e164.clone()), + bob_uuid.clone(), + bob_device_id, + &mut bob_store.identity_store, + &mut bob_store.session_store, + &mut bob_store.pre_key_store, + &mut bob_store.signed_pre_key_store, + None, + ) + .await; + + match bob_ptext { + Err(SignalProtocolError::InvalidSealedSenderMessage(_)) => { /* ok */ } + Err(err) => { + panic!("Unexpected error {}", err) + } + Ok(_) => { + panic!("Shouldn't have decrypted") + } + } + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn test_sealed_sender_multi_recipient_encrypt_with_archived_session( +) -> Result<(), SignalProtocolError> { + async { + let mut rng = OsRng; + + let alice_device_id = 23; + let bob_device_id = 42; + + let alice_e164 = "+14151111111".to_owned(); + + let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string(); + let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string(); + + let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key(); + + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut rng).await?; + + process_prekey_bundle( + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut rng, + None, + ) + .await?; + + let trust_root = KeyPair::generate(&mut rng); + let server_key = KeyPair::generate(&mut rng); + + let server_cert = + ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?; + + let expires = 1605722925; + + let sender_cert = SenderCertificate::new( + alice_uuid.clone(), + Some(alice_e164.clone()), + alice_pubkey, + alice_device_id, + expires, + server_cert, + &server_key.private_key, + &mut rng, + )?; + + let alice_ptext = vec![1, 2, 3, 23, 99]; + let alice_message = message_encrypt( + &alice_ptext, + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + None, + ) + .await?; + + let alice_usmc = UnidentifiedSenderMessageContent::new( + alice_message.message_type(), + sender_cert.clone(), + alice_message.serialize().to_vec(), + ContentHint::Default, + None, + )?; + + let recipients = [&bob_uuid_address]; + let mut session = alice_store + .session_store + .load_session(&bob_uuid_address, None) + .await? + .expect("present"); + session.archive_current_state()?; + match sealed_sender_multi_recipient_encrypt( + &recipients, + &[&session], + &alice_usmc, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .await + { + Ok(_) => panic!("should have failed"), + Err(e) => { + // Make sure we mention *which* recipient's session failed. + let description = e.to_string(); + assert!( + description.contains(&bob_uuid_address.to_string()), + "should mention recipient in message \"{}\"", + description + ); + } + } + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn test_sealed_sender_multi_recipient_encrypt_with_bad_registration_id( +) -> Result<(), SignalProtocolError> { + async { + let mut rng = OsRng; + + let alice_device_id = 23; + let bob_device_id = 42; + + let alice_e164 = "+14151111111".to_owned(); + + let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string(); + let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string(); + + let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = + InMemSignalProtocolStore::new(IdentityKeyPair::generate(&mut rng), 0x4000)?; + + let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key(); + + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut rng).await?; + + process_prekey_bundle( + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut rng, + None, + ) + .await?; + + let trust_root = KeyPair::generate(&mut rng); + let server_key = KeyPair::generate(&mut rng); + + let server_cert = + ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?; + + let expires = 1605722925; + + let sender_cert = SenderCertificate::new( + alice_uuid.clone(), + Some(alice_e164.clone()), + alice_pubkey, + alice_device_id, + expires, + server_cert, + &server_key.private_key, + &mut rng, + )?; + + let alice_ptext = vec![1, 2, 3, 23, 99]; + let alice_message = message_encrypt( + &alice_ptext, + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + None, + ) + .await?; + + let alice_usmc = UnidentifiedSenderMessageContent::new( + alice_message.message_type(), + sender_cert.clone(), + alice_message.serialize().to_vec(), + ContentHint::Default, + None, + )?; + + let recipients = [&bob_uuid_address]; + match sealed_sender_multi_recipient_encrypt( + &recipients, + &alice_store + .session_store + .load_existing_sessions(&recipients)?, + &alice_usmc, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .await + { + Ok(_) => panic!("should have failed"), + Err(SignalProtocolError::InvalidRegistrationId(address, _id)) => { + assert_eq!(address, bob_uuid_address); + } + Err(e) => panic!("wrong error: {}", e), + } + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn test_decryption_error_in_sealed_sender() -> Result<(), SignalProtocolError> { + async { + let mut rng = OsRng; + + let alice_device_id = 23; + let bob_device_id = 42; + + let alice_e164 = "+14151111111".to_owned(); + + let alice_uuid = "9d0652a3-dcc3-4d11-975f-74d61598733f".to_string(); + let bob_uuid = "796abedb-ca4e-4f18-8803-1fde5b921f9f".to_string(); + + let alice_uuid_address = ProtocolAddress::new(alice_uuid.clone(), 1); + let bob_uuid_address = ProtocolAddress::new(bob_uuid.clone(), bob_device_id); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let alice_pubkey = *alice_store.get_identity_key_pair(None).await?.public_key(); + + let alice_pre_key_bundle = create_pre_key_bundle(&mut alice_store, &mut rng).await?; + + process_prekey_bundle( + &alice_uuid_address, + &mut bob_store.session_store, + &mut bob_store.identity_store, + &alice_pre_key_bundle, + &mut rng, + None, + ) + .await?; + + // Send one message to establish a session. + + let bob_first_message = message_encrypt( + b"swim camp", + &alice_uuid_address, + &mut bob_store.session_store, + &mut bob_store.identity_store, + None, + ) + .await?; + + message_decrypt( + &bob_first_message, + &bob_uuid_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &mut alice_store.pre_key_store, + &mut alice_store.signed_pre_key_store, + &mut rng, + None, + ) + .await?; + + // Pretend the second message fails to decrypt. + + let bob_message = message_encrypt( + b"space camp", + &alice_uuid_address, + &mut bob_store.session_store, + &mut bob_store.identity_store, + None, + ) + .await?; + + let original_ratchet_key = match bob_message { + CiphertextMessage::PreKeySignalMessage(ref m) => m.message().sender_ratchet_key(), + _ => panic!("without ACKs, every message should be a PreKeySignalMessage"), + }; + + // Skip over the part where Bob sends this to Alice and Alice fails to decrypt it, + // for whatever reason. + + let trust_root = KeyPair::generate(&mut rng); + let server_key = KeyPair::generate(&mut rng); + + let server_cert = + ServerCertificate::new(1, server_key.public_key, &trust_root.private_key, &mut rng)?; + + let expires = 1605722925; + + let sender_cert = SenderCertificate::new( + alice_uuid.clone(), + Some(alice_e164.clone()), + alice_pubkey, + alice_device_id, + expires, + server_cert, + &server_key.private_key, + &mut rng, + )?; + + let error_message = DecryptionErrorMessage::for_original( + bob_message.serialize(), + bob_message.message_type(), + 408, + 5, + )?; + let error_message_content = PlaintextContent::from(error_message); + let error_message_usmc = UnidentifiedSenderMessageContent::new( + CiphertextMessageType::Plaintext, + sender_cert.clone(), + error_message_content.serialized().to_vec(), + ContentHint::Default, + None, + )?; + + let alice_ctext = sealed_sender_encrypt_from_usmc( + &bob_uuid_address, + &error_message_usmc, + &mut alice_store.identity_store, + None, + &mut rng, + ) + .await?; + + let bob_usmc = + sealed_sender_decrypt_to_usmc(&alice_ctext, &mut bob_store.identity_store, None) + .await?; + + assert!(matches!( + bob_usmc.msg_type()?, + CiphertextMessageType::Plaintext, + )); + + let bob_plaintext = PlaintextContent::try_from(bob_usmc.contents()?)?; + let bob_error_message = + extract_decryption_error_message_from_serialized_content(bob_plaintext.body()) + .expect("present"); + + assert_eq!(bob_error_message.ratchet_key(), Some(original_ratchet_key)); + assert_eq!(bob_error_message.timestamp(), 408); + assert_eq!(bob_error_message.device_id(), 5); + + Ok(()) + } + .now_or_never() + .expect("sync") +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/tests/session.rs b/net/gurk-rs/files/vendor/libsignal-protocol/tests/session.rs new file mode 100644 index 0000000..a389cc5 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/tests/session.rs @@ -0,0 +1,1990 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +mod support; + +use futures_util::FutureExt; +use libsignal_protocol::*; +use rand::rngs::OsRng; +use std::convert::TryFrom; +use support::*; + +#[test] +#[allow(clippy::eval_order_dependence)] +fn test_basic_prekey_v3() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let alice_address = ProtocolAddress::new("+14151111111".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let bob_pre_key_pair = KeyPair::generate(&mut csprng); + let bob_signed_pre_key_pair = KeyPair::generate(&mut csprng); + + let bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key.serialize(); + let bob_signed_pre_key_signature = bob_store + .get_identity_key_pair(None) + .await? + .private_key() + .calculate_signature(&bob_signed_pre_key_public, &mut csprng)?; + + let pre_key_id = 31337; + let signed_pre_key_id = 22; + + let bob_pre_key_bundle = PreKeyBundle::new( + bob_store.get_local_registration_id(None).await?, + 1, // device id + Some((pre_key_id, bob_pre_key_pair.public_key)), // pre key + signed_pre_key_id, // signed pre key id + bob_signed_pre_key_pair.public_key, + bob_signed_pre_key_signature.to_vec(), + *bob_store.get_identity_key_pair(None).await?.identity_key(), + )?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + assert!(alice_store + .load_session(&bob_address, None) + .await? + .is_some()); + assert_eq!( + alice_store + .load_session(&bob_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + + let original_message = "L'homme est condamné à être libre"; + + let outgoing_message = encrypt(&mut alice_store, &bob_address, original_message).await?; + + assert_eq!( + outgoing_message.message_type(), + CiphertextMessageType::PreKey + ); + + let incoming_message = CiphertextMessage::PreKeySignalMessage( + PreKeySignalMessage::try_from(outgoing_message.serialize())?, + ); + + bob_store + .save_pre_key( + pre_key_id, + &PreKeyRecord::new(pre_key_id, &bob_pre_key_pair), + None, + ) + .await?; + bob_store + .save_signed_pre_key( + signed_pre_key_id, + &SignedPreKeyRecord::new( + signed_pre_key_id, + /*timestamp*/ 42, + &bob_signed_pre_key_pair, + &bob_signed_pre_key_signature, + ), + None, + ) + .await?; + + let ptext = decrypt(&mut bob_store, &alice_address, &incoming_message).await?; + + assert_eq!( + String::from_utf8(ptext).expect("valid utf8"), + original_message + ); + + let bobs_response = "Who watches the watchers?"; + + assert!(bob_store + .load_session(&alice_address, None) + .await? + .is_some()); + let bobs_session_with_alice = bob_store + .load_session(&alice_address, None) + .await? + .expect("session found"); + assert_eq!(bobs_session_with_alice.session_version()?, 3); + assert_eq!(bobs_session_with_alice.alice_base_key()?.len(), 32 + 1); + + let bob_outgoing = encrypt(&mut bob_store, &alice_address, bobs_response).await?; + + assert_eq!(bob_outgoing.message_type(), CiphertextMessageType::Whisper); + + let alice_decrypts = decrypt(&mut alice_store, &bob_address, &bob_outgoing).await?; + + assert_eq!( + String::from_utf8(alice_decrypts).expect("valid utf8"), + bobs_response + ); + + run_interaction( + &mut alice_store, + &alice_address, + &mut bob_store, + &bob_address, + ) + .await?; + + let mut alice_store = support::test_in_memory_protocol_store()?; + + let bob_pre_key_pair = KeyPair::generate(&mut csprng); + let bob_signed_pre_key_pair = KeyPair::generate(&mut csprng); + + let bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key.serialize(); + let bob_signed_pre_key_signature = bob_store + .get_identity_key_pair(None) + .await? + .private_key() + .calculate_signature(&bob_signed_pre_key_public, &mut csprng)?; + + let pre_key_id = 31337; + let signed_pre_key_id = 22; + + let bob_pre_key_bundle = PreKeyBundle::new( + bob_store.get_local_registration_id(None).await?, + 1, // device id + Some((pre_key_id + 1, bob_pre_key_pair.public_key)), // pre key, + signed_pre_key_id + 1, + bob_signed_pre_key_pair.public_key, + bob_signed_pre_key_signature.to_vec(), + *bob_store.get_identity_key_pair(None).await?.identity_key(), + )?; + + bob_store + .save_pre_key( + pre_key_id + 1, + &PreKeyRecord::new(pre_key_id + 1, &bob_pre_key_pair), + None, + ) + .await?; + bob_store + .save_signed_pre_key( + signed_pre_key_id + 1, + &SignedPreKeyRecord::new( + signed_pre_key_id + 1, + /*timestamp*/ 42, + &bob_signed_pre_key_pair, + &bob_signed_pre_key_signature, + ), + None, + ) + .await?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + let outgoing_message = encrypt(&mut alice_store, &bob_address, original_message).await?; + + assert!(matches!( + decrypt(&mut bob_store, &alice_address, &outgoing_message) + .await + .unwrap_err(), + SignalProtocolError::UntrustedIdentity(a) if a == alice_address + )); + + assert!( + bob_store + .save_identity( + &alice_address, + alice_store + .get_identity_key_pair(None) + .await? + .identity_key(), + None, + ) + .await? + ); + + let decrypted = decrypt(&mut bob_store, &alice_address, &outgoing_message).await?; + assert_eq!( + String::from_utf8(decrypted).expect("valid utf8"), + original_message + ); + + // Sign pre-key with wrong key: + let bob_pre_key_bundle = PreKeyBundle::new( + bob_store.get_local_registration_id(None).await?, + 1, // device id + Some((pre_key_id, bob_pre_key_pair.public_key)), // pre key + signed_pre_key_id, + bob_signed_pre_key_pair.public_key, + bob_signed_pre_key_signature.to_vec(), + *alice_store + .get_identity_key_pair(None) + .await? + .identity_key(), + )?; + + assert!(process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await + .is_err()); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +#[ignore = "slow to run locally"] +#[allow(clippy::eval_order_dependence)] +fn chain_jump_over_limit() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let alice_address = ProtocolAddress::new("+14151111111".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let bob_pre_key_pair = KeyPair::generate(&mut csprng); + let bob_signed_pre_key_pair = KeyPair::generate(&mut csprng); + + let bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key.serialize(); + let bob_signed_pre_key_signature = bob_store + .get_identity_key_pair(None) + .await? + .private_key() + .calculate_signature(&bob_signed_pre_key_public, &mut csprng)?; + + let pre_key_id = 31337; + let signed_pre_key_id = 22; + + let bob_pre_key_bundle = PreKeyBundle::new( + bob_store.get_local_registration_id(None).await?, + 1, // device id + Some((pre_key_id, bob_pre_key_pair.public_key)), // pre key + signed_pre_key_id, // signed pre key id + bob_signed_pre_key_pair.public_key, + bob_signed_pre_key_signature.to_vec(), + *bob_store.get_identity_key_pair(None).await?.identity_key(), + )?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + bob_store + .save_pre_key( + pre_key_id, + &PreKeyRecord::new(pre_key_id, &bob_pre_key_pair), + None, + ) + .await?; + bob_store + .save_signed_pre_key( + signed_pre_key_id, + &SignedPreKeyRecord::new( + signed_pre_key_id, + /*timestamp*/ 42, + &bob_signed_pre_key_pair, + &bob_signed_pre_key_signature, + ), + None, + ) + .await?; + + // Same as library consts.rs + pub const MAX_FORWARD_JUMPS: usize = 25_000; + + for _i in 0..(MAX_FORWARD_JUMPS + 1) { + let _msg = encrypt( + &mut alice_store, + &bob_address, + "Yet another message for you", + ) + .await?; + } + + let too_far = encrypt(&mut alice_store, &bob_address, "Now you have gone too far").await?; + + assert!(decrypt(&mut bob_store, &alice_address, &too_far) + .await + .is_err()); + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +#[ignore = "slow to run locally"] +#[allow(clippy::eval_order_dependence)] +fn chain_jump_over_limit_with_self() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let a1_address = ProtocolAddress::new("+14151111111".to_owned(), 1); + let a2_address = ProtocolAddress::new("+14151111111".to_owned(), 2); + + let mut a1_store = support::test_in_memory_protocol_store()?; + let mut a2_store = a1_store.clone(); // same key! + + let a2_pre_key_pair = KeyPair::generate(&mut csprng); + let a2_signed_pre_key_pair = KeyPair::generate(&mut csprng); + + let a2_signed_pre_key_public = a2_signed_pre_key_pair.public_key.serialize(); + let a2_signed_pre_key_signature = a2_store + .get_identity_key_pair(None) + .await? + .private_key() + .calculate_signature(&a2_signed_pre_key_public, &mut csprng)?; + + let pre_key_id = 31337; + let signed_pre_key_id = 22; + + let a2_pre_key_bundle = PreKeyBundle::new( + a2_store.get_local_registration_id(None).await?, + 1, // device id + Some((pre_key_id, a2_pre_key_pair.public_key)), // pre key + signed_pre_key_id, // signed pre key id + a2_signed_pre_key_pair.public_key, + a2_signed_pre_key_signature.to_vec(), + *a2_store.get_identity_key_pair(None).await?.identity_key(), + )?; + + process_prekey_bundle( + &a2_address, + &mut a1_store.session_store, + &mut a1_store.identity_store, + &a2_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + a2_store + .save_pre_key( + pre_key_id, + &PreKeyRecord::new(pre_key_id, &a2_pre_key_pair), + None, + ) + .await?; + a2_store + .save_signed_pre_key( + signed_pre_key_id, + &SignedPreKeyRecord::new( + signed_pre_key_id, + /*timestamp*/ 42, + &a2_signed_pre_key_pair, + &a2_signed_pre_key_signature, + ), + None, + ) + .await?; + + // Same as library consts.rs + pub const MAX_FORWARD_JUMPS: usize = 25_000; + + for _i in 0..(MAX_FORWARD_JUMPS + 1) { + let _msg = encrypt( + &mut a1_store, + &a2_address, + "Yet another message for youself", + ) + .await?; + } + + let too_far = encrypt( + &mut a1_store, + &a2_address, + "This is the song that never ends", + ) + .await?; + + let ptext = decrypt(&mut a2_store, &a1_address, &too_far).await?; + assert_eq!( + String::from_utf8(ptext).unwrap(), + "This is the song that never ends" + ); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +#[allow(clippy::eval_order_dependence)] +fn test_bad_signed_pre_key_signature() -> Result<(), SignalProtocolError> { + async { + let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let bob_store = support::test_in_memory_protocol_store()?; + + let mut csprng = OsRng; + let bob_pre_key_pair = KeyPair::generate(&mut csprng); + let bob_signed_pre_key_pair = KeyPair::generate(&mut csprng); + + let bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key.serialize(); + let bob_signed_pre_key_signature = bob_store + .get_identity_key_pair(None) + .await? + .private_key() + .calculate_signature(&bob_signed_pre_key_public, &mut csprng)? + .to_vec(); + + let pre_key_id = 31337; + let signed_pre_key_id = 22; + + for bit in 0..8 * bob_signed_pre_key_signature.len() { + let mut bad_signature = bob_signed_pre_key_signature.clone(); + + bad_signature[bit / 8] ^= 0x01u8 << (bit % 8); + + let bob_pre_key_bundle = PreKeyBundle::new( + bob_store.get_local_registration_id(None).await?, + 1, + Some((pre_key_id, bob_pre_key_pair.public_key)), + signed_pre_key_id, + bob_signed_pre_key_pair.public_key, + bad_signature, + *bob_store.get_identity_key_pair(None).await?.identity_key(), + )?; + + assert!(process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await + .is_err()); + } + + // Finally check that the non-corrupted signature is accepted: + + let bob_pre_key_bundle = PreKeyBundle::new( + bob_store.get_local_registration_id(None).await?, + 1, + Some((pre_key_id, bob_pre_key_pair.public_key)), + signed_pre_key_id, + bob_signed_pre_key_pair.public_key, + bob_signed_pre_key_signature, + *bob_store.get_identity_key_pair(None).await?.identity_key(), + )?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +// testRepeatBundleMessageV2 cannot be represented + +#[test] +#[allow(clippy::eval_order_dependence)] +fn repeat_bundle_message_v3() -> Result<(), SignalProtocolError> { + async { + let alice_address = ProtocolAddress::new("+14151111111".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let mut csprng = OsRng; + let bob_pre_key_pair = KeyPair::generate(&mut csprng); + let bob_signed_pre_key_pair = KeyPair::generate(&mut csprng); + + let bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key.serialize(); + let bob_signed_pre_key_signature = bob_store + .get_identity_key_pair(None) + .await? + .private_key() + .calculate_signature(&bob_signed_pre_key_public, &mut csprng)?; + + let pre_key_id = 31337; + let signed_pre_key_id = 22; + + let bob_pre_key_bundle = PreKeyBundle::new( + bob_store.get_local_registration_id(None).await?, + 1, // device id + Some((pre_key_id, bob_pre_key_pair.public_key)), // pre key + signed_pre_key_id, // signed pre key id + bob_signed_pre_key_pair.public_key, + bob_signed_pre_key_signature.to_vec(), + *bob_store.get_identity_key_pair(None).await?.identity_key(), + )?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + assert!(alice_store + .load_session(&bob_address, None) + .await? + .is_some()); + assert_eq!( + alice_store + .load_session(&bob_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + + let original_message = "L'homme est condamné à être libre"; + + let outgoing_message1 = encrypt(&mut alice_store, &bob_address, original_message).await?; + let outgoing_message2 = encrypt(&mut alice_store, &bob_address, original_message).await?; + + assert_eq!( + outgoing_message1.message_type(), + CiphertextMessageType::PreKey + ); + assert_eq!( + outgoing_message2.message_type(), + CiphertextMessageType::PreKey + ); + + let incoming_message = CiphertextMessage::PreKeySignalMessage( + PreKeySignalMessage::try_from(outgoing_message1.serialize())?, + ); + + bob_store + .save_pre_key( + pre_key_id, + &PreKeyRecord::new(pre_key_id, &bob_pre_key_pair), + None, + ) + .await?; + bob_store + .save_signed_pre_key( + signed_pre_key_id, + &SignedPreKeyRecord::new( + signed_pre_key_id, + /*timestamp*/ 42, + &bob_signed_pre_key_pair, + &bob_signed_pre_key_signature, + ), + None, + ) + .await?; + + let ptext = decrypt(&mut bob_store, &alice_address, &incoming_message).await?; + assert_eq!( + String::from_utf8(ptext).expect("valid utf8"), + original_message + ); + + let bob_outgoing = encrypt(&mut bob_store, &alice_address, original_message).await?; + assert_eq!(bob_outgoing.message_type(), CiphertextMessageType::Whisper); + let alice_decrypts = decrypt(&mut alice_store, &bob_address, &bob_outgoing).await?; + assert_eq!( + String::from_utf8(alice_decrypts).expect("valid utf8"), + original_message + ); + + // The test + + let incoming_message2 = CiphertextMessage::PreKeySignalMessage( + PreKeySignalMessage::try_from(outgoing_message2.serialize())?, + ); + + let ptext = decrypt(&mut bob_store, &alice_address, &incoming_message2).await?; + assert_eq!( + String::from_utf8(ptext).expect("valid utf8"), + original_message + ); + + let bob_outgoing = encrypt(&mut bob_store, &alice_address, original_message).await?; + let alice_decrypts = decrypt(&mut alice_store, &bob_address, &bob_outgoing).await?; + assert_eq!( + String::from_utf8(alice_decrypts).expect("valid utf8"), + original_message + ); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +#[allow(clippy::eval_order_dependence)] +fn bad_message_bundle() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let alice_address = ProtocolAddress::new("+14151111111".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let bob_pre_key_pair = KeyPair::generate(&mut csprng); + let bob_signed_pre_key_pair = KeyPair::generate(&mut csprng); + + let bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key.serialize(); + let bob_signed_pre_key_signature = bob_store + .get_identity_key_pair(None) + .await? + .private_key() + .calculate_signature(&bob_signed_pre_key_public, &mut csprng)?; + + let pre_key_id = 31337; + let signed_pre_key_id = 22; + + let bob_pre_key_bundle = PreKeyBundle::new( + bob_store.get_local_registration_id(None).await?, + 1, // device id + Some((pre_key_id, bob_pre_key_pair.public_key)), + signed_pre_key_id, // signed pre key id + bob_signed_pre_key_pair.public_key, + bob_signed_pre_key_signature.to_vec(), + *bob_store.get_identity_key_pair(None).await?.identity_key(), + )?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + bob_store + .save_pre_key( + pre_key_id, + &PreKeyRecord::new(pre_key_id, &bob_pre_key_pair), + None, + ) + .await?; + bob_store + .save_signed_pre_key( + signed_pre_key_id, + &SignedPreKeyRecord::new( + signed_pre_key_id, + /*timestamp*/ 42, + &bob_signed_pre_key_pair, + &bob_signed_pre_key_signature, + ), + None, + ) + .await?; + + assert!(alice_store + .load_session(&bob_address, None) + .await? + .is_some()); + assert_eq!( + alice_store + .load_session(&bob_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + + let original_message = "L'homme est condamné à être libre"; + + assert!(bob_store.get_pre_key(pre_key_id, None).await.is_ok()); + let outgoing_message = encrypt(&mut alice_store, &bob_address, original_message).await?; + + assert_eq!( + outgoing_message.message_type(), + CiphertextMessageType::PreKey + ); + + let outgoing_message = outgoing_message.serialize().to_vec(); + + let mut corrupted_message: Vec = outgoing_message.clone(); + corrupted_message[outgoing_message.len() - 10] ^= 1; + + let incoming_message = CiphertextMessage::PreKeySignalMessage( + PreKeySignalMessage::try_from(corrupted_message.as_slice())?, + ); + + assert!(decrypt(&mut bob_store, &alice_address, &incoming_message) + .await + .is_err()); + assert!(bob_store.get_pre_key(pre_key_id, None).await.is_ok()); + + let incoming_message = CiphertextMessage::PreKeySignalMessage( + PreKeySignalMessage::try_from(outgoing_message.as_slice())?, + ); + + let ptext = decrypt(&mut bob_store, &alice_address, &incoming_message).await?; + + assert_eq!( + String::from_utf8(ptext).expect("valid utf8"), + original_message + ); + assert!(matches!( + bob_store.get_pre_key(pre_key_id, None).await.unwrap_err(), + SignalProtocolError::InvalidPreKeyId + )); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +#[allow(clippy::eval_order_dependence)] +fn optional_one_time_prekey() -> Result<(), SignalProtocolError> { + async { + let alice_address = ProtocolAddress::new("+14151111111".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let mut csprng = OsRng; + let bob_signed_pre_key_pair = KeyPair::generate(&mut csprng); + + let bob_signed_pre_key_public = bob_signed_pre_key_pair.public_key.serialize(); + let bob_signed_pre_key_signature = bob_store + .get_identity_key_pair(None) + .await? + .private_key() + .calculate_signature(&bob_signed_pre_key_public, &mut csprng)?; + + let signed_pre_key_id = 22; + + let bob_pre_key_bundle = PreKeyBundle::new( + bob_store.get_local_registration_id(None).await?, + 1, // device id + None, // no pre key + signed_pre_key_id, // signed pre key id + bob_signed_pre_key_pair.public_key, + bob_signed_pre_key_signature.to_vec(), + *bob_store.get_identity_key_pair(None).await?.identity_key(), + )?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + assert_eq!( + alice_store + .load_session(&bob_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + + let original_message = "L'homme est condamné à être libre"; + + let outgoing_message = encrypt(&mut alice_store, &bob_address, original_message).await?; + + assert_eq!( + outgoing_message.message_type(), + CiphertextMessageType::PreKey + ); + + let incoming_message = CiphertextMessage::PreKeySignalMessage( + PreKeySignalMessage::try_from(outgoing_message.serialize())?, + ); + + bob_store + .save_signed_pre_key( + signed_pre_key_id, + &SignedPreKeyRecord::new( + signed_pre_key_id, + /*timestamp*/ 42, + &bob_signed_pre_key_pair, + &bob_signed_pre_key_signature, + ), + None, + ) + .await?; + + let ptext = decrypt(&mut bob_store, &alice_address, &incoming_message).await?; + + assert_eq!( + String::from_utf8(ptext).expect("valid utf8"), + original_message + ); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn basic_session_v3() -> Result<(), SignalProtocolError> { + let (alice_session, bob_session) = initialize_sessions_v3()?; + run_session_interaction(alice_session, bob_session)?; + Ok(()) +} + +#[test] +fn message_key_limits() -> Result<(), SignalProtocolError> { + async { + let (alice_session_record, bob_session_record) = initialize_sessions_v3()?; + + let alice_address = ProtocolAddress::new("+14159999999".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14158888888".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + alice_store + .store_session(&bob_address, &alice_session_record, None) + .await?; + bob_store + .store_session(&alice_address, &bob_session_record, None) + .await?; + + const MAX_MESSAGE_KEYS: usize = 2000; // same value as in library + const TOO_MANY_MESSAGES: usize = MAX_MESSAGE_KEYS + 300; + + let mut inflight = Vec::with_capacity(TOO_MANY_MESSAGES); + + for i in 0..TOO_MANY_MESSAGES { + inflight + .push(encrypt(&mut alice_store, &bob_address, &format!("It's over {}", i)).await?); + } + + assert_eq!( + String::from_utf8(decrypt(&mut bob_store, &alice_address, &inflight[1000]).await?) + .expect("valid utf8"), + "It's over 1000" + ); + assert_eq!( + String::from_utf8( + decrypt( + &mut bob_store, + &alice_address, + &inflight[TOO_MANY_MESSAGES - 1] + ) + .await? + ) + .expect("valid utf8"), + format!("It's over {}", TOO_MANY_MESSAGES - 1) + ); + + let err = decrypt(&mut bob_store, &alice_address, &inflight[5]) + .await + .unwrap_err(); + assert!(matches!( + err, + SignalProtocolError::DuplicatedMessage(2300, 5) + )); + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[allow(clippy::needless_range_loop)] +fn run_session_interaction( + alice_session: SessionRecord, + bob_session: SessionRecord, +) -> Result<(), SignalProtocolError> { + async { + use rand::seq::SliceRandom; + + let alice_address = ProtocolAddress::new("+14159999999".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14158888888".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + alice_store + .store_session(&bob_address, &alice_session, None) + .await?; + bob_store + .store_session(&alice_address, &bob_session, None) + .await?; + + let alice_plaintext = "This is Alice's message"; + let alice_ciphertext = encrypt(&mut alice_store, &bob_address, alice_plaintext).await?; + let bob_decrypted = decrypt(&mut bob_store, &alice_address, &alice_ciphertext).await?; + assert_eq!( + String::from_utf8(bob_decrypted).expect("valid utf8"), + alice_plaintext + ); + + let bob_plaintext = "This is Bob's reply"; + + let bob_ciphertext = encrypt(&mut bob_store, &alice_address, bob_plaintext).await?; + let alice_decrypted = decrypt(&mut alice_store, &bob_address, &bob_ciphertext).await?; + assert_eq!( + String::from_utf8(alice_decrypted).expect("valid utf8"), + bob_plaintext + ); + + const ALICE_MESSAGE_COUNT: usize = 50; + const BOB_MESSAGE_COUNT: usize = 50; + + let mut alice_messages = Vec::with_capacity(ALICE_MESSAGE_COUNT); + + for i in 0..ALICE_MESSAGE_COUNT { + let ptext = format!("смерть за смерть {}", i); + let ctext = encrypt(&mut alice_store, &bob_address, &ptext).await?; + alice_messages.push((ptext, ctext)); + } + + let mut rng = rand::rngs::OsRng; + + alice_messages.shuffle(&mut rng); + + for i in 0..ALICE_MESSAGE_COUNT / 2 { + let ptext = decrypt(&mut bob_store, &alice_address, &alice_messages[i].1).await?; + assert_eq!( + String::from_utf8(ptext).expect("valid utf8"), + alice_messages[i].0 + ); + } + + let mut bob_messages = Vec::with_capacity(BOB_MESSAGE_COUNT); + + for i in 0..BOB_MESSAGE_COUNT { + let ptext = format!("Relax in the safety of your own delusions. {}", i); + let ctext = encrypt(&mut bob_store, &alice_address, &ptext).await?; + bob_messages.push((ptext, ctext)); + } + + bob_messages.shuffle(&mut rng); + + for i in 0..BOB_MESSAGE_COUNT / 2 { + let ptext = decrypt(&mut alice_store, &bob_address, &bob_messages[i].1).await?; + assert_eq!( + String::from_utf8(ptext).expect("valid utf8"), + bob_messages[i].0 + ); + } + + for i in ALICE_MESSAGE_COUNT / 2..ALICE_MESSAGE_COUNT { + let ptext = decrypt(&mut bob_store, &alice_address, &alice_messages[i].1).await?; + assert_eq!( + String::from_utf8(ptext).expect("valid utf8"), + alice_messages[i].0 + ); + } + + for i in BOB_MESSAGE_COUNT / 2..BOB_MESSAGE_COUNT { + let ptext = decrypt(&mut alice_store, &bob_address, &bob_messages[i].1).await?; + assert_eq!( + String::from_utf8(ptext).expect("valid utf8"), + bob_messages[i].0 + ); + } + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +async fn run_interaction( + alice_store: &mut InMemSignalProtocolStore, + alice_address: &ProtocolAddress, + bob_store: &mut InMemSignalProtocolStore, + bob_address: &ProtocolAddress, +) -> Result<(), SignalProtocolError> { + let alice_ptext = "It's rabbit season"; + + let alice_message = encrypt(alice_store, bob_address, alice_ptext).await?; + assert_eq!(alice_message.message_type(), CiphertextMessageType::Whisper); + assert_eq!( + String::from_utf8(decrypt(bob_store, alice_address, &alice_message).await?) + .expect("valid utf8"), + alice_ptext + ); + + let bob_ptext = "It's duck season"; + + let bob_message = encrypt(bob_store, alice_address, bob_ptext).await?; + assert_eq!(bob_message.message_type(), CiphertextMessageType::Whisper); + assert_eq!( + String::from_utf8(decrypt(alice_store, bob_address, &bob_message).await?) + .expect("valid utf8"), + bob_ptext + ); + + for i in 0..10 { + let alice_ptext = format!("A->B message {}", i); + let alice_message = encrypt(alice_store, bob_address, &alice_ptext).await?; + assert_eq!(alice_message.message_type(), CiphertextMessageType::Whisper); + assert_eq!( + String::from_utf8(decrypt(bob_store, alice_address, &alice_message).await?) + .expect("valid utf8"), + alice_ptext + ); + } + + for i in 0..10 { + let bob_ptext = format!("B->A message {}", i); + let bob_message = encrypt(bob_store, alice_address, &bob_ptext).await?; + assert_eq!(bob_message.message_type(), CiphertextMessageType::Whisper); + assert_eq!( + String::from_utf8(decrypt(alice_store, bob_address, &bob_message).await?) + .expect("valid utf8"), + bob_ptext + ); + } + + let mut alice_ooo_messages = vec![]; + + for i in 0..10 { + let alice_ptext = format!("A->B OOO message {}", i); + let alice_message = encrypt(alice_store, bob_address, &alice_ptext).await?; + alice_ooo_messages.push((alice_ptext, alice_message)); + } + + for i in 0..10 { + let alice_ptext = format!("A->B post-OOO message {}", i); + let alice_message = encrypt(alice_store, bob_address, &alice_ptext).await?; + assert_eq!(alice_message.message_type(), CiphertextMessageType::Whisper); + assert_eq!( + String::from_utf8(decrypt(bob_store, alice_address, &alice_message).await?) + .expect("valid utf8"), + alice_ptext + ); + } + + for i in 0..10 { + let bob_ptext = format!("B->A message post-OOO {}", i); + let bob_message = encrypt(bob_store, alice_address, &bob_ptext).await?; + assert_eq!(bob_message.message_type(), CiphertextMessageType::Whisper); + assert_eq!( + String::from_utf8(decrypt(alice_store, bob_address, &bob_message).await?) + .expect("valid utf8"), + bob_ptext + ); + } + + for (ptext, ctext) in alice_ooo_messages { + assert_eq!( + String::from_utf8(decrypt(bob_store, alice_address, &ctext).await?) + .expect("valid utf8"), + ptext + ); + } + + Ok(()) +} + +#[allow(clippy::eval_order_dependence)] +async fn is_session_id_equal( + alice_store: &dyn ProtocolStore, + alice_address: &ProtocolAddress, + bob_store: &dyn ProtocolStore, + bob_address: &ProtocolAddress, +) -> Result { + Ok(alice_store + .load_session(bob_address, None) + .await? + .expect("session found") + .alice_base_key()? + == bob_store + .load_session(alice_address, None) + .await? + .expect("session found") + .alice_base_key()?) +} + +#[test] +fn basic_simultaneous_initiate() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let alice_address = ProtocolAddress::new("+14151111111".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let alice_pre_key_bundle = create_pre_key_bundle(&mut alice_store, &mut csprng).await?; + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut csprng).await?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + process_prekey_bundle( + &alice_address, + &mut bob_store.session_store, + &mut bob_store.identity_store, + &alice_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + let message_for_bob = encrypt(&mut alice_store, &bob_address, "hi bob").await?; + let message_for_alice = encrypt(&mut bob_store, &alice_address, "hi alice").await?; + + assert_eq!( + message_for_bob.message_type(), + CiphertextMessageType::PreKey + ); + assert_eq!( + message_for_alice.message_type(), + CiphertextMessageType::PreKey + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address).await? + ); + + let alice_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from( + message_for_alice.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(alice_plaintext).expect("valid utf8"), + "hi alice" + ); + + let bob_plaintext = decrypt( + &mut bob_store, + &alice_address, + &CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from( + message_for_bob.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(bob_plaintext).expect("valid utf8"), + "hi bob" + ); + + assert_eq!( + alice_store + .load_session(&bob_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + assert_eq!( + bob_store + .load_session(&alice_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address).await? + ); + + let alice_response = encrypt(&mut alice_store, &bob_address, "nice to see you").await?; + + assert_eq!( + alice_response.message_type(), + CiphertextMessageType::Whisper + ); + + let response_plaintext = decrypt( + &mut bob_store, + &alice_address, + &CiphertextMessage::SignalMessage(SignalMessage::try_from(alice_response.serialize())?), + ) + .await?; + assert_eq!( + String::from_utf8(response_plaintext).expect("valid utf8"), + "nice to see you" + ); + + assert!(is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address).await?); + + let bob_response = encrypt(&mut bob_store, &alice_address, "you as well").await?; + + assert_eq!(bob_response.message_type(), CiphertextMessageType::Whisper); + + let response_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::SignalMessage(SignalMessage::try_from(bob_response.serialize())?), + ) + .await?; + assert_eq!( + String::from_utf8(response_plaintext).expect("valid utf8"), + "you as well" + ); + + assert!(is_session_id_equal(&bob_store, &bob_address, &alice_store, &alice_address).await?); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn simultaneous_initiate_with_lossage() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let alice_address = ProtocolAddress::new("+14151111111".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let alice_pre_key_bundle = create_pre_key_bundle(&mut alice_store, &mut csprng).await?; + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut csprng).await?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + process_prekey_bundle( + &alice_address, + &mut bob_store.session_store, + &mut bob_store.identity_store, + &alice_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + let message_for_bob = encrypt(&mut alice_store, &bob_address, "hi bob").await?; + let message_for_alice = encrypt(&mut bob_store, &alice_address, "hi alice").await?; + + assert_eq!( + message_for_bob.message_type(), + CiphertextMessageType::PreKey + ); + assert_eq!( + message_for_alice.message_type(), + CiphertextMessageType::PreKey + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address).await? + ); + + let bob_plaintext = decrypt( + &mut bob_store, + &alice_address, + &CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from( + message_for_bob.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(bob_plaintext).expect("valid utf8"), + "hi bob" + ); + + assert_eq!( + alice_store + .load_session(&bob_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + assert_eq!( + bob_store + .load_session(&alice_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + + let alice_response = encrypt(&mut alice_store, &bob_address, "nice to see you").await?; + + assert_eq!(alice_response.message_type(), CiphertextMessageType::PreKey); + + let response_plaintext = decrypt( + &mut bob_store, + &alice_address, + &CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from( + alice_response.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(response_plaintext).expect("valid utf8"), + "nice to see you" + ); + + assert!(is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address).await?); + + let bob_response = encrypt(&mut bob_store, &alice_address, "you as well").await?; + + assert_eq!(bob_response.message_type(), CiphertextMessageType::Whisper); + + let response_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::SignalMessage(SignalMessage::try_from(bob_response.serialize())?), + ) + .await?; + assert_eq!( + String::from_utf8(response_plaintext).expect("valid utf8"), + "you as well" + ); + + assert!(is_session_id_equal(&bob_store, &bob_address, &alice_store, &alice_address).await?); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn simultaneous_initiate_lost_message() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let alice_address = ProtocolAddress::new("+14151111111".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let alice_pre_key_bundle = create_pre_key_bundle(&mut alice_store, &mut csprng).await?; + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut csprng).await?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + process_prekey_bundle( + &alice_address, + &mut bob_store.session_store, + &mut bob_store.identity_store, + &alice_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + let message_for_bob = encrypt(&mut alice_store, &bob_address, "hi bob").await?; + let message_for_alice = encrypt(&mut bob_store, &alice_address, "hi alice").await?; + + assert_eq!( + message_for_bob.message_type(), + CiphertextMessageType::PreKey + ); + assert_eq!( + message_for_alice.message_type(), + CiphertextMessageType::PreKey + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address).await? + ); + + let alice_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from( + message_for_alice.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(alice_plaintext).expect("valid utf8"), + "hi alice" + ); + + let bob_plaintext = decrypt( + &mut bob_store, + &alice_address, + &CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from( + message_for_bob.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(bob_plaintext).expect("valid utf8"), + "hi bob" + ); + + assert_eq!( + alice_store + .load_session(&bob_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + assert_eq!( + bob_store + .load_session(&alice_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address).await? + ); + + let alice_response = encrypt(&mut alice_store, &bob_address, "nice to see you").await?; + + assert_eq!( + alice_response.message_type(), + CiphertextMessageType::Whisper + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address).await? + ); + + let bob_response = encrypt(&mut bob_store, &alice_address, "you as well").await?; + + assert_eq!(bob_response.message_type(), CiphertextMessageType::Whisper); + + let response_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::SignalMessage(SignalMessage::try_from(bob_response.serialize())?), + ) + .await?; + assert_eq!( + String::from_utf8(response_plaintext).expect("valid utf8"), + "you as well" + ); + + assert!(is_session_id_equal(&bob_store, &bob_address, &alice_store, &alice_address).await?); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn simultaneous_initiate_repeated_messages() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let alice_address = ProtocolAddress::new("+14151111111".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + for _ in 0..15 { + let alice_pre_key_bundle = create_pre_key_bundle(&mut alice_store, &mut csprng).await?; + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut csprng).await?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + process_prekey_bundle( + &alice_address, + &mut bob_store.session_store, + &mut bob_store.identity_store, + &alice_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + let message_for_bob = encrypt(&mut alice_store, &bob_address, "hi bob").await?; + let message_for_alice = encrypt(&mut bob_store, &alice_address, "hi alice").await?; + + assert_eq!( + message_for_bob.message_type(), + CiphertextMessageType::PreKey + ); + assert_eq!( + message_for_alice.message_type(), + CiphertextMessageType::PreKey + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address) + .await? + ); + + let alice_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from( + message_for_alice.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(alice_plaintext).expect("valid utf8"), + "hi alice" + ); + + let bob_plaintext = decrypt( + &mut bob_store, + &alice_address, + &CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from( + message_for_bob.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(bob_plaintext).expect("valid utf8"), + "hi bob" + ); + + assert_eq!( + alice_store + .load_session(&bob_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + assert_eq!( + bob_store + .load_session(&alice_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address) + .await? + ); + } + + for _ in 0..50 { + let message_for_bob = encrypt(&mut alice_store, &bob_address, "hi bob").await?; + let message_for_alice = encrypt(&mut bob_store, &alice_address, "hi alice").await?; + + assert_eq!( + message_for_bob.message_type(), + CiphertextMessageType::Whisper + ); + assert_eq!( + message_for_alice.message_type(), + CiphertextMessageType::Whisper + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address) + .await? + ); + + let alice_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::SignalMessage(SignalMessage::try_from( + message_for_alice.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(alice_plaintext).expect("valid utf8"), + "hi alice" + ); + + let bob_plaintext = decrypt( + &mut bob_store, + &alice_address, + &CiphertextMessage::SignalMessage(SignalMessage::try_from( + message_for_bob.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(bob_plaintext).expect("valid utf8"), + "hi bob" + ); + + assert_eq!( + alice_store + .load_session(&bob_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + assert_eq!( + bob_store + .load_session(&alice_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address) + .await? + ); + } + + let alice_response = encrypt(&mut alice_store, &bob_address, "nice to see you").await?; + + assert_eq!( + alice_response.message_type(), + CiphertextMessageType::Whisper + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address).await? + ); + + let bob_response = encrypt(&mut bob_store, &alice_address, "you as well").await?; + + assert_eq!(bob_response.message_type(), CiphertextMessageType::Whisper); + + let response_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::SignalMessage(SignalMessage::try_from(bob_response.serialize())?), + ) + .await?; + assert_eq!( + String::from_utf8(response_plaintext).expect("valid utf8"), + "you as well" + ); + + assert!(is_session_id_equal(&bob_store, &bob_address, &alice_store, &alice_address).await?); + + Ok(()) + } + .now_or_never() + .expect("sync") +} + +#[test] +fn simultaneous_initiate_lost_message_repeated_messages() -> Result<(), SignalProtocolError> { + async { + let mut csprng = OsRng; + + let alice_address = ProtocolAddress::new("+14151111111".to_owned(), 1); + let bob_address = ProtocolAddress::new("+14151111112".to_owned(), 1); + + let mut alice_store = support::test_in_memory_protocol_store()?; + let mut bob_store = support::test_in_memory_protocol_store()?; + + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut csprng).await?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + let lost_message_for_bob = + encrypt(&mut alice_store, &bob_address, "it was so long ago").await?; + + for _ in 0..15 { + let alice_pre_key_bundle = create_pre_key_bundle(&mut alice_store, &mut csprng).await?; + let bob_pre_key_bundle = create_pre_key_bundle(&mut bob_store, &mut csprng).await?; + + process_prekey_bundle( + &bob_address, + &mut alice_store.session_store, + &mut alice_store.identity_store, + &bob_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + process_prekey_bundle( + &alice_address, + &mut bob_store.session_store, + &mut bob_store.identity_store, + &alice_pre_key_bundle, + &mut csprng, + None, + ) + .await?; + + let message_for_bob = encrypt(&mut alice_store, &bob_address, "hi bob").await?; + let message_for_alice = encrypt(&mut bob_store, &alice_address, "hi alice").await?; + + assert_eq!( + message_for_bob.message_type(), + CiphertextMessageType::PreKey + ); + assert_eq!( + message_for_alice.message_type(), + CiphertextMessageType::PreKey + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address) + .await? + ); + + let alice_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from( + message_for_alice.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(alice_plaintext).expect("valid utf8"), + "hi alice" + ); + + let bob_plaintext = decrypt( + &mut bob_store, + &alice_address, + &CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from( + message_for_bob.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(bob_plaintext).expect("valid utf8"), + "hi bob" + ); + + assert_eq!( + alice_store + .load_session(&bob_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + assert_eq!( + bob_store + .load_session(&alice_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address) + .await? + ); + } + + for _ in 0..50 { + let message_for_bob = encrypt(&mut alice_store, &bob_address, "hi bob").await?; + let message_for_alice = encrypt(&mut bob_store, &alice_address, "hi alice").await?; + + assert_eq!( + message_for_bob.message_type(), + CiphertextMessageType::Whisper + ); + assert_eq!( + message_for_alice.message_type(), + CiphertextMessageType::Whisper + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address) + .await? + ); + + let alice_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::SignalMessage(SignalMessage::try_from( + message_for_alice.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(alice_plaintext).expect("valid utf8"), + "hi alice" + ); + + let bob_plaintext = decrypt( + &mut bob_store, + &alice_address, + &CiphertextMessage::SignalMessage(SignalMessage::try_from( + message_for_bob.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(bob_plaintext).expect("valid utf8"), + "hi bob" + ); + + assert_eq!( + alice_store + .load_session(&bob_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + assert_eq!( + bob_store + .load_session(&alice_address, None) + .await? + .expect("session found") + .session_version()?, + 3 + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address) + .await? + ); + } + + let alice_response = encrypt(&mut alice_store, &bob_address, "nice to see you").await?; + + assert_eq!( + alice_response.message_type(), + CiphertextMessageType::Whisper + ); + + assert!( + !is_session_id_equal(&alice_store, &alice_address, &bob_store, &bob_address).await? + ); + + let bob_response = encrypt(&mut bob_store, &alice_address, "you as well").await?; + + assert_eq!(bob_response.message_type(), CiphertextMessageType::Whisper); + + let response_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::SignalMessage(SignalMessage::try_from(bob_response.serialize())?), + ) + .await?; + assert_eq!( + String::from_utf8(response_plaintext).expect("valid utf8"), + "you as well" + ); + + assert!(is_session_id_equal(&bob_store, &bob_address, &alice_store, &alice_address).await?); + + let blast_from_the_past = decrypt( + &mut bob_store, + &alice_address, + &CiphertextMessage::PreKeySignalMessage(PreKeySignalMessage::try_from( + lost_message_for_bob.serialize(), + )?), + ) + .await?; + assert_eq!( + String::from_utf8(blast_from_the_past).expect("valid utf8"), + "it was so long ago" + ); + + assert!( + !is_session_id_equal(&bob_store, &bob_address, &alice_store, &alice_address).await? + ); + + let bob_response = encrypt(&mut bob_store, &alice_address, "so it was").await?; + + assert_eq!(bob_response.message_type(), CiphertextMessageType::Whisper); + + let response_plaintext = decrypt( + &mut alice_store, + &bob_address, + &CiphertextMessage::SignalMessage(SignalMessage::try_from(bob_response.serialize())?), + ) + .await?; + assert_eq!( + String::from_utf8(response_plaintext).expect("valid utf8"), + "so it was" + ); + + assert!(is_session_id_equal(&bob_store, &bob_address, &alice_store, &alice_address).await?); + + Ok(()) + } + .now_or_never() + .expect("sync") +} diff --git a/net/gurk-rs/files/vendor/libsignal-protocol/tests/support/mod.rs b/net/gurk-rs/files/vendor/libsignal-protocol/tests/support/mod.rs new file mode 100644 index 0000000..89d9d0b --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-protocol/tests/support/mod.rs @@ -0,0 +1,142 @@ +// +// Copyright 2020 Signal Messenger, LLC. +// SPDX-License-Identifier: AGPL-3.0-only +// + +use libsignal_protocol::*; +use rand::{rngs::OsRng, CryptoRng, Rng}; + +pub fn test_in_memory_protocol_store() -> Result { + let mut csprng = OsRng; + let identity_key = IdentityKeyPair::generate(&mut csprng); + let registration_id = 5; // fixme randomly generate this + + InMemSignalProtocolStore::new(identity_key, registration_id) +} + +#[allow(dead_code)] +pub async fn encrypt( + store: &mut InMemSignalProtocolStore, + remote_address: &ProtocolAddress, + msg: &str, +) -> Result { + message_encrypt( + msg.as_bytes(), + remote_address, + &mut store.session_store, + &mut store.identity_store, + None, + ) + .await +} + +#[allow(dead_code)] +pub async fn decrypt( + store: &mut InMemSignalProtocolStore, + remote_address: &ProtocolAddress, + msg: &CiphertextMessage, +) -> Result, SignalProtocolError> { + let mut csprng = OsRng; + message_decrypt( + msg, + remote_address, + &mut store.session_store, + &mut store.identity_store, + &mut store.pre_key_store, + &mut store.signed_pre_key_store, + &mut csprng, + None, + ) + .await +} + +#[allow(dead_code, clippy::eval_order_dependence)] +pub async fn create_pre_key_bundle( + store: &mut dyn ProtocolStore, + mut csprng: &mut R, +) -> Result { + let pre_key_pair = KeyPair::generate(&mut csprng); + let signed_pre_key_pair = KeyPair::generate(&mut csprng); + + let signed_pre_key_public = signed_pre_key_pair.public_key.serialize(); + let signed_pre_key_signature = store + .get_identity_key_pair(None) + .await? + .private_key() + .calculate_signature(&signed_pre_key_public, &mut csprng)?; + + let device_id: u32 = csprng.gen(); + let pre_key_id: u32 = csprng.gen(); + let signed_pre_key_id: u32 = csprng.gen(); + + let pre_key_bundle = PreKeyBundle::new( + store.get_local_registration_id(None).await?, + device_id, + Some((pre_key_id, pre_key_pair.public_key)), + signed_pre_key_id, + signed_pre_key_pair.public_key, + signed_pre_key_signature.to_vec(), + *store.get_identity_key_pair(None).await?.identity_key(), + )?; + + store + .save_pre_key( + pre_key_id, + &PreKeyRecord::new(pre_key_id, &pre_key_pair), + None, + ) + .await?; + + let timestamp = csprng.gen(); + + store + .save_signed_pre_key( + signed_pre_key_id, + &SignedPreKeyRecord::new( + signed_pre_key_id, + timestamp, + &signed_pre_key_pair, + &signed_pre_key_signature, + ), + None, + ) + .await?; + + Ok(pre_key_bundle) +} + +#[allow(dead_code)] +pub fn initialize_sessions_v3() -> Result<(SessionRecord, SessionRecord), SignalProtocolError> { + let mut csprng = OsRng; + let alice_identity = IdentityKeyPair::generate(&mut csprng); + let bob_identity = IdentityKeyPair::generate(&mut csprng); + + let alice_base_key = KeyPair::generate(&mut csprng); + + let bob_base_key = KeyPair::generate(&mut csprng); + let bob_ephemeral_key = bob_base_key; + + let alice_params = AliceSignalProtocolParameters::new( + alice_identity, + alice_base_key, + *bob_identity.identity_key(), + bob_base_key.public_key, + None, + bob_ephemeral_key.public_key, + ); + + let alice_session = initialize_alice_session_record(&alice_params, &mut csprng)?; + + let bob_params = BobSignalProtocolParameters::new( + bob_identity, + bob_base_key, + None, + bob_ephemeral_key, + *alice_identity.identity_key(), + alice_base_key.public_key, + ); + + let bob_session = initialize_bob_session_record(&bob_params)?; + + Ok((alice_session, bob_session)) +} diff --git a/net/gurk-rs/files/vendor/libsignal-service-hyper/.cargo-checksum.json b/net/gurk-rs/files/vendor/libsignal-service-hyper/.cargo-checksum.json new file mode 100644 index 0000000..3310ee3 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service-hyper/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"5feadd3cbe4c14a449d5060aa6d4b043f891a849cd22329f706b5d88ac296ef1","examples/registering.rs":"c29a6e4b95e54c35e976e66ec330e843c7573298b96c9789d6d0e9cc8ac0bfdd","src/lib.rs":"af88f1fc949c629d526ad9a87d93f4d5cd8b171b2a3002ec786842fae83776f6","src/provisioning.rs":"6508541f4a9c85047f62648cd09c4e50bbbb82c38c12482096fb6ab729d172a6","src/push_service.rs":"485631af21f7d95ba06854ce93b8131189cdc600e076c8d7c1655501aca823d5","src/websocket.rs":"5c36db52518398b309457c06b477650a9f1066281af7048615f086787ae7ff9b"},"package":null} \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/libsignal-service-hyper/Cargo.toml b/net/gurk-rs/files/vendor/libsignal-service-hyper/Cargo.toml new file mode 100644 index 0000000..044c961 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service-hyper/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "libsignal-service-hyper" +version = "0.1.0" +authors = ["Gabriel Féron "] +edition = "2018" + +[dependencies] +libsignal-service = { path = "../libsignal-service" } + +async-trait = "0.1" +base64 = "0.13" +bytes = "1.0" +futures = "0.3" +log = "0.4" +mpart-async = "0.5" +serde = "1.0" +serde_json = "1.0" +thiserror = "1.0" +url = "2.1" + +hyper = { version = "0.14", features = [ "client", "stream" ] } +hyper-rustls = "0.22" +hyper-timeout = "0.4" +headers = "0.3" + +# for websocket support +async-tungstenite = { version = "0.15", features = [ "tokio-rustls-native-certs" ] } + +tokio = { version = "1.0", features = [ "macros" ] } +tokio-rustls = "0.22" + +[dev-dependencies] +env_logger = "0.9" +image = { version = "0.23", default-features = false, features = [ "png" ] } +opener = "0.5" +qrcode = "0.12" +rand = "0.7" +structopt = "0.3" +tokio = { version = "1.0", features = [ "rt-multi-thread" ]} + +[features] +unsend-futures = ["libsignal-service/unsend-futures"] diff --git a/net/gurk-rs/files/vendor/libsignal-service-hyper/examples/registering.rs b/net/gurk-rs/files/vendor/libsignal-service-hyper/examples/registering.rs new file mode 100644 index 0000000..de498cc --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service-hyper/examples/registering.rs @@ -0,0 +1,138 @@ +use std::str::FromStr; + +use libsignal_service::configuration::{ServiceCredentials, SignalServers}; +use libsignal_service::prelude::phonenumber::PhoneNumber; +use libsignal_service::provisioning::{ + generate_registration_id, ConfirmCodeMessage, ConfirmCodeResponse, + ProvisioningManager, VerificationCodeResponse, +}; +use libsignal_service::push_service::{PushService, ServiceError}; +use libsignal_service::USER_AGENT; + +use libsignal_service_hyper::prelude::HyperPushService; + +use rand::RngCore; + +#[tokio::main] +async fn main() { + let phonenumber = let_user_enter_phone_number(); + let password = let_user_enter_password(); + let use_voice = does_user_want_voice_confirmation(); + let captcha = let_user_solve_captcha(); + + let mut push_service = + create_push_service(phonenumber.clone(), password.clone()); + let mut manager = + ProvisioningManager::new(&mut push_service, phonenumber, password); + + println!("Sending registration request..."); + + let registration_result = register_user(&mut manager, captcha, use_voice) + .await + .expect("Sending registration request failed."); + + match registration_result { + VerificationCodeResponse::Issued => { + println!("Registration request was sent"); + }, + VerificationCodeResponse::CaptchaRequired => { + println!("Captcha was wrong or not provided."); + // Here you would go back to entering the Captcha + }, + } + + let confirmation_code = let_user_enter_confirmation_code(); + + println!("Sending confirmation code..."); + + let _registration_data = + confirm_registration(&mut manager, confirmation_code) + .await + .expect("Sending confirmation code failed."); + // You would want to store the registration data + + println!("Registration completed!"); +} + +pub async fn register_user<'a, T: PushService>( + manager: &mut ProvisioningManager<'a, T>, + captcha: String, + use_voice: bool, +) -> Result { + if use_voice { + manager + .request_voice_verification_code(Some(&captcha), None) + .await + } else { + manager + .request_sms_verification_code(Some(&captcha), None) + .await + } +} + +async fn confirm_registration<'a, T: PushService>( + manager: &mut ProvisioningManager<'a, T>, + confirmation_code: u32, +) -> Result { + let registration_id = generate_registration_id(&mut rand::thread_rng()); + let signaling_key = generate_signaling_key(); + + manager + .confirm_verification_code( + confirmation_code, + ConfirmCodeMessage::new_without_unidentified_access( + signaling_key.to_vec(), + registration_id, + ), + ) + .await +} + +fn generate_signaling_key() -> [u8; 52] { + // Signaling key that decrypts the incoming Signal messages + let mut rng = rand::thread_rng(); + let mut signaling_key = [0u8; 52]; + rng.fill_bytes(&mut signaling_key); + signaling_key +} + +fn create_push_service( + phonenumber: PhoneNumber, + password: String, +) -> HyperPushService { + HyperPushService::new( + SignalServers::Staging, // You might want to switch to Production servers + Some(ServiceCredentials { + uuid: None, + phonenumber, + password: Some(password), + signaling_key: None, + device_id: None, + }), + USER_AGENT.into(), + ) +} + +// ------------------------------------ +// Here come the user interaction mocks + +fn let_user_solve_captcha() -> String { + // Here you want to let the user solve a captcha on https://signalcaptchas.org/registration/generate.html + "EnterCaptchaHere".to_string() +} + +fn let_user_enter_confirmation_code() -> u32 { + 12345 +} + +fn does_user_want_voice_confirmation() -> bool { + false +} + +fn let_user_enter_phone_number() -> PhoneNumber { + PhoneNumber::from_str("+49301234567").expect("Not a valid phone number") +} + +fn let_user_enter_password() -> String { + "EnterPasswordHere".to_string() +} diff --git a/net/gurk-rs/files/vendor/libsignal-service-hyper/src/lib.rs b/net/gurk-rs/files/vendor/libsignal-service-hyper/src/lib.rs new file mode 100644 index 0000000..d91a8aa --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service-hyper/src/lib.rs @@ -0,0 +1,8 @@ +#![recursion_limit = "256"] + +pub mod push_service; +pub mod websocket; + +pub mod prelude { + pub use crate::push_service::*; +} diff --git a/net/gurk-rs/files/vendor/libsignal-service-hyper/src/provisioning.rs b/net/gurk-rs/files/vendor/libsignal-service-hyper/src/provisioning.rs new file mode 100644 index 0000000..97b9cb5 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service-hyper/src/provisioning.rs @@ -0,0 +1,150 @@ +use futures::{channel::mpsc::Sender, pin_mut, SinkExt, StreamExt}; +use url::Url; + +use crate::push_service::AwcPushService; +use libsignal_protocol::{ + generate_registration_id, + keys::{PrivateKey, PublicKey}, + Context, +}; +use libsignal_service::{ + configuration::ServiceConfiguration, + messagepipe::Credentials, + prelude::PushService, + provisioning::{ProvisioningError, ProvisioningPipe, ProvisioningStep}, + push_service::{ConfirmDeviceMessage, DeviceId}, + USER_AGENT, +}; + +#[derive(Debug)] +pub enum SecondaryDeviceProvisioning { + Url(Url), + NewDeviceRegistration { + phone_number: String, + device_id: DeviceId, + registration_id: u32, + uuid: String, + private_key: PrivateKey, + public_key: PublicKey, + profile_key: Vec, + }, +} + +pub async fn provision_secondary_device( + ctx: &Context, + service_configuration: &ServiceConfiguration, + signaling_key: &[u8; 52], + password: &str, + device_name: &str, + mut tx: Sender, +) -> Result<(), ProvisioningError> { + assert_eq!( + password.len(), + 24, + "the password needs to be a 24 characters ASCII string" + ); + + let mut push_service = + AwcPushService::new(service_configuration.clone(), None, USER_AGENT); + + let (ws, stream) = + push_service.ws("/v1/websocket/provisioning/", None).await?; + + let registration_id = generate_registration_id(&ctx, 0)?; + + let provisioning_pipe = ProvisioningPipe::from_socket(ws, stream, &ctx)?; + let provision_stream = provisioning_pipe.stream(); + pin_mut!(provision_stream); + while let Some(step) = provision_stream.next().await { + match step { + Ok(ProvisioningStep::Url(url)) => { + tx.send(SecondaryDeviceProvisioning::Url(url)) + .await + .expect("failed to send provisioning Url in channel"); + } + Ok(ProvisioningStep::Message(message)) => { + let uuid = + message.uuid.ok_or(ProvisioningError::InvalidData { + reason: "missing client UUID".into(), + })?; + + let public_key = PublicKey::decode_point( + &ctx, + &message.identity_key_public.ok_or( + ProvisioningError::InvalidData { + reason: "missing public key".into(), + }, + )?, + )?; + + let private_key = PrivateKey::decode_point( + &ctx, + &message.identity_key_private.ok_or( + ProvisioningError::InvalidData { + reason: "missing public key".into(), + }, + )?, + )?; + + let profile_key = message.profile_key.ok_or( + ProvisioningError::InvalidData { + reason: "missing profile key".into(), + }, + )?; + + let phone_number = + message.number.ok_or(ProvisioningError::InvalidData { + reason: "missing phone number".into(), + })?; + + // we need to authenticate with the phone number + // to confirm the new device + let mut push_service = AwcPushService::new( + service_configuration.clone(), + Some(Credentials { + e164: phone_number.clone(), + uuid: None, + password: Some(password.to_string()), + signaling_key: Some(*signaling_key), + }), + USER_AGENT, + ); + + let device_id = push_service + .confirm_device( + message + .provisioning_code + .ok_or(ProvisioningError::InvalidData { + reason: "no provisioning confirmation code" + .into(), + })? + .parse() + .unwrap(), + ConfirmDeviceMessage { + signaling_key: signaling_key.to_vec(), + supports_sms: false, + fetches_messages: true, + registration_id, + name: device_name.to_string(), + }, + ) + .await?; + + tx.send(SecondaryDeviceProvisioning::NewDeviceRegistration { + phone_number, + device_id, + registration_id, + uuid, + private_key, + public_key, + profile_key, + }) + .await + .expect("failed to send provisioning message in rx channel"); + } + Err(e) => return Err(e.into()), + } + } + + Ok(()) +} diff --git a/net/gurk-rs/files/vendor/libsignal-service-hyper/src/push_service.rs b/net/gurk-rs/files/vendor/libsignal-service-hyper/src/push_service.rs new file mode 100644 index 0000000..7bdb12b --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service-hyper/src/push_service.rs @@ -0,0 +1,493 @@ +use std::{io::Read, time::Duration}; + +use bytes::{Buf, Bytes}; +use futures::{FutureExt, StreamExt, TryStreamExt}; +use headers::{Authorization, HeaderMapExt}; +use hyper::{ + client::HttpConnector, + header::{CONTENT_LENGTH, CONTENT_TYPE, USER_AGENT}, + Body, Client, Method, Request, Response, StatusCode, +}; +use hyper_rustls::HttpsConnector; +use hyper_timeout::TimeoutConnector; +use libsignal_service::{ + configuration::*, messagepipe::WebSocketService, prelude::ProtobufMessage, + push_service::*, MaybeSend, +}; +use serde::{Deserialize, Serialize}; +use tokio_rustls::rustls; + +use crate::websocket::TungsteniteWebSocket; + +#[derive(Clone)] +pub struct HyperPushService { + cfg: ServiceConfiguration, + user_agent: String, + credentials: Option, + client: Client>>, +} + +#[derive(Debug)] +struct RequestBody { + contents: Vec, + content_type: String, +} + +impl HyperPushService { + pub fn new( + cfg: impl Into, + credentials: Option, + user_agent: String, + ) -> Self { + let cfg = cfg.into(); + let tls_config = Self::tls_config(&cfg); + + let mut http = HttpConnector::new(); + http.enforce_http(false); + let https = HttpsConnector::from((http, tls_config)); + + // as in Signal-Android + let mut timeout_connector = TimeoutConnector::new(https); + timeout_connector.set_connect_timeout(Some(Duration::from_secs(10))); + timeout_connector.set_read_timeout(Some(Duration::from_secs(65))); + timeout_connector.set_write_timeout(Some(Duration::from_secs(65))); + + let client: Client<_, hyper::Body> = + Client::builder().build(timeout_connector); + + Self { + cfg, + credentials: credentials.and_then(|c| c.authorization()), + client, + user_agent, + } + } + + fn tls_config(cfg: &ServiceConfiguration) -> rustls::ClientConfig { + // This will fail to compile against rustls 0.20, see service-actix push_service get_client + let mut tls_config = rustls::ClientConfig::new(); + tls_config.alpn_protocols = vec![b"http/1.1".to_vec()]; + tls_config + .root_store + .add_pem_file(&mut std::io::Cursor::new( + cfg.certificate_authority.clone(), + )) + .expect("invalid TLS certificate authority"); + tls_config + } + + async fn request( + &self, + method: Method, + endpoint: Endpoint, + path: impl AsRef, + credentials_override: HttpAuthOverride, + body: Option, + ) -> Result, ServiceError> { + let url = self.cfg.base_url(endpoint).join(path.as_ref())?; + log::debug!("HTTP request {} {}", method, url); + let mut builder = Request::builder() + .method(method) + .uri(url.as_str()) + .header(USER_AGENT, &self.user_agent); + + match credentials_override { + HttpAuthOverride::NoOverride => { + if let Some(HttpAuth { username, password }) = + self.credentials.as_ref() + { + builder + .headers_mut() + .unwrap() + .typed_insert(Authorization::basic(username, password)); + } + }, + HttpAuthOverride::Identified(HttpAuth { username, password }) => { + builder + .headers_mut() + .unwrap() + .typed_insert(Authorization::basic(&username, &password)); + }, + HttpAuthOverride::Unidentified => (), + }; + + let request = if let Some(RequestBody { + contents, + content_type, + }) = body + { + builder + .header(CONTENT_LENGTH, contents.len() as u64) + .header(CONTENT_TYPE, content_type) + .body(Body::from(contents)) + .unwrap() + } else { + builder.body(Body::empty()).unwrap() + }; + + let mut response = self.client.request(request).await.map_err(|e| { + ServiceError::SendError { + reason: e.to_string(), + } + })?; + + match response.status() { + StatusCode::OK => Ok(response), + StatusCode::NO_CONTENT => Ok(response), + StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN => { + Err(ServiceError::Unauthorized) + }, + StatusCode::PAYLOAD_TOO_LARGE => { + // This is 413 and means rate limit exceeded for Signal. + Err(ServiceError::RateLimitExceeded) + }, + StatusCode::CONFLICT => { + let mismatched_devices = + Self::json(&mut response).await.map_err(|e| { + log::error!( + "Failed to decode HTTP 409 response: {}", + e + ); + ServiceError::UnhandledResponseCode { + http_code: StatusCode::CONFLICT.as_u16(), + } + })?; + Err(ServiceError::MismatchedDevicesException( + mismatched_devices, + )) + }, + StatusCode::GONE => { + let stale_devices = + Self::json(&mut response).await.map_err(|e| { + log::error!( + "Failed to decode HTTP 410 response: {}", + e + ); + ServiceError::UnhandledResponseCode { + http_code: StatusCode::GONE.as_u16(), + } + })?; + Err(ServiceError::StaleDevices(stale_devices)) + }, + // XXX: fill in rest from PushServiceSocket + code => { + log::trace!( + "Unhandled response with body: {}", + Self::text(&mut response).await? + ); + Err(ServiceError::UnhandledResponseCode { + http_code: code.as_u16(), + }) + }, + } + } + + async fn json(response: &mut Response) -> Result + where + for<'de> T: Deserialize<'de>, + { + let body = hyper::body::aggregate(response).await.map_err(|e| { + ServiceError::ResponseError { + reason: format!( + "failed to aggregate HTTP response body: {}", + e + ), + } + })?; + + serde_json::from_reader(body.reader()).map_err(|e| { + ServiceError::JsonDecodeError { + reason: e.to_string(), + } + }) + } + + async fn protobuf( + response: &mut Response, + ) -> Result + where + M: ProtobufMessage + Default, + { + let body = hyper::body::aggregate(response).await.map_err(|e| { + ServiceError::ResponseError { + reason: format!( + "failed to aggregate HTTP response body: {}", + e + ), + } + })?; + + M::decode(body).map_err(ServiceError::ProtobufDecodeError) + } + + async fn text( + response: &mut Response, + ) -> Result { + let body = hyper::body::aggregate(response).await.map_err(|e| { + ServiceError::ResponseError { + reason: format!( + "failed to aggregate HTTP response body: {}", + e + ), + } + })?; + let mut text = String::new(); + body.reader().read_to_string(&mut text).map_err(|e| { + ServiceError::ResponseError { + reason: format!("failed to read HTTP response body: {}", e), + } + })?; + Ok(text) + } +} + +#[cfg_attr(feature = "unsend-futures", async_trait::async_trait(?Send))] +#[cfg_attr(not(feature = "unsend-futures"), async_trait::async_trait)] +impl PushService for HyperPushService { + // This is in principle known at compile time, but long to write out. + type ByteStream = Box; + type WebSocket = TungsteniteWebSocket; + + async fn get_json( + &mut self, + service: Endpoint, + path: &str, + credentials_override: HttpAuthOverride, + ) -> Result + where + for<'de> T: Deserialize<'de>, + { + let mut response = self + .request(Method::GET, service, path, credentials_override, None) + .await?; + + Self::json(&mut response).await + } + + async fn delete_json( + &mut self, + service: Endpoint, + path: &str, + ) -> Result + where + for<'de> T: Deserialize<'de>, + { + let mut response = self + .request( + Method::DELETE, + service, + path, + HttpAuthOverride::NoOverride, + None, + ) + .await?; + + Self::json(&mut response).await + } + + async fn put_json( + &mut self, + service: Endpoint, + path: &str, + credentials_override: HttpAuthOverride, + value: S, + ) -> Result + where + for<'de> D: Deserialize<'de>, + S: MaybeSend + Serialize, + { + let json = serde_json::to_vec(&value).map_err(|e| { + ServiceError::JsonDecodeError { + reason: e.to_string(), + } + })?; + + let mut response = self + .request( + Method::PUT, + service, + path, + credentials_override, + Some(RequestBody { + contents: json, + content_type: "application/json".into(), + }), + ) + .await?; + + Self::json(&mut response).await + } + + async fn get_protobuf( + &mut self, + service: Endpoint, + path: &str, + credentials_override: HttpAuthOverride, + ) -> Result + where + T: Default + libsignal_service::prelude::ProtobufMessage, + { + let mut response = self + .request(Method::GET, service, path, credentials_override, None) + .await?; + + Self::protobuf(&mut response).await + } + + async fn put_protobuf( + &mut self, + service: Endpoint, + path: &str, + value: S, + ) -> Result + where + D: Default + libsignal_service::prelude::ProtobufMessage, + S: Sized + libsignal_service::prelude::ProtobufMessage, + { + let protobuf = value.encode_to_vec(); + + let mut response = self + .request( + Method::PUT, + service, + path, + HttpAuthOverride::NoOverride, + Some(RequestBody { + contents: protobuf, + content_type: "application/x-protobuf".into(), + }), + ) + .await?; + + Self::protobuf(&mut response).await + } + + async fn get_from_cdn( + &mut self, + cdn_id: u32, + path: &str, + ) -> Result { + let response = self + .request( + Method::GET, + Endpoint::Cdn(cdn_id), + path, + HttpAuthOverride::Unidentified, // CDN requests are always without authentication + None, + ) + .await?; + + Ok(Box::new( + response + .into_body() + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)) + .into_async_read(), + )) + } + + async fn post_to_cdn0<'s, C: std::io::Read + Send + 's>( + &mut self, + path: &str, + value: &[(&str, &str)], + file: Option<(&str, &'s mut C)>, + ) -> Result<(), ServiceError> { + let mut form = mpart_async::client::MultipartRequest::default(); + + // mpart-async has a peculiar ordering of the form items, + // and Amazon S3 expects them in a very specific order (i.e., the file contents should + // go last. + // + // mpart-async uses a VecDeque internally for ordering the fields in the order given. + // + // https://github.com/cetra3/mpart-async/issues/16 + + for &(k, v) in value { + form.add_field(k, v); + } + + if let Some((filename, file)) = file { + // XXX Actix doesn't cope with none-'static lifetimes + // https://docs.rs/actix-web/3.2.0/actix_web/body/enum.Body.html + let mut buf = Vec::new(); + file.read_to_end(&mut buf) + .expect("infallible Read instance"); + form.add_stream( + "file", + filename, + "application/octet-stream", + futures::future::ok::<_, ()>(Bytes::from(buf)).into_stream(), + ); + } + + let content_type = + format!("multipart/form-data; boundary={}", form.get_boundary()); + + // XXX Amazon S3 needs the Content-Length, but we don't know it without depleting the whole + // stream. Sadly, Content-Length != contents.len(), but should include the whole form. + let mut body_contents = vec![]; + while let Some(b) = form.next().await { + // Unwrap, because no error type was used above + body_contents.extend(b.unwrap()); + } + log::trace!( + "Sending PUT with Content-Type={} and length {}", + content_type, + body_contents.len() + ); + + let response = self + .request( + Method::POST, + Endpoint::Cdn(0), + path, + HttpAuthOverride::NoOverride, + Some(RequestBody { + contents: body_contents, + content_type, + }), + ) + .await?; + + log::debug!("AwcPushService::PUT response: {:?}", response); + + Ok(()) + } + + async fn ws( + &mut self, + path: &str, + credentials: Option, + ) -> Result< + ( + Self::WebSocket, + ::Stream, + ), + ServiceError, + > { + Ok(TungsteniteWebSocket::with_tls_config( + Self::tls_config(&self.cfg), + self.cfg.base_url(Endpoint::Service), + path, + credentials.as_ref(), + ) + .await?) + } +} + +#[cfg(test)] +mod tests { + use libsignal_service::configuration::SignalServers; + + #[test] + fn create_clients() { + let configs = &[SignalServers::Staging, SignalServers::Production]; + + for cfg in configs { + let _ = super::HyperPushService::new( + cfg, + None, + "libsignal-service test".to_string(), + ); + } + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service-hyper/src/websocket.rs b/net/gurk-rs/files/vendor/libsignal-service-hyper/src/websocket.rs new file mode 100644 index 0000000..f72d27a --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service-hyper/src/websocket.rs @@ -0,0 +1,221 @@ +use std::sync::Arc; + +use async_tungstenite::{ + tokio::connect_async_with_tls_connector, + tungstenite::{Error as TungsteniteError, Message}, +}; +use bytes::Bytes; +use futures::{channel::mpsc::*, prelude::*}; +use hyper::StatusCode; +use tokio::time::Instant; +use tokio_rustls::rustls; +use url::Url; + +use libsignal_service::{ + configuration::ServiceCredentials, + messagepipe::*, + push_service::{self, ServiceError}, + MaybeSend, +}; + +// This weird one-time trait is required because MaybeSend, unlike Send, is not +// an auto trait. Only auto traits can be used as additional traits in a trait object. +trait MaybeSendSink: Sink + MaybeSend {} +impl MaybeSendSink for T where + T: Sink + MaybeSend +{ +} + +pub struct TungsteniteWebSocket { + socket_sink: Box, +} + +#[derive(thiserror::Error, Debug)] +pub enum TungsteniteWebSocketError { + #[error("error while connecting to websocket: {0}")] + ConnectionError(#[from] TungsteniteError), +} + +impl From for ServiceError { + fn from(e: TungsteniteWebSocketError) -> Self { + match e { + TungsteniteWebSocketError::ConnectionError( + TungsteniteError::Http(response), + ) => match response.status() { + StatusCode::FORBIDDEN => ServiceError::Unauthorized, + s => ServiceError::WsError { + reason: format!("HTTP status {}", s), + }, + }, + e => ServiceError::WsError { + reason: e.to_string(), + }, + } + } +} + +// impl From for ServiceError { +// fn from(e: AwcWebSocketError) -> ServiceError { +// match e { +// AwcWebSocketError::ConnectionError(e) => match e { +// WsClientError::InvalidResponseStatus(s) => match s { +// StatusCode::FORBIDDEN => ServiceError::Unauthorized, +// s => ServiceError::WsError { +// reason: format!("HTTP status {}", s), +// }, +// }, +// e => ServiceError::WsError { +// reason: e.to_string(), +// }, +// }, +// } +// } +// } + +// impl From for AwcWebSocketError { +// fn from(e: WsProtocolError) -> AwcWebSocketError { +// todo!("error conversion {:?}", e) +// // return Some(Err(ServiceError::WsError { +// // reason: e.to_string(), +// // })); +// } +// } + +// Process the WebSocket, until it times out. +async fn process( + socket_stream: S, + mut incoming_sink: Sender, +) -> Result<(), TungsteniteWebSocketError> +where + S: Unpin, + S: Stream>, +{ + let mut socket_stream = socket_stream.fuse(); + + let mut ka_interval = tokio::time::interval_at( + Instant::now(), + push_service::KEEPALIVE_TIMEOUT_SECONDS, + ); + + loop { + tokio::select! { + _ = ka_interval.tick() => { + log::trace!("Triggering keep-alive"); + if let Err(e) = incoming_sink.send(WebSocketStreamItem::KeepAliveRequest).await { + log::info!("Websocket sink has closed: {:?}.", e); + break; + }; + }, + frame = socket_stream.next() => { + let frame = if let Some(frame) = frame { + frame + } else { + log::info!("process: Socket stream ended"); + break; + }; + + let frame = match frame? { + Message::Binary(s) => s, + Message::Ping(msg) => { + log::warn!("Received Ping({:?})", msg); + + continue; + }, + Message::Pong(msg) => { + log::trace!("Received Pong({:?})", msg); + + continue; + }, + Message::Text(frame) => { + log::warn!("Message::Text {:?}", frame); + + // this is a protocol violation, maybe break; is better? + continue; + }, + + Message::Close(c) => { + log::warn!("Websocket closing: {:?}", c); + + break; + }, + }; + + // Match SendError + if let Err(e) = incoming_sink.send(WebSocketStreamItem::Message(Bytes::from(frame))).await { + log::info!("Websocket sink has closed: {:?}.", e); + break; + } + }, + } + } + Ok(()) +} + +impl TungsteniteWebSocket { + pub(crate) async fn with_tls_config( + tls_config: rustls::ClientConfig, + base_url: impl std::borrow::Borrow, + path: &str, + credentials: Option<&ServiceCredentials>, + ) -> Result< + (Self, ::Stream), + TungsteniteWebSocketError, + > { + let mut url = base_url.borrow().join(path).expect("valid url"); + url.set_scheme("wss").expect("valid https base url"); + + let tls_connector = + tokio_rustls::TlsConnector::from(Arc::new(tls_config)); + + if let Some(credentials) = credentials { + url.query_pairs_mut() + .append_pair("login", &credentials.login()) + .append_pair( + "password", + credentials.password.as_ref().expect("a password"), + ); + } + + log::trace!("Will start websocket at {:?}", url); + + let (socket_stream, response) = + connect_async_with_tls_connector(url, Some(tls_connector)).await?; + + log::debug!("WebSocket connected: {:?}", response); + + let (incoming_sink, incoming_stream) = channel(5); + + let (socket_sink, socket_stream) = socket_stream.split(); + let processing_task = process(socket_stream, incoming_sink); + + // When the processing_task stops, the consuming stream and sink also + // terminate. + tokio::spawn(processing_task.map(|v| match v { + Ok(()) => (), + Err(e) => { + log::warn!("Processing task terminated with error: {:?}", e) + }, + })); + + Ok(( + Self { + socket_sink: Box::new(socket_sink), + }, + incoming_stream, + )) + } +} + +#[cfg_attr(feature = "unsend-futures", async_trait::async_trait(?Send))] +#[cfg_attr(not(feature = "unsend-futures"), async_trait::async_trait)] +impl WebSocketService for TungsteniteWebSocket { + type Stream = Receiver; + + async fn send_message(&mut self, msg: Bytes) -> Result<(), ServiceError> { + self.socket_sink + .send(Message::Binary(msg.to_vec())) + .await + .map_err(TungsteniteWebSocketError::from)?; + Ok(()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/.cargo-checksum.json b/net/gurk-rs/files/vendor/libsignal-service/.cargo-checksum.json new file mode 100644 index 0000000..23f6e06 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"7990658c5f339ecae207340ad4e77e4b1adb3dbd5d5944d557383542fbbe4119","build.rs":"c9720a17e019fb61aa66aee6bb2d10785ddc4f4773989d6be12f6b08964b449c","protobuf/DecryptedGroups.proto":"6441ebc3ce3e4ececbd312efcf1784ebd167b39677c21ad08fc33b3199ce53fe","protobuf/Groups.proto":"45f93f817634d0baa10f3228a7a07e234be2e85eb006ca0f2e639ec5118fc3d7","protobuf/Provisioning.proto":"632588c1e71774292a58029e38f2c482daa57621908efe902093d7214756a351","protobuf/SignalService.proto":"f30e9b57990b11bbd5b6efdbb4d0e2ce41c6eb60a915ac02d8ed43eeaefe625e","protobuf/StickerResources.proto":"f1f9b5d815eb703129986e95175cf3a61d5b37c8de9154af646081fa5774ad1d","protobuf/UnidentifiedDelivery.proto":"246c66792a5d68b8d10f13f5e6c30901ca7f2e766d9e2f3fdde37f5df75f0f5d","protobuf/WebSocketResources.proto":"881b0e22f5a66642975b4d41dc401c6a4d63816e23c8c45c9eec168c21fe2ab8","src/account_manager.rs":"5eacdfbeac7cb52dd32eeaf26a4eb4396bf4fdba4b40a2a95c19b6889d854fd3","src/attachment_cipher.rs":"dcc323bcdbee10fd6c9fc7d3cee6bcc7e13690625d2e2495f1656008ea6fe1dd","src/cipher.rs":"5f2b92e97cb8eb96a0b4e66494d52ea2db2eb63fbb8e36f990bca65f54285062","src/configuration.rs":"05478f7fef7becd63e3d9a4d1f8b58ec5785a0c962cfd2fcf3b2d68ef21e3cc2","src/content.rs":"651ebd040f3d93ed845e5c2d7e788e85e62880fc6c7964424cb435af5dea7d27","src/digeststream.rs":"1c7b943342f30e1fc5b3fb377cd49e0252e4abc2cef7b462968a311db1a3cbb0","src/envelope.rs":"df47eb9dc9e3ea6c2e6e74f0f7b6d11f2f8883fbffcc1aa5f8050e468fc5ec13","src/groups_v2/manager.rs":"bc3fd73d0498a6e3ca8d4b538386df6a3966c9a27ab216f294b5b97f1e936b6f","src/groups_v2/mod.rs":"0979622b08a6cd35edd67a54b4c133ec11f36b6b174429c9dc8d4f5e8336335d","src/groups_v2/operations.rs":"4cc3c587c4b107a5e647e38f6033672851275126780d2401cd5d92271594eed5","src/groups_v2/utils.rs":"5a3dba2c3b8d2db9ce59fff6fd08b031570b3ef3fedcd92dcfd8782e2c124145","src/kat.bin.rs":"57ae2884824a4c20406bbf04572e02321431b21e33341448a863ac6ef90b61d9","src/lib.rs":"44defcec01445f462a45206889fa042c87148d6944bd9acbc29cff335d095eef","src/messagepipe.rs":"af2d316b15f8b6401ed75ad6962a31dcf3ef508d80833f7ba05a775b9b037c19","src/models.rs":"0f52fe9ee01706e7fea6cb21c150e049f8fd6802d64cecd751795c9d7d22fc03","src/pre_keys.rs":"882b56b873f0cbb47d765a6c7b09fff187aa451abc72787f7443bf4316bea5bc","src/profile_cipher.rs":"51d089128457df028b3f8860da4951429dc381450f9a6a742b3a88eab317e581","src/profile_name.rs":"3b3672e98b07644975fc34afe173e235c0fb595261a82da0c51efeb8c553bbd0","src/proto.rs":"e5c977af587b11226d5803678392b89602a424e24365f1855770a0907a10157a","src/provisioning/cipher.rs":"5dfc259426b247d2eec112326873fdf82c4a52f70e35bdc5594d96501b55cfb5","src/provisioning/manager.rs":"6450ac900cb187efe1335c7556e9dfafa8955e56d8208d0fa6abf58a38ab563b","src/provisioning/mod.rs":"4c89449c578e7f9d64fb877a9357e6837ad592ff2c4b99e2be3c5ec099bb23a6","src/provisioning/pipe.rs":"5f68e9d489468b01348f98a490617436c5e0706d9a74ee0af1e8d9a5a8904cc4","src/push_service.rs":"761bc4e1811b99cd166fe3d793f57dbde97850dd2abc7d26180f5ffb3c3a339f","src/receiver.rs":"513984f0fcf3ca1eb2fe1f5ac4edc325a0a665a26a1919df5b8365da8b77ab8b","src/sealed_session_cipher.rs":"4f9628cef6d10f33faf3a0d20a17ef9e6400f224a244ff5f6f0b9c318d661ca5","src/sender.rs":"6281dd9d81e46785a372b18c3265c05d68d298c6003d408a03f6ce75e51cfc4d","src/service_address.rs":"c39952513f50d869dc4cbc3541261e185e1524419760aab2688da5bbd62fd1c9","src/session_store.rs":"d6ff85eae98ed25ae36fa7d4e1ef3521cfbf952b273737bcdc492b8c72ea8a63","src/utils.rs":"d15bc4fd4e77a86963396b3d3e2f6b92cde5b35e3024f0a53b9487fe0f094afd"},"package":null} \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/libsignal-service/Cargo.toml b/net/gurk-rs/files/vendor/libsignal-service/Cargo.toml new file mode 100644 index 0000000..c8f7451 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "libsignal-service" +version = "0.1.0" +authors = ["Michael Bryan ", "Shady Khalifa "] +edition = "2018" +license = "GPLv3" +readme = "../README.md" + +[dependencies] +libsignal-protocol = { git = "https://github.com/signalapp/libsignal-client", tag="v0.11.0" } +zkgroup = { git = "https://github.com/signalapp/zkgroup", tag = "v0.7.3" } +async-trait = "0.1" +url = { version = "2.1", features = ["serde"] } +base64 = "0.13" +bytes = "1" +futures = "0.3" +pin-project = "1.0" +thiserror = "1.0" +serde = {version = "1.0", features=["derive"]} +prost = "0.9" +http = "0.2" +chrono = { version = "0.4", features = ["serde"] } +log = "0.4" +bincode = "1.3" + +sha2 = "0.9" +hmac = "0.11" +hex = "0.4" +aes = { version = "0.7", features = ["ctr"] } +aes-gcm = "0.9" +block-modes = "0.8" +rand = "0.7" + +uuid = { version = "0.8", features = [ "serde" ] } +phonenumber = "0.3" +hkdf = "0.11" + +[build-dependencies] +prost-build = "0.9" + +[dev-dependencies] +anyhow = "1.0" +tokio = { version = "1.0", features = [ "rt", "macros" ] } + +rustls = "0.20" + +[features] +prefer-e164 = [] +unsend-futures = [] diff --git a/net/gurk-rs/files/vendor/libsignal-service/build.rs b/net/gurk-rs/files/vendor/libsignal-service/build.rs new file mode 100644 index 0000000..a72b723 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/build.rs @@ -0,0 +1,32 @@ +use std::path::Path; + +fn main() { + let protobuf = Path::new("protobuf").to_owned(); + + // Build script does not automagically rerun when a new protobuf file is added. + // Directories are checked against mtime, which is platform specific + println!("cargo:rerun-if-changed=protobuf"); + // Adding src/proto.rs means an extra `include!` will trigger a rerun. This is on best-effort + // basis. + println!("cargo:rerun-if-changed=src/proto.rs"); + + let input: Vec<_> = protobuf + .read_dir() + .expect("protobuf directory") + .filter_map(|entry| { + let entry = entry.expect("readable protobuf directory"); + let path = entry.path(); + if Some("proto") + == path.extension().and_then(std::ffi::OsStr::to_str) + { + assert!(path.is_file()); + println!("cargo:rerun-if-changed={}", path.to_str().unwrap()); + Some(path) + } else { + None + } + }) + .collect(); + + prost_build::compile_protos(&input, &[protobuf]).unwrap(); +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/protobuf/DecryptedGroups.proto b/net/gurk-rs/files/vendor/libsignal-service/protobuf/DecryptedGroups.proto new file mode 100644 index 0000000..3aa9f4b --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/protobuf/DecryptedGroups.proto @@ -0,0 +1,109 @@ +/** + * Copyright (C) 2019 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +syntax = "proto3"; + +package signalservice; + +option java_package = "org.signal.storageservice.protos.groups.local"; +option java_multiple_files = true; + +import "Groups.proto"; + +// Decrypted version of Member +// Keep field numbers in step +message DecryptedMember { + bytes uuid = 1; + Member.Role role = 2; + bytes profileKey = 3; + uint32 joinedAtRevision = 5; +} + +message DecryptedPendingMember { + bytes uuid = 1; + Member.Role role = 2; + bytes addedByUuid = 3; + uint64 timestamp = 4; + bytes uuidCipherText = 5; +} + +message DecryptedRequestingMember { + bytes uuid = 1; + bytes profileKey = 2; + uint64 timestamp = 4; +} + +message DecryptedPendingMemberRemoval { + bytes uuid = 1; + bytes uuidCipherText = 2; +} + +message DecryptedApproveMember { + bytes uuid = 1; + Member.Role role = 2; +} + +message DecryptedModifyMemberRole { + bytes uuid = 1; + Member.Role role = 2; +} + +// Decrypted version of message Group +// Keep field numbers in step +message DecryptedGroup { + string title = 2; + string avatar = 3; + DecryptedTimer disappearingMessagesTimer = 4; + AccessControl accessControl = 5; + uint32 revision = 6; + repeated DecryptedMember members = 7; + repeated DecryptedPendingMember pendingMembers = 8; + repeated DecryptedRequestingMember requestingMembers = 9; + bytes inviteLinkPassword = 10; + string description = 11; +} + +// Decrypted version of message GroupChange.Actions +// Keep field numbers in step +message DecryptedGroupChange { + bytes editor = 1; + uint32 revision = 2; + repeated DecryptedMember newMembers = 3; + repeated bytes deleteMembers = 4; + repeated DecryptedModifyMemberRole modifyMemberRoles = 5; + repeated DecryptedMember modifiedProfileKeys = 6; + repeated DecryptedPendingMember newPendingMembers = 7; + repeated DecryptedPendingMemberRemoval deletePendingMembers = 8; + repeated DecryptedMember promotePendingMembers = 9; + DecryptedString newTitle = 10; + DecryptedString newAvatar = 11; + DecryptedTimer newTimer = 12; + AccessControl.AccessRequired newAttributeAccess = 13; + AccessControl.AccessRequired newMemberAccess = 14; + AccessControl.AccessRequired newInviteLinkAccess = 15; + repeated DecryptedRequestingMember newRequestingMembers = 16; + repeated bytes deleteRequestingMembers = 17; + repeated DecryptedApproveMember promoteRequestingMembers = 18; + bytes newInviteLinkPassword = 19; + DecryptedString newDescription = 20; +} + +message DecryptedString { + string value = 1; +} + +message DecryptedTimer { + uint32 duration = 1; +} + +message DecryptedGroupJoinInfo { + string title = 2; + string avatar = 3; + uint32 memberCount = 4; + AccessControl.AccessRequired addFromInviteLink = 5; + uint32 revision = 6; + bool pendingAdminApproval = 7; + string description = 8; +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/protobuf/Groups.proto b/net/gurk-rs/files/vendor/libsignal-service/protobuf/Groups.proto new file mode 100644 index 0000000..0ba85a9 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/protobuf/Groups.proto @@ -0,0 +1,226 @@ +/** + * Copyright (C) 2019 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +syntax = "proto3"; + +package signalservice; + +option java_package = "org.signal.storageservice.protos.groups"; +option java_multiple_files = true; + +message AvatarUploadAttributes { + string key = 1; + string credential = 2; + string acl = 3; + string algorithm = 4; + string date = 5; + string policy = 6; + string signature = 7; +} + +message Member { + enum Role { + UNKNOWN = 0; + DEFAULT = 1; + ADMINISTRATOR = 2; + } + + bytes userId = 1; + Role role = 2; + bytes profileKey = 3; + bytes presentation = 4; + uint32 joinedAtRevision = 5; +} + +message PendingMember { + Member member = 1; + bytes addedByUserId = 2; + uint64 timestamp = 3; +} + +message RequestingMember { + bytes userId = 1; + bytes profileKey = 2; + bytes presentation = 3; + uint64 timestamp = 4; +} + +message AccessControl { + enum AccessRequired { + UNKNOWN = 0; + ANY = 1; + MEMBER = 2; + ADMINISTRATOR = 3; + UNSATISFIABLE = 4; + } + + AccessRequired attributes = 1; + AccessRequired members = 2; + AccessRequired addFromInviteLink = 3; +} + +message Group { + bytes publicKey = 1; + bytes title = 2; + string avatar = 3; + bytes disappearingMessagesTimer = 4; + AccessControl accessControl = 5; + uint32 revision = 6; + repeated Member members = 7; + repeated PendingMember pendingMembers = 8; + repeated RequestingMember requestingMembers = 9; + bytes inviteLinkPassword = 10; + bytes description = 11; +} + +message GroupChange { + + message Actions { + + message AddMemberAction { + Member added = 1; + bool joinFromInviteLink = 2; + } + + message DeleteMemberAction { + bytes deletedUserId = 1; + } + + message ModifyMemberRoleAction { + bytes userId = 1; + Member.Role role = 2; + } + + message ModifyMemberProfileKeyAction { + bytes presentation = 1; + } + + message AddPendingMemberAction { + PendingMember added = 1; + } + + message DeletePendingMemberAction { + bytes deletedUserId = 1; + } + + message PromotePendingMemberAction { + bytes presentation = 1; + } + + message AddRequestingMemberAction { + RequestingMember added = 1; + } + + message DeleteRequestingMemberAction { + bytes deletedUserId = 1; + } + + message PromoteRequestingMemberAction { + bytes userId = 1; + Member.Role role = 2; + } + + message ModifyTitleAction { + bytes title = 1; + } + + message ModifyDescriptionAction { + bytes description = 1; + } + + message ModifyAvatarAction { + string avatar = 1; + } + + message ModifyDisappearingMessagesTimerAction { + bytes timer = 1; + } + + message ModifyAttributesAccessControlAction { + AccessControl.AccessRequired attributesAccess = 1; + } + + message ModifyMembersAccessControlAction { + AccessControl.AccessRequired membersAccess = 1; + } + + message ModifyAddFromInviteLinkAccessControlAction { + AccessControl.AccessRequired addFromInviteLinkAccess = 1; + } + + message ModifyInviteLinkPasswordAction { + bytes inviteLinkPassword = 1; + } + + bytes sourceUuid = 1; + uint32 revision = 2; + repeated AddMemberAction addMembers = 3; + repeated DeleteMemberAction deleteMembers = 4; + repeated ModifyMemberRoleAction modifyMemberRoles = 5; + repeated ModifyMemberProfileKeyAction modifyMemberProfileKeys = 6; + repeated AddPendingMemberAction addPendingMembers = 7; + repeated DeletePendingMemberAction deletePendingMembers = 8; + repeated PromotePendingMemberAction promotePendingMembers = 9; + ModifyTitleAction modifyTitle = 10; + ModifyAvatarAction modifyAvatar = 11; + ModifyDisappearingMessagesTimerAction modifyDisappearingMessagesTimer = 12; + ModifyAttributesAccessControlAction modifyAttributesAccess = 13; + ModifyMembersAccessControlAction modifyMemberAccess = 14; + ModifyAddFromInviteLinkAccessControlAction modifyAddFromInviteLinkAccess = 15; + repeated AddRequestingMemberAction addRequestingMembers = 16; + repeated DeleteRequestingMemberAction deleteRequestingMembers = 17; + repeated PromoteRequestingMemberAction promoteRequestingMembers = 18; + ModifyInviteLinkPasswordAction modifyInviteLinkPassword = 19; + ModifyDescriptionAction modifyDescription = 20; + } + + bytes actions = 1; + bytes serverSignature = 2; + uint32 changeEpoch = 3; +} + +message GroupChanges { + message GroupChangeState { + GroupChange groupChange = 1; + Group groupState = 2; + } + + repeated GroupChangeState groupChanges = 1; +} + +message GroupAttributeBlob { + oneof content { + string title = 1; + bytes avatar = 2; + uint32 disappearingMessagesDuration = 3; + string description = 4; + } +} + +message GroupInviteLink { + message GroupInviteLinkContentsV1 { + bytes groupMasterKey = 1; + bytes inviteLinkPassword = 2; + } + + oneof contents { + GroupInviteLinkContentsV1 v1Contents = 1; + } +} + +message GroupJoinInfo { + bytes publicKey = 1; + bytes title = 2; + string avatar = 3; + uint32 memberCount = 4; + AccessControl.AccessRequired addFromInviteLink = 5; + uint32 revision = 6; + bool pendingAdminApproval = 7; + bytes description = 8; +} + +message GroupExternalCredential { + string token = 1; +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/protobuf/Provisioning.proto b/net/gurk-rs/files/vendor/libsignal-service/protobuf/Provisioning.proto new file mode 100644 index 0000000..80de36a --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/protobuf/Provisioning.proto @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2014-2016 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +syntax = "proto2"; + +package signalservice; + +option java_package = "org.whispersystems.signalservice.internal.push"; +option java_outer_classname = "ProvisioningProtos"; + +message ProvisioningUuid { + optional string uuid = 1; +} + +message ProvisionEnvelope { + optional bytes publicKey = 1; + optional bytes body = 2; // Encrypted ProvisionMessage +} + +message ProvisionMessage { + optional bytes identityKeyPublic = 1; + optional bytes identityKeyPrivate = 2; + optional string number = 3; + optional string uuid = 8; + optional string provisioningCode = 4; + optional string userAgent = 5; + optional bytes profileKey = 6; + optional bool readReceipts = 7; + optional uint32 provisioningVersion = 9; +} + +enum ProvisioningVersion { + option allow_alias = true; + + INITIAL = 0; + TABLET_SUPPORT = 1; + CURRENT = 1; +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/protobuf/SignalService.proto b/net/gurk-rs/files/vendor/libsignal-service/protobuf/SignalService.proto new file mode 100644 index 0000000..e4baee4 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/protobuf/SignalService.proto @@ -0,0 +1,625 @@ +/** + * Copyright (C) 2014-2016 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +syntax = "proto2"; + +package signalservice; + +option java_package = "org.whispersystems.signalservice.internal.push"; +option java_outer_classname = "SignalServiceProtos"; + +message Envelope { + enum Type { + UNKNOWN = 0; + CIPHERTEXT = 1; + KEY_EXCHANGE = 2; + PREKEY_BUNDLE = 3; + RECEIPT = 5; + UNIDENTIFIED_SENDER = 6; + reserved 7; // SENDERKEY_MESSAGE + PLAINTEXT_CONTENT = 8; + } + + optional Type type = 1; + optional string sourceE164 = 2; + optional string sourceUuid = 11; + optional uint32 sourceDevice = 7; + optional string relay = 3; + optional uint64 timestamp = 5; + optional bytes legacyMessage = 6; // Contains an encrypted DataMessage + optional bytes content = 8; // Contains an encrypted Content + optional string serverGuid = 9; + optional uint64 serverTimestamp = 10; +} + +message Content { + optional DataMessage dataMessage = 1; + optional SyncMessage syncMessage = 2; + optional CallMessage callMessage = 3; + optional NullMessage nullMessage = 4; + optional ReceiptMessage receiptMessage = 5; + optional TypingMessage typingMessage = 6; + optional bytes senderKeyDistributionMessage = 7; + optional bytes decryptionErrorMessage = 8; +} + +message CallMessage { + message Offer { + enum Type { + OFFER_AUDIO_CALL = 0; + OFFER_VIDEO_CALL = 1; + reserved /* OFFER_NEED_PERMISSION */ 2; // removed + } + + optional uint64 id = 1; + // Legacy/deprecated; replaced by 'opaque' + optional string sdp = 2; + optional Type type = 3; + optional bytes opaque = 4; + } + + message Answer { + optional uint64 id = 1; + // Legacy/deprecated; replaced by 'opaque' + optional string sdp = 2; + optional bytes opaque = 3; + } + + message IceUpdate { + optional uint64 id = 1; + // Legacy/deprecated; remove when old clients are gone. + optional string mid = 2; + // Legacy/deprecated; remove when old clients are gone. + optional uint32 line = 3; + // Legacy/deprecated; replaced by 'opaque' + optional string sdp = 4; + optional bytes opaque = 5; + } + + message Busy { + optional uint64 id = 1; + } + + message Hangup { + enum Type { + HANGUP_NORMAL = 0; + HANGUP_ACCEPTED = 1; + HANGUP_DECLINED = 2; + HANGUP_BUSY = 3; + HANGUP_NEED_PERMISSION = 4; + } + + optional uint64 id = 1; + optional Type type = 2; + optional uint32 deviceId = 3; + } + + message Opaque { + optional bytes data = 1; + } + + optional Offer offer = 1; + optional Answer answer = 2; + repeated IceUpdate iceUpdate = 3; + optional Hangup legacyHangup = 4; + optional Busy busy = 5; + reserved /* profileKey */ 6; + optional Hangup hangup = 7; + optional bool multiRing = 8; + optional uint32 destinationDeviceId = 9; + optional Opaque opaque = 10; +} + +message DataMessage { + enum Flags { + END_SESSION = 1; + EXPIRATION_TIMER_UPDATE = 2; + PROFILE_KEY_UPDATE = 4; + } + + message BodyRange { + optional int32 start = 1; + optional int32 length = 2; + + oneof associatedValue { + string mentionUuid = 3; + } + } + + message Quote { + message QuotedAttachment { + optional string contentType = 1; + optional string fileName = 2; + optional AttachmentPointer thumbnail = 3; + } + + optional uint64 id = 1; + optional string authorE164 = 2; + optional string authorUuid = 5; + optional string text = 3; + repeated QuotedAttachment attachments = 4; + repeated BodyRange bodyRanges = 6; + } + + message Contact { + message Name { + optional string givenName = 1; + optional string familyName = 2; + optional string prefix = 3; + optional string suffix = 4; + optional string middleName = 5; + optional string displayName = 6; + } + + message Phone { + enum Type { + HOME = 1; + MOBILE = 2; + WORK = 3; + CUSTOM = 4; + } + + optional string value = 1; + optional Type type = 2; + optional string label = 3; + } + + message Email { + enum Type { + HOME = 1; + MOBILE = 2; + WORK = 3; + CUSTOM = 4; + } + + optional string value = 1; + optional Type type = 2; + optional string label = 3; + } + + message PostalAddress { + enum Type { + HOME = 1; + WORK = 2; + CUSTOM = 3; + } + + optional Type type = 1; + optional string label = 2; + optional string street = 3; + optional string pobox = 4; + optional string neighborhood = 5; + optional string city = 6; + optional string region = 7; + optional string postcode = 8; + optional string country = 9; + } + + message Avatar { + optional AttachmentPointer avatar = 1; + optional bool isProfile = 2; + } + + optional Name name = 1; + repeated Phone number = 3; + repeated Email email = 4; + repeated PostalAddress address = 5; + optional Avatar avatar = 6; + optional string organization = 7; + } + + message Preview { + optional string url = 1; + optional string title = 2; + optional AttachmentPointer image = 3; + optional string description = 4; + optional uint64 date = 5; + } + + message Sticker { + optional bytes packId = 1; + optional bytes packKey = 2; + optional uint32 stickerId = 3; + optional AttachmentPointer data = 4; + optional string emoji = 5; + } + + message Reaction { + optional string emoji = 1; + optional bool remove = 2; + reserved /* targetAuthorE164 */ 3; // removed + optional string targetAuthorUuid = 4; + optional uint64 targetSentTimestamp = 5; + } + + message Delete { + optional uint64 targetSentTimestamp = 1; + } + + message GroupCallUpdate { + optional string eraId = 1; + } + + message Payment { + + message Address { + message MobileCoin { + optional bytes address = 1; + } + + oneof Address { + MobileCoin mobileCoin = 1; + } + } + + message Amount { + message MobileCoin { + optional uint64 picoMob = 1; + } + + oneof Amount { + MobileCoin mobileCoin = 1; + } + } + + message Notification { + message MobileCoin { + optional bytes receipt = 1; + } + + oneof Transaction { + MobileCoin mobileCoin = 1; + } + + optional string note = 2; + } + + oneof Item { + Notification notification = 1; + } + } + + enum ProtocolVersion { + option allow_alias = true; + + INITIAL = 0; + MESSAGE_TIMERS = 1; + VIEW_ONCE = 2; + VIEW_ONCE_VIDEO = 3; + REACTIONS = 4; + CDN_SELECTOR_ATTACHMENTS = 5; + MENTIONS = 6; + PAYMENTS = 7; + CURRENT = 7; + } + + optional string body = 1; + repeated AttachmentPointer attachments = 2; + optional GroupContext group = 3; + optional GroupContextV2 groupV2 = 15; + optional uint32 flags = 4; + optional uint32 expireTimer = 5; + optional bytes profileKey = 6; + optional uint64 timestamp = 7; + optional Quote quote = 8; + repeated Contact contact = 9; + repeated Preview preview = 10; + optional Sticker sticker = 11; + optional uint32 requiredProtocolVersion = 12; + optional bool isViewOnce = 14; + optional Reaction reaction = 16; + optional Delete delete = 17; + repeated BodyRange bodyRanges = 18; + optional GroupCallUpdate groupCallUpdate = 19; + optional Payment payment = 20; +} + +message NullMessage { + optional bytes padding = 1; +} + +message ReceiptMessage { + enum Type { + DELIVERY = 0; + READ = 1; + VIEWED = 2; + } + + optional Type type = 1; + repeated uint64 timestamp = 2; +} + +message TypingMessage { + enum Action { + STARTED = 0; + STOPPED = 1; + } + + optional uint64 timestamp = 1; + optional Action action = 2; + optional bytes groupId = 3; +} + +message Verified { + enum State { + DEFAULT = 0; + VERIFIED = 1; + UNVERIFIED = 2; + } + + optional string destinationE164 = 1; + optional string destinationUuid = 5; + optional bytes identityKey = 2; + optional State state = 3; + optional bytes nullMessage = 4; +} + +message SyncMessage { + message Sent { + message UnidentifiedDeliveryStatus { + optional string destinationE164 = 1; + optional string destinationUuid = 3; + optional bool unidentified = 2; + } + + optional string destinationE164 = 1; + optional string destinationUuid = 7; + optional uint64 timestamp = 2; + optional DataMessage message = 3; + optional uint64 expirationStartTimestamp = 4; + repeated UnidentifiedDeliveryStatus unidentifiedStatus = 5; + optional bool isRecipientUpdate = 6 [default = false]; + } + + message Contacts { + optional AttachmentPointer blob = 1; + optional bool complete = 2 [default = false]; + } + + message Groups { + optional AttachmentPointer blob = 1; + } + + message Blocked { + repeated string numbers = 1; + repeated string uuids = 3; + repeated bytes groupIds = 2; + } + + message Request { + enum Type { + UNKNOWN = 0; + CONTACTS = 1; + GROUPS = 2; + BLOCKED = 3; + CONFIGURATION = 4; + KEYS = 5; + } + + optional Type type = 1; + } + + message Read { + optional string senderE164 = 1; + optional string senderUuid = 3; + optional uint64 timestamp = 2; + } + + message Viewed { + optional string senderE164 = 1; + optional string senderUuid = 3; + optional uint64 timestamp = 2; + } + + message Configuration { + optional bool readReceipts = 1; + optional bool unidentifiedDeliveryIndicators = 2; + optional bool typingIndicators = 3; + reserved /* linkPreviews */ 4; // removed + optional uint32 provisioningVersion = 5; + optional bool linkPreviews = 6; + } + + message StickerPackOperation { + enum Type { + INSTALL = 0; + REMOVE = 1; + } + + optional bytes packId = 1; + optional bytes packKey = 2; + optional Type type = 3; + } + + message ViewOnceOpen { + optional string senderE164 = 1; + optional string senderUuid = 3; + optional uint64 timestamp = 2; + } + + message FetchLatest { + enum Type { + UNKNOWN = 0; + LOCAL_PROFILE = 1; + STORAGE_MANIFEST = 2; + } + + optional Type type = 1; + } + + message Keys { + optional bytes storageService = 1; + } + + message MessageRequestResponse { + enum Type { + UNKNOWN = 0; + ACCEPT = 1; + DELETE = 2; + BLOCK = 3; + BLOCK_AND_DELETE = 4; + } + + optional string threadE164 = 1; + optional string threadUuid = 2; + optional bytes groupId = 3; + optional Type type = 4; + } + + message OutgoingPayment { + message MobileCoin { + optional bytes recipientAddress = 1; + // @required + optional uint64 amountPicoMob = 2; + // @required + optional uint64 feePicoMob = 3; + optional bytes receipt = 4; + optional uint64 ledgerBlockTimestamp = 5; + // @required + optional uint64 ledgerBlockIndex = 6; + repeated bytes spentKeyImages = 7; + repeated bytes outputPublicKeys = 8; + } + optional string recipientUuid = 1; + optional string note = 2; + + oneof paymentDetail { + MobileCoin mobileCoin = 3; + } + } + + optional Sent sent = 1; + optional Contacts contacts = 2; + optional Groups groups = 3; + optional Request request = 4; + repeated Read read = 5; + optional Blocked blocked = 6; + optional Verified verified = 7; + optional Configuration configuration = 9; + optional bytes padding = 8; + repeated StickerPackOperation stickerPackOperation = 10; + optional ViewOnceOpen viewOnceOpen = 11; + optional FetchLatest fetchLatest = 12; + optional Keys keys = 13; + optional MessageRequestResponse messageRequestResponse = 14; + optional OutgoingPayment outgoingPayment = 15; + repeated Viewed viewed = 16; +} + +message AttachmentPointer { + enum Flags { + VOICE_MESSAGE = 1; + BORDERLESS = 2; + reserved 3; + GIF = 4; + } + + oneof attachment_identifier { + fixed64 cdnId = 1; + string cdnKey = 15; + } + optional string contentType = 2; + optional bytes key = 3; + optional uint32 size = 4; + optional bytes thumbnail = 5; + optional bytes digest = 6; + optional string fileName = 7; + optional uint32 flags = 8; + optional uint32 width = 9; + optional uint32 height = 10; + optional string caption = 11; + optional string blurHash = 12; + optional uint64 uploadTimestamp = 13; + optional uint32 cdnNumber = 14; + // Next ID: 16 +} + +message GroupContext { + enum Type { + UNKNOWN = 0; + UPDATE = 1; + DELIVER = 2; + QUIT = 3; + REQUEST_INFO = 4; + } + + message Member { + reserved /* uuid */ 1; // removed + optional string e164 = 2; + } + + optional bytes id = 1; + optional Type type = 2; + optional string name = 3; + repeated string membersE164 = 4; + repeated Member members = 6; + optional AttachmentPointer avatar = 5; +} + +message GroupContextV2 { + optional bytes masterKey = 1; + optional uint32 revision = 2; + optional bytes groupChange = 3; +} + +message ContactDetails { + message Avatar { + optional string contentType = 1; + optional uint32 length = 2; + } + + optional string number = 1; + optional string uuid = 9; + optional string name = 2; + optional Avatar avatar = 3; + optional string color = 4; + optional Verified verified = 5; + optional bytes profileKey = 6; + optional bool blocked = 7; + optional uint32 expireTimer = 8; + optional uint32 inboxPosition = 10; + optional bool archived = 11; +} + +message GroupDetails { + message Avatar { + optional string contentType = 1; + optional uint32 length = 2; + } + + message Member { + reserved /* uuid */ 1; // removed + optional string e164 = 2; + } + + optional bytes id = 1; + optional string name = 2; + repeated string membersE164 = 3; + repeated Member members = 9; + optional Avatar avatar = 4; + optional bool active = 5 [default = true]; + optional uint32 expireTimer = 6; + optional string color = 7; + optional bool blocked = 8; + optional uint32 inboxPosition = 10; + optional bool archived = 11; +} + +message PaymentAddress { + oneof Address { + MobileCoinAddress mobileCoinAddress = 1; + } + + message MobileCoinAddress { + optional bytes address = 1; + optional bytes signature = 2; + } +} + +message DecryptionErrorMessage { + optional bytes ratchetKey = 1; + optional uint64 timestamp = 2; + optional uint32 deviceId = 3; +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/protobuf/StickerResources.proto b/net/gurk-rs/files/vendor/libsignal-service/protobuf/StickerResources.proto new file mode 100644 index 0000000..03e5ccb --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/protobuf/StickerResources.proto @@ -0,0 +1,25 @@ +/** + * Copyright (C) 2019 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +syntax = "proto2"; + +package signalservice; + +option java_package = "org.whispersystems.signalservice.internal.sticker"; +option java_outer_classname = "StickerProtos"; + +message Pack { + message Sticker { + optional uint32 id = 1; + optional string emoji = 2; + optional string contentType = 3; + } + + optional string title = 1; + optional string author = 2; + optional Sticker cover = 3; + repeated Sticker stickers = 4; +} + diff --git a/net/gurk-rs/files/vendor/libsignal-service/protobuf/UnidentifiedDelivery.proto b/net/gurk-rs/files/vendor/libsignal-service/protobuf/UnidentifiedDelivery.proto new file mode 100644 index 0000000..c9e3154 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/protobuf/UnidentifiedDelivery.proto @@ -0,0 +1,48 @@ +syntax = "proto2"; + +package signal; + +option java_package = "org.signal.libsignal.metadata"; +option java_outer_classname = "SignalProtos"; + +message ServerCertificate { + message Certificate { + optional uint32 id = 1; + optional bytes key = 2; + } + + optional bytes certificate = 1; + optional bytes signature = 2; +} + +message SenderCertificate { + message Certificate { + optional string senderE164 = 1; + optional string senderUuid = 6; + optional uint32 senderDevice = 2; + optional fixed64 expires = 3; + optional bytes identityKey = 4; + optional ServerCertificate signer = 5; + } + + optional bytes certificate = 1; + optional bytes signature = 2; +} + +message UnidentifiedSenderMessage { + + message Message { + enum Type { + PREKEY_MESSAGE = 1; + MESSAGE = 2; + } + + optional Type type = 1; + optional SenderCertificate senderCertificate = 2; + optional bytes content = 3; + } + + optional bytes ephemeralPublic = 1; + optional bytes encryptedStatic = 2; + optional bytes encryptedMessage = 3; +} \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/libsignal-service/protobuf/WebSocketResources.proto b/net/gurk-rs/files/vendor/libsignal-service/protobuf/WebSocketResources.proto new file mode 100644 index 0000000..46ea453 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/protobuf/WebSocketResources.proto @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2014-2016 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +syntax = "proto2"; + +package signalservice; + +option java_package = "org.whispersystems.signalservice.internal.websocket"; +option java_outer_classname = "WebSocketProtos"; + +message WebSocketRequestMessage { + optional string verb = 1; + optional string path = 2; + optional bytes body = 3; + repeated string headers = 5; + optional uint64 id = 4; +} + +message WebSocketResponseMessage { + optional uint64 id = 1; + optional uint32 status = 2; + optional string message = 3; + repeated string headers = 5; + optional bytes body = 4; +} + +message WebSocketMessage { + enum Type { + UNKNOWN = 0; + REQUEST = 1; + RESPONSE = 2; + } + + optional Type type = 1; + optional WebSocketRequestMessage request = 2; + optional WebSocketResponseMessage response = 3; +} \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/account_manager.rs b/net/gurk-rs/files/vendor/libsignal-service/src/account_manager.rs new file mode 100644 index 0000000..8ae95be --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/account_manager.rs @@ -0,0 +1,409 @@ +use std::collections::HashMap; +use std::convert::{TryFrom, TryInto}; +use std::time::SystemTime; + +use libsignal_protocol::{ + IdentityKeyStore, KeyPair, PreKeyRecord, PreKeyStore, PublicKey, + SignalProtocolError, SignedPreKeyRecord, SignedPreKeyStore, +}; +use zkgroup::profiles::ProfileKey; + +use crate::{ + configuration::{Endpoint, ServiceCredentials}, + pre_keys::{PreKeyEntity, PreKeyState}, + profile_cipher::{ProfileCipher, ProfileCipherError}, + profile_name::ProfileName, + proto::{ProvisionEnvelope, ProvisionMessage, ProvisioningVersion}, + provisioning::{ProvisioningCipher, ProvisioningError}, + push_service::{ + AccountAttributes, HttpAuthOverride, PushService, ServiceError, + }, +}; + +pub struct AccountManager { + service: Service, + profile_key: Option<[u8; 32]>, +} + +#[derive(thiserror::Error, Debug)] +pub enum ProfileManagerError { + #[error(transparent)] + ServiceError(#[from] ServiceError), + #[error(transparent)] + ProfileCipherError(#[from] ProfileCipherError), +} + +#[derive(thiserror::Error, Debug)] +pub enum LinkError { + #[error(transparent)] + ServiceError(#[from] ServiceError), + #[error("TsUrl has an invalid UUID field")] + InvalidUuid, + #[error("TsUrl has an invalid pub_key field")] + InvalidPublicKey, + #[error("Protocol error {0}")] + ProtocolError(#[from] SignalProtocolError), + #[error(transparent)] + ProvisioningError(#[from] ProvisioningError), +} + +#[derive(Debug, Default)] +pub struct Profile { + pub name: Option>, + pub about: Option, + pub about_emoji: Option, +} + +const PRE_KEY_MINIMUM: u32 = 10; +const PRE_KEY_BATCH_SIZE: u32 = 100; +const PRE_KEY_MEDIUM_MAX_VALUE: u32 = 0xFFFFFF; + +impl AccountManager { + pub fn new(service: Service, profile_key: Option<[u8; 32]>) -> Self { + Self { + service, + profile_key, + } + } + + /// Checks the availability of pre-keys, and updates them as necessary. + /// + /// Parameters are the protocol's `StoreContext`, and the offsets for the next pre-key and + /// signed pre-keys. + /// + /// Equivalent to Java's RefreshPreKeysJob + /// + /// Returns the next pre-key offset and next signed pre-key offset as a tuple. + #[allow(clippy::too_many_arguments)] + pub async fn update_pre_key_bundle( + &mut self, + identity_store: &dyn IdentityKeyStore, + pre_key_store: &mut dyn PreKeyStore, + signed_pre_key_store: &mut dyn SignedPreKeyStore, + csprng: &mut R, + pre_keys_offset_id: u32, + next_signed_pre_key_id: u32, + use_last_resort_key: bool, + ) -> Result<(u32, u32), ServiceError> { + let prekey_count = match self.service.get_pre_key_status().await { + Ok(status) => status.count, + Err(ServiceError::Unauthorized) => { + log::info!("Got Unauthorized when fetching pre-key status. Assuming first installment."); + // Additionally, the second PUT request will fail if this really comes down to an + // authorization failure. + 0 + }, + Err(e) => return Err(e), + }; + log::trace!("Remaining pre-keys on server: {}", prekey_count); + + if prekey_count >= PRE_KEY_MINIMUM { + log::info!("Available keys sufficient"); + return Ok((pre_keys_offset_id, next_signed_pre_key_id)); + } + + let mut pre_key_entities = vec![]; + for i in 0..PRE_KEY_BATCH_SIZE { + let key_pair = KeyPair::generate(csprng); + let pre_key_id = + ((pre_keys_offset_id + i) % (PRE_KEY_MEDIUM_MAX_VALUE - 1)) + 1; + let pre_key_record = PreKeyRecord::new(pre_key_id, &key_pair); + pre_key_store + .save_pre_key(pre_key_id, &pre_key_record, None) + .await?; + + pre_key_entities.push(PreKeyEntity::try_from(pre_key_record)?); + } + + // Generate and store the next signed prekey + let identity_key_pair = + identity_store.get_identity_key_pair(None).await?; + let signed_pre_key_pair = KeyPair::generate(csprng); + let signed_pre_key_public = signed_pre_key_pair.public_key; + let signed_pre_key_signature = identity_key_pair + .private_key() + .calculate_signature(&signed_pre_key_public.serialize(), csprng)?; + + let unix_time = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap(); + + let signed_prekey_record = SignedPreKeyRecord::new( + next_signed_pre_key_id, + unix_time.as_millis() as u64, + &signed_pre_key_pair, + &signed_pre_key_signature, + ); + + signed_pre_key_store + .save_signed_pre_key( + next_signed_pre_key_id, + &signed_prekey_record, + None, + ) + .await?; + + let pre_key_state = PreKeyState { + pre_keys: pre_key_entities, + signed_pre_key: signed_prekey_record.try_into()?, + identity_key: *identity_key_pair.public_key(), + last_resort_key: if use_last_resort_key { + Some(PreKeyEntity { + key_id: 0x7fffffff, + public_key: "NDI=".into(), + }) + } else { + None + }, + }; + + self.service.register_pre_keys(pre_key_state).await?; + + log::trace!("Successfully refreshed prekeys"); + Ok(( + pre_keys_offset_id + PRE_KEY_BATCH_SIZE, + next_signed_pre_key_id + 1, + )) + } + + async fn new_device_provisioning_code( + &mut self, + ) -> Result { + #[derive(serde::Deserialize)] + #[serde(rename_all = "camelCase")] + struct DeviceCode { + verification_code: String, + } + + let dc: DeviceCode = self + .service + .get_json( + Endpoint::Service, + "/v1/devices/provisioning/code", + HttpAuthOverride::NoOverride, + ) + .await?; + Ok(dc.verification_code) + } + + async fn send_provisioning_message( + &mut self, + destination: &str, + env: ProvisionEnvelope, + ) -> Result<(), ServiceError> { + use prost::Message; + + #[derive(serde::Serialize)] + struct ProvisioningMessage { + body: String, + } + + let body = env.encode_to_vec(); + + self.service + .put_json( + Endpoint::Service, + &format!("/v1/provisioning/{}", destination), + HttpAuthOverride::NoOverride, + &ProvisioningMessage { + body: base64::encode(body), + }, + ) + .await + } + + /// Link a new device, given a tsurl. + /// + /// Equivalent of Java's `AccountManager::addDevice()` + /// + /// When calling this, make sure that UnidentifiedDelivery is disabled, ie., that your + /// application does not send any unidentified messages before linking is complete. + /// Cfr.: + /// - `app/src/main/java/org/thoughtcrime/securesms/migrations/LegacyMigrationJob.java`:250 and; + /// - `app/src/main/java/org/thoughtcrime/securesms/DeviceActivity.java`:195 + /// + /// ```java + /// TextSecurePreferences.setIsUnidentifiedDeliveryEnabled(context, false); + /// ``` + pub async fn link_device( + &mut self, + url: url::Url, + identity_store: &dyn IdentityKeyStore, + credentials: ServiceCredentials, + ) -> Result<(), LinkError> { + let query: HashMap<_, _> = url.query_pairs().collect(); + let ephemeral_id = query.get("uuid").ok_or(LinkError::InvalidUuid)?; + let pub_key = + query.get("pub_key").ok_or(LinkError::InvalidPublicKey)?; + let pub_key = base64::decode(&**pub_key) + .map_err(|_e| LinkError::InvalidPublicKey)?; + let pub_key = PublicKey::deserialize(&pub_key) + .map_err(|_e| LinkError::InvalidPublicKey)?; + + let identity_key_pair = + identity_store.get_identity_key_pair(None).await?; + + if credentials.uuid.is_none() { + log::warn!("No local UUID set"); + } + + let provisioning_code = self.new_device_provisioning_code().await?; + + let msg = ProvisionMessage { + identity_key_public: Some( + identity_key_pair.public_key().serialize().into_vec(), + ), + identity_key_private: Some( + identity_key_pair.private_key().serialize(), + ), + number: Some(credentials.e164()), + uuid: credentials.uuid.as_ref().map(|u| u.to_string()), + profile_key: self.profile_key.as_ref().map(|x| x.to_vec()), + // CURRENT is not exposed by prost :( + provisioning_version: Some(i32::from( + ProvisioningVersion::TabletSupport, + ) as _), + provisioning_code: Some(provisioning_code), + read_receipts: None, + user_agent: None, + }; + + let cipher = ProvisioningCipher::from_public(pub_key); + + let encrypted = cipher.encrypt(msg)?; + self.send_provisioning_message(ephemeral_id, encrypted) + .await?; + Ok(()) + } + + /// Upload a profile + /// + /// Panics if no `profile_key` was set. + /// + /// Convenience method for + /// ```ignore + /// manager.upload_versioned_profile::>, _>(uuid, name, about, about_emoji, None) + /// ``` + pub async fn upload_versioned_profile_without_avatar>( + &mut self, + uuid: uuid::Uuid, + name: ProfileName, + about: Option, + about_emoji: Option, + ) -> Result<(), ProfileManagerError> { + self.upload_versioned_profile::>, _>( + uuid, + name, + about, + about_emoji, + None, + ) + .await?; + Ok(()) + } + + pub async fn retrieve_profile( + &mut self, + uuid: uuid::Uuid, + ) -> Result { + let profile_key = + self.profile_key.expect("set profile key in AccountManager"); + let profile_key = ProfileKey::create(profile_key); + let profile_cipher = ProfileCipher::from(profile_key); + let profile_key_version = + profile_key.get_profile_key_version(*uuid.as_bytes()); + + let encrypted_profile = self + .service + .retrieve_versioned_profile_by_id( + &uuid.to_string(), + &profile_key_version, + ) + .await?; + + // Profile decryption + let name = encrypted_profile + .name + .map(|data| profile_cipher.decrypt_name(data)) + .transpose()? + .flatten(); + let about = encrypted_profile + .about + .map(|data| profile_cipher.decrypt_about(data)) + .transpose()?; + let about_emoji = encrypted_profile + .about_emoji + .map(|data| profile_cipher.decrypt_emoji(data)) + .transpose()?; + + Ok(Profile { + name, + about, + about_emoji, + }) + } + + /// Upload a profile + /// + /// Panics if no `profile_key` was set. + /// + /// Returns the avatar url path. + pub async fn upload_versioned_profile< + 's, + C: std::io::Read + Send + 's, + S: AsRef, + >( + &mut self, + uuid: uuid::Uuid, + name: ProfileName, + about: Option, + about_emoji: Option, + avatar: Option<&'s mut C>, + ) -> Result, ProfileManagerError> { + let profile_key = + self.profile_key.expect("set profile key in AccountManager"); + let profile_key = ProfileKey::create(profile_key); + let profile_cipher = ProfileCipher::from(profile_key); + + // Profile encryption + let name = profile_cipher.encrypt_name(name.as_ref())?; + let about = about.unwrap_or_default(); + let about = profile_cipher.encrypt_about(about)?; + let about_emoji = about_emoji.unwrap_or_default(); + let about_emoji = profile_cipher.encrypt_emoji(about_emoji)?; + + // If avatar -> upload + if let Some(_avatar) = avatar { + // FIXME ProfileCipherOutputStream.java + // It's just AES GCM, but a bit of work to decently implement it with a stream. + unimplemented!("Setting avatar requires ProfileCipherStream") + } + + let profile_key = profile_cipher.into_inner(); + let commitment = profile_key.get_commitment(*uuid.as_bytes()); + let profile_key_version = + profile_key.get_profile_key_version(*uuid.as_bytes()); + + Ok(self + .service + .write_profile( + &profile_key_version, + &name, + &about, + &about_emoji, + &commitment, + None, // FIXME avatar + ) + .await?) + } + + /// Set profile attributes + /// + /// Signal Android does not allow unsetting voice/video. + pub async fn set_account_attributes( + &mut self, + attributes: AccountAttributes, + ) -> Result<(), ServiceError> { + self.service.set_account_attributes(attributes).await + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/attachment_cipher.rs b/net/gurk-rs/files/vendor/libsignal-service/src/attachment_cipher.rs new file mode 100644 index 0000000..a3b94b0 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/attachment_cipher.rs @@ -0,0 +1,163 @@ +use aes::Aes256; +use block_modes::{block_padding::Pkcs7, BlockMode, Cbc}; +use hmac::{Hmac, Mac, NewMac}; +use sha2::Sha256; + +#[derive(thiserror::Error, Debug, PartialEq, Eq)] +pub enum AttachmentCipherError { + #[error("MAC verification error")] + MacError, + #[error("Padding verification error")] + PaddingError, +} + +/// Encrypts an attachment in place, given the key material. +/// +/// The Vec will be reused when it has enough space to house the MAC, +/// otherwise reallocation might happen. +pub fn encrypt_in_place(iv: [u8; 16], key: [u8; 64], plaintext: &mut Vec) { + let aes_half = &key[..32]; + let mac_half = &key[32..]; + + let plaintext_len = plaintext.len(); + plaintext.reserve(plaintext.len() + 16 + 16); + + // Prepend IV + plaintext.extend(&[0u8; 16]); + plaintext.copy_within(..plaintext_len, 16); + plaintext[0..16].copy_from_slice(&iv); + + // Pad with zeroes for padding + plaintext.extend(&[0u8; 16]); + + let cipher = Cbc::::new_from_slices(aes_half, &iv) + .expect("fixed length key material"); + + let buffer = plaintext; + let ciphertext_slice = cipher + .encrypt(&mut buffer[16..], plaintext_len) + .expect("encrypted ciphertext"); + let ciphertext_len = ciphertext_slice.len(); + // Correct length for padding + buffer.truncate(16 + ciphertext_len); + + // Compute and append MAC + let mut mac = Hmac::::new_from_slice(mac_half) + .expect("fixed length key material"); + mac.update(buffer); + buffer.extend(mac.finalize().into_bytes()); +} + +/// Decrypts an attachment in place, given the key material. +/// +/// On error, ciphertext is not changed. +pub fn decrypt_in_place( + key: [u8; 64], + ciphertext: &mut Vec, +) -> Result<(), AttachmentCipherError> { + let aes_half = &key[..32]; + let mac_half = &key[32..]; + + let ciphertext_len = ciphertext.len(); + + let (buffer, their_mac) = ciphertext.split_at_mut(ciphertext_len - 32); + + // Compute and append MAC + let mut mac = Hmac::::new_from_slice(mac_half) + .expect("fixed length key material"); + mac.update(buffer); + mac.verify(their_mac) + .map_err(|_| AttachmentCipherError::MacError)?; + + let (iv, buffer) = buffer.split_at_mut(16); + + let cipher = Cbc::::new_from_slices(aes_half, iv) + .expect("fixed length key material"); + + let plaintext_slice = cipher + .decrypt(buffer) + .map_err(|_| AttachmentCipherError::PaddingError)?; + + let plaintext_len = plaintext_slice.len(); + + // Get rid of IV and MAC + ciphertext.copy_within(16..(plaintext_len + 16), 0); + ciphertext.truncate(plaintext_len); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + use rand::prelude::*; + + #[test] + fn attachment_encrypt_decrypt() -> Result<(), AttachmentCipherError> { + let mut key = [0u8; 64]; + let mut iv = [0u8; 16]; + rand::thread_rng().fill_bytes(&mut key); + rand::thread_rng().fill_bytes(&mut iv); + + let plaintext = b"Peter Parker"; + let mut buf = Vec::from(plaintext as &[u8]); + encrypt_in_place(iv, key, &mut buf); + assert_ne!(&buf, &plaintext); + decrypt_in_place(key, &mut buf)?; + assert_eq!(&buf, &plaintext); + Ok(()) + } + + #[test] + fn attachment_encrypt_decrypt_empty() -> Result<(), AttachmentCipherError> { + let mut key = [0u8; 64]; + let mut iv = [0u8; 16]; + rand::thread_rng().fill_bytes(&mut key); + rand::thread_rng().fill_bytes(&mut iv); + let plaintext = b""; + let mut buf = Vec::from(plaintext as &[u8]); + encrypt_in_place(iv, key, &mut buf); + assert_ne!(&buf, &plaintext); + decrypt_in_place(key, &mut buf)?; + assert_eq!(&buf, &plaintext); + Ok(()) + } + + #[test] + fn attachment_encrypt_decrypt_bad_key() { + let mut key = [0u8; 64]; + let mut iv = [0u8; 16]; + rand::thread_rng().fill_bytes(&mut key); + rand::thread_rng().fill_bytes(&mut iv); + let plaintext = b"Peter Parker"; + let mut buf = Vec::from(plaintext as &[u8]); + encrypt_in_place(iv, key, &mut buf); + + // Generate bad key + rand::thread_rng().fill_bytes(&mut key); + assert_eq!( + decrypt_in_place(key, &mut buf).unwrap_err(), + AttachmentCipherError::MacError + ); + assert_ne!(&buf, &plaintext); + } + + #[test] + fn know_answer_test_attachment() -> Result<(), AttachmentCipherError> { + let mut ciphertext = include!("kat.bin.rs"); + let key_material = [ + 52, 102, 97, 87, 153, 192, 64, 116, 93, 96, 57, 110, 6, 197, 208, + 85, 49, 249, 154, 137, 116, 124, 112, 107, 8, 158, 48, 4, 8, 66, + 173, 5, 28, 16, 199, 226, 234, 38, 69, 167, 163, 34, 107, 164, 15, + 118, 101, 146, 34, 213, 85, 164, 110, 83, 129, 245, 62, 44, 158, + 78, 205, 62, 153, 108, + ]; + + decrypt_in_place(key_material, &mut ciphertext)?; + // This 32 is given by the AttachmentPointer + ciphertext.truncate(32); + assert_eq!(ciphertext, b"test for libsignal-service-rust\n"); + Ok(()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/cipher.rs b/net/gurk-rs/files/vendor/libsignal-service/src/cipher.rs new file mode 100644 index 0000000..dd35a91 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/cipher.rs @@ -0,0 +1,372 @@ +use std::convert::TryFrom; + +use block_modes::block_padding::{Iso7816, Padding}; +use libsignal_protocol::{ + message_decrypt_prekey, message_decrypt_signal, message_encrypt, + CiphertextMessageType, IdentityKeyStore, PreKeySignalMessage, PreKeyStore, + ProtocolAddress, SessionStore, SignalMessage, SignalProtocolError, + SignedPreKeyStore, +}; +use prost::Message; +use rand::{CryptoRng, Rng}; + +use crate::{ + content::{Content, Metadata}, + envelope::Envelope, + push_service::ServiceError, + sealed_session_cipher::UnidentifiedAccess, + sealed_session_cipher::{ + CertificateValidator, DecryptionResult, SealedSessionCipher, + }, + sender::OutgoingPushMessage, + ServiceAddress, +}; + +/// Decrypts incoming messages and encrypts outgoing messages. +/// +/// Equivalent of SignalServiceCipher in Java. +#[derive(Clone)] +pub struct ServiceCipher { + session_store: S, + identity_key_store: I, + signed_pre_key_store: SP, + pre_key_store: P, + csprng: R, + sealed_session_cipher: SealedSessionCipher, +} + +impl ServiceCipher +where + S: SessionStore + Clone, + I: IdentityKeyStore + Clone, + SP: SignedPreKeyStore + Clone, + P: PreKeyStore + Clone, + R: Rng + CryptoRng + Clone, +{ + pub fn new( + session_store: S, + identity_key_store: I, + signed_pre_key_store: SP, + pre_key_store: P, + csprng: R, + certificate_validator: CertificateValidator, + ) -> Self { + Self { + session_store: session_store.clone(), + identity_key_store: identity_key_store.clone(), + signed_pre_key_store: signed_pre_key_store.clone(), + pre_key_store: pre_key_store.clone(), + csprng: csprng.clone(), + sealed_session_cipher: SealedSessionCipher::new( + session_store, + identity_key_store, + signed_pre_key_store, + pre_key_store, + csprng, + certificate_validator, + ), + } + } + + /// Opens ("decrypts") an envelope. + /// + /// Envelopes may be empty, in which case this method returns `Ok(None)` + pub async fn open_envelope( + &mut self, + envelope: Envelope, + ) -> Result, ServiceError> { + if envelope.legacy_message.is_some() { + let plaintext = self.decrypt(&envelope).await?; + let message = + crate::proto::DataMessage::decode(plaintext.data.as_slice())?; + Ok(Some(Content::from_body(message, plaintext.metadata))) + } else if envelope.content.is_some() { + let plaintext = self.decrypt(&envelope).await?; + let message = + crate::proto::Content::decode(plaintext.data.as_slice())?; + Ok(Content::from_proto(message, plaintext.metadata)) + } else { + Ok(None) + } + } + + /// Equivalent of decrypt(Envelope, ciphertext) + /// + /// Triage of legacy messages happens inside this method, as opposed to the + /// Java implementation, because it makes the borrow checker and the + /// author happier. + async fn decrypt( + &mut self, + envelope: &Envelope, + ) -> Result { + let ciphertext = if let Some(msg) = envelope.legacy_message.as_ref() { + msg + } else if let Some(msg) = envelope.content.as_ref() { + msg + } else { + return Err(ServiceError::InvalidFrameError { + reason: + "Envelope should have either a legacy message or content." + .into(), + }); + }; + + use crate::proto::envelope::Type; + let plaintext = match envelope.r#type() { + Type::PrekeyBundle => { + let sender = get_preferred_protocol_address( + &self.session_store, + &envelope.source_address(), + envelope.source_device(), + ) + .await?; + let metadata = Metadata { + sender: envelope.source_address(), + sender_device: envelope.source_device(), + timestamp: envelope.timestamp(), + needs_receipt: false, + }; + + let mut data = message_decrypt_prekey( + &PreKeySignalMessage::try_from(&ciphertext[..]).unwrap(), + &sender, + &mut self.session_store, + &mut self.identity_key_store, + &mut self.pre_key_store, + &mut self.signed_pre_key_store, + &mut self.csprng, + None, + ) + .await? + .as_slice() + .to_vec(); + + let session_record = self + .session_store + .load_session(&sender, None) + .await? + .ok_or_else(|| { + SignalProtocolError::SessionNotFound(format!( + "{}", + sender + )) + })?; + + strip_padding(session_record.session_version()?, &mut data)?; + Plaintext { metadata, data } + }, + Type::Ciphertext => { + let sender = get_preferred_protocol_address( + &self.session_store, + &envelope.source_address(), + envelope.source_device(), + ) + .await?; + let metadata = Metadata { + sender: envelope.source_address(), + sender_device: envelope.source_device(), + timestamp: envelope.timestamp(), + needs_receipt: false, + }; + + let mut data = message_decrypt_signal( + &SignalMessage::try_from(&ciphertext[..])?, + &sender, + &mut self.session_store, + &mut self.identity_key_store, + &mut self.csprng, + None, + ) + .await? + .as_slice() + .to_vec(); + + let session_record = self + .session_store + .load_session(&sender, None) + .await? + .ok_or_else(|| { + SignalProtocolError::SessionNotFound(format!( + "{}", + sender + )) + })?; + + strip_padding(session_record.session_version()?, &mut data)?; + Plaintext { metadata, data } + }, + Type::UnidentifiedSender => { + let DecryptionResult { + sender_uuid, + sender_e164, + device_id, + padded_message: mut data, + version, + } = self + .sealed_session_cipher + .decrypt(ciphertext, envelope.timestamp()) + .await?; + let sender = ServiceAddress { + phonenumber: sender_e164, + uuid: sender_uuid, + relay: None, + }; + let metadata = Metadata { + sender, + sender_device: device_id, + timestamp: envelope.timestamp(), + needs_receipt: false, + }; + strip_padding(version, &mut data)?; + Plaintext { metadata, data } + }, + _ => { + // else + return Err(ServiceError::InvalidFrameError { + reason: format!( + "Envelope has unknown type {:?}.", + envelope.r#type() + ), + }); + }, + }; + Ok(plaintext) + } + + pub(crate) async fn encrypt( + &mut self, + address: &ProtocolAddress, + unindentified_access: Option<&UnidentifiedAccess>, + content: &[u8], + ) -> Result { + if unindentified_access.is_some() { + unimplemented!("unidentified access is not implemented"); + } else { + let session_record = self + .session_store + .load_session(address, None) + .await? + .ok_or_else(|| { + SignalProtocolError::SessionNotFound(format!("{}", address)) + })?; + + let padded_content = + add_padding(session_record.session_version()?, content)?; + + let message = message_encrypt( + &padded_content, + address, + &mut self.session_store, + &mut self.identity_key_store, + None, + ) + .await?; + + let destination_registration_id = + session_record.remote_registration_id()?; + + let body = base64::encode(message.serialize()); + + use crate::proto::envelope::Type; + let message_type = match message.message_type() { + CiphertextMessageType::PreKey => Type::PrekeyBundle, + CiphertextMessageType::Whisper => Type::Ciphertext, + t => panic!("Bad type: {:?}", t), + } as u32; + Ok(OutgoingPushMessage { + r#type: message_type, + destination_device_id: address.device_id(), + destination_registration_id, + content: body, + }) + } + } +} + +struct Plaintext { + metadata: Metadata, + data: Vec, +} + +#[allow(clippy::comparison_chain)] +fn add_padding(version: u32, contents: &[u8]) -> Result, ServiceError> { + if version < 2 { + Err(ServiceError::InvalidFrameError { + reason: format!("Unknown version {}", version), + }) + } else if version == 2 { + Ok(contents.to_vec()) + } else { + let message_length = contents.len(); + let message_length_with_terminator = contents.len() + 1; + let mut message_part_count = message_length_with_terminator / 160; + if message_length_with_terminator % 160 != 0 { + message_part_count += 1; + } + + let message_length_with_padding = message_part_count * 160; + + let mut buffer = vec![0u8; message_length_with_padding]; + buffer[..message_length].copy_from_slice(contents); + Iso7816::pad_block(&mut buffer, message_length).map_err(|e| { + ServiceError::InvalidFrameError { + reason: format!("Invalid message padding: {:?}", e), + } + })?; + Ok(buffer) + } +} + +#[allow(clippy::comparison_chain)] +fn strip_padding( + version: u32, + contents: &mut Vec, +) -> Result<(), ServiceError> { + if version < 2 { + Err(ServiceError::InvalidFrameError { + reason: format!("Unknown version {}", version), + }) + } else if version == 2 { + Ok(()) + } else { + let new_length = Iso7816::unpad(contents) + .map_err(|e| ServiceError::InvalidFrameError { + reason: format!("Invalid message padding: {:?}", e), + })? + .len(); + contents.resize(new_length, 0); + Ok(()) + } +} + +/// Equivalent of `SignalServiceCipher::getPreferredProtocolAddress` +pub async fn get_preferred_protocol_address( + session_store: &dyn SessionStore, + address: &ServiceAddress, + device_id: u32, +) -> Result { + if let Some(ref uuid) = address.uuid { + let address = ProtocolAddress::new(uuid.to_string(), device_id); + if session_store.load_session(&address, None).await?.is_some() { + return Ok(address); + } + } + if let Some(e164) = address.e164() { + let address = ProtocolAddress::new(e164, device_id); + if session_store.load_session(&address, None).await?.is_some() { + return Ok(address); + } + if cfg!(feature = "prefer-e164") { + log::warn!("prefer-e164 triggered. This is a legacy feature and shouldn't be used for new applications."); + return Ok(address); + } + } + if cfg!(feature = "prefer-e164") { + panic!( + "{:?}:{} does not have a e164 associated, falling back to UUID.", + address, device_id + ); + } + + Ok(ProtocolAddress::new(address.identifier(), device_id)) +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/configuration.rs b/net/gurk-rs/files/vendor/libsignal-service/src/configuration.rs new file mode 100644 index 0000000..37b2d0d --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/configuration.rs @@ -0,0 +1,180 @@ +use std::{collections::HashMap, str::FromStr}; + +use libsignal_protocol::PublicKey; +use serde::{Deserialize, Serialize}; +use url::Url; +use zkgroup::ServerPublicParams; + +use crate::{ + envelope::{CIPHER_KEY_SIZE, MAC_KEY_SIZE}, + push_service::{HttpAuth, ServiceError, DEFAULT_DEVICE_ID}, + sealed_session_cipher::{CertificateValidator, SealedSessionError}, +}; + +#[derive(Clone)] +pub struct ServiceConfiguration { + service_url: Url, + storage_url: Url, + cdn_urls: HashMap, + contact_discovery_url: Url, + pub certificate_authority: String, + pub unidentified_sender_trust_root: String, + pub zkgroup_server_public_params: ServerPublicParams, +} + +pub type SignalingKey = [u8; CIPHER_KEY_SIZE + MAC_KEY_SIZE]; + +#[derive(Clone)] +pub struct ServiceCredentials { + pub uuid: Option, + pub phonenumber: phonenumber::PhoneNumber, + pub password: Option, + pub signaling_key: Option, + pub device_id: Option, +} + +impl ServiceCredentials { + pub fn authorization(&self) -> Option { + self.password.as_ref().map(|password| HttpAuth { + username: self.login(), + password: password.clone(), + }) + } + + pub fn e164(&self) -> String { + self.phonenumber + .format() + .mode(phonenumber::Mode::E164) + .to_string() + } + + pub fn login(&self) -> String { + let identifier = { + if let Some(uuid) = self.uuid.as_ref() { + uuid.to_string() + } else { + self.e164() + } + }; + + match self.device_id { + None | Some(DEFAULT_DEVICE_ID) => identifier, + Some(id) => format!("{}.{}", identifier, id), + } + } +} + +const SIGNAL_ROOT_CA: &str = r#"-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIJAIm6LatK5PNiMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEdMBsGA1UECgwUT3BlbiBXaGlzcGVyIFN5c3RlbXMxHTAbBgNVBAsMFE9wZW4gV2hpc3BlciBTeXN0ZW1zMRMwEQYDVQQDDApUZXh0U2VjdXJlMB4XDTEzMDMyNTIyMTgzNVoXDTIzMDMyMzIyMTgzNVowgY0xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMR0wGwYDVQQKDBRPcGVuIFdoaXNwZXIgU3lzdGVtczEdMBsGA1UECwwUT3BlbiBXaGlzcGVyIFN5c3RlbXMxEzARBgNVBAMMClRleHRTZWN1cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBSWBpOCBDF0i4q2d4jAXkSXUGpbeWugVPQCjaL6qD9QDOxeW1afvfPo863i6Crq1KDxHpB36EwzVcjwLkFTIMeo7t9s1FQolAt3mErV2U0vie6Ves+yj6grSfxwIDAcdsKmI0a1SQCZlr3Q1tcHAkAKFRxYNawADyps5B+Zmqcgf653TXS5/0IPPQLocLn8GWLwOYNnYfBvILKDMItmZTtEbucdigxEA9mfIvvHADEbteLtVgwBm9R5vVvtwrD6CCxI3pgH7EH7kMP0Od93wLisvn1yhHY7FuYlrkYqdkMvWUrKoASVw4jb69vaeJCUdU+HCoXOSP1PQcL6WenNCHAgMBAAGjUDBOMB0GA1UdDgQWBBQBixjxP/s5GURuhYa+lGUypzI8kDAfBgNVHSMEGDAWgBQBixjxP/s5GURuhYa+lGUypzI8kDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQB+Hr4hC56m0LvJAu1RK6NuPDbTMEN7/jMojFHxH4P3XPFfupjR+bkDq0pPOU6JjIxnrD1XD/EVmTTaTVY5iOheyv7UzJOefb2pLOc9qsuvI4fnaESh9bhzln+LXxtCrRPGhkxA1IMIo3J/s2WF/KVYZyciu6b4ubJ91XPAuBNZwImug7/srWvbpk0hq6A6z140WTVSKtJG7EP41kJe/oF4usY5J7LPkxK3LWzMJnb5EIJDmRvyH8pyRwWg6Qm6qiGFaI4nL8QU4La1x2en4DGXRaLMPRwjELNgQPodR38zoCMuA8gHZfZYYoZ7D7Q1wNUiVHcxuFrEeBaYJbLErwLV +-----END CERTIFICATE-----"#; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum SignalServers { + Staging, + Production, +} + +#[derive(Debug)] +pub enum Endpoint { + Service, + Storage, + Cdn(u32), + ContactDiscovery, +} + +impl FromStr for SignalServers { + type Err = std::io::Error; + + fn from_str(s: &str) -> Result { + use std::io::ErrorKind; + match s { + "staging" => Ok(Self::Staging), + "production" => Ok(Self::Production), + _ => Err(Self::Err::new( + ErrorKind::InvalidInput, + "invalid signal servers, can be either: staging or production", + )), + } + } +} + +impl ToString for SignalServers { + fn to_string(&self) -> String { + match self { + Self::Staging => "staging", + Self::Production => "production", + } + .to_string() + } +} + +impl From for ServiceConfiguration { + fn from(val: SignalServers) -> Self { + ServiceConfiguration::from(&val) + } +} + +impl From<&SignalServers> for ServiceConfiguration { + fn from(val: &SignalServers) -> Self { + // base configuration from https://github.com/signalapp/Signal-Desktop/blob/development/config/default.json + match val { + // configuration with the Signal API staging endpoints + // see: https://github.com/signalapp/Signal-Desktop/blob/master/config/default.json + SignalServers::Staging => ServiceConfiguration { + service_url: "https://chat.staging.signal.org".parse().unwrap(), + storage_url:"https://storage-staging.signal.org".parse().unwrap(), + cdn_urls: { + let mut map = HashMap::new(); + map.insert(0, "https://cdn-staging.signal.org".parse().unwrap()); + map.insert(2, "https://cdn2-staging.signal.org".parse().unwrap()); + map + }, + contact_discovery_url: + "https://api-staging.directory.signal.org".parse().unwrap(), + certificate_authority: SIGNAL_ROOT_CA.into(), + unidentified_sender_trust_root: + "BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx".into(), + zkgroup_server_public_params: bincode::deserialize(&base64::decode("ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdls=").unwrap()).unwrap(), + }, + // configuration with the Signal API production endpoints + // https://github.com/signalapp/Signal-Desktop/blob/master/config/production.json + SignalServers::Production => ServiceConfiguration { + service_url: + "https://chat.signal.org".parse().unwrap(), + storage_url: "https://storage.signal.org".parse().unwrap(), + cdn_urls: { + let mut map = HashMap::new(); + map.insert(0, "https://cdn.signal.org".parse().unwrap()); + map.insert(2, "https://cdn2.signal.org".parse().unwrap()); + map + }, + contact_discovery_url: "https://api.directory.signal.org".parse().unwrap(), + certificate_authority: SIGNAL_ROOT_CA.into(), + unidentified_sender_trust_root: + "BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF".into(), + zkgroup_server_public_params: bincode::deserialize( + &base64::decode("AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X0=").unwrap()).unwrap(), + }, + } + } +} + +impl ServiceConfiguration { + pub fn credentials_validator( + &self, + ) -> Result { + Ok(CertificateValidator::new(PublicKey::deserialize( + &base64::decode(&self.unidentified_sender_trust_root) + .map_err(|_| SealedSessionError::InvalidCertificate)?, + )?)) + } + + pub fn base_url(&self, endpoint: Endpoint) -> &Url { + match endpoint { + Endpoint::Service => &self.service_url, + Endpoint::Storage => &self.storage_url, + Endpoint::Cdn(ref n) => &self.cdn_urls[n], + Endpoint::ContactDiscovery => &self.contact_discovery_url, + } + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/content.rs b/net/gurk-rs/files/vendor/libsignal-service/src/content.rs new file mode 100644 index 0000000..35b818a --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/content.rs @@ -0,0 +1,112 @@ +pub use crate::{ + proto::{ + attachment_pointer::Flags as AttachmentPointerFlags, + data_message::Flags as DataMessageFlags, data_message::Reaction, + group_context::Type as GroupType, sync_message, AttachmentPointer, + CallMessage, DataMessage, GroupContext, GroupContextV2, ReceiptMessage, + SyncMessage, TypingMessage, + }, + push_service::ServiceError, +}; + +#[derive(Clone, Debug)] +pub struct Metadata { + pub sender: crate::ServiceAddress, + pub sender_device: u32, + pub timestamp: u64, + pub needs_receipt: bool, +} + +#[derive(Clone, Debug)] +pub struct Content { + pub metadata: Metadata, + pub body: ContentBody, +} + +impl Content { + pub fn from_body(body: impl Into, metadata: Metadata) -> Self { + Self { + metadata, + body: body.into(), + } + } + + /// Converts a proto::Content into a public Content, including metadata. + pub(crate) fn from_proto( + p: crate::proto::Content, + metadata: Metadata, + ) -> Option { + // The Java version also assumes only one content type at a time. + // It's a bit sad that we cannot really match here, we've got no + // r#type() method. + // Allow the manual map (if let Some -> option.map(||)), because it + // reduces the git diff when more types would be added. + #[allow(clippy::manual_map)] + if let Some(msg) = p.data_message { + Some(Self::from_body(msg, metadata)) + } else if let Some(msg) = p.sync_message { + Some(Self::from_body(msg, metadata)) + } else if let Some(msg) = p.call_message { + Some(Self::from_body(msg, metadata)) + } else if let Some(msg) = p.receipt_message { + Some(Self::from_body(msg, metadata)) + } else if let Some(msg) = p.typing_message { + Some(Self::from_body(msg, metadata)) + } else { + None + } + } +} + +#[derive(Clone, Debug)] +#[allow(clippy::large_enum_variant)] +pub enum ContentBody { + DataMessage(DataMessage), + SynchronizeMessage(SyncMessage), + CallMessage(CallMessage), + ReceiptMessage(ReceiptMessage), + TypingMessage(TypingMessage), +} + +impl ContentBody { + pub fn into_proto(self) -> crate::proto::Content { + match self { + Self::DataMessage(msg) => crate::proto::Content { + data_message: Some(msg), + ..Default::default() + }, + Self::SynchronizeMessage(msg) => crate::proto::Content { + sync_message: Some(msg), + ..Default::default() + }, + Self::CallMessage(msg) => crate::proto::Content { + call_message: Some(msg), + ..Default::default() + }, + Self::ReceiptMessage(msg) => crate::proto::Content { + receipt_message: Some(msg), + ..Default::default() + }, + Self::TypingMessage(msg) => crate::proto::Content { + typing_message: Some(msg), + ..Default::default() + }, + } + } +} + +macro_rules! impl_from_for_content_body { + ($enum:ident ($t:ty)) => { + impl From<$t> for ContentBody { + fn from(inner: $t) -> ContentBody { + ContentBody::$enum(inner) + } + } + }; +} + +impl_from_for_content_body!(DataMessage(DataMessage)); +impl_from_for_content_body!(SynchronizeMessage(SyncMessage)); +impl_from_for_content_body!(CallMessage(CallMessage)); +impl_from_for_content_body!(ReceiptMessage(ReceiptMessage)); +impl_from_for_content_body!(TypingMessage(TypingMessage)); diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/digeststream.rs b/net/gurk-rs/files/vendor/libsignal-service/src/digeststream.rs new file mode 100644 index 0000000..626caec --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/digeststream.rs @@ -0,0 +1,31 @@ +use std::io::Read; + +use sha2::{Digest, Sha256}; + +pub struct DigestingReader<'r, R> { + inner: &'r mut R, + digest: Sha256, +} + +impl<'r, R: Read> Read for DigestingReader<'r, R> { + fn read(&mut self, tgt: &mut [u8]) -> Result { + let amount = self.inner.read(tgt)?; + self.digest.update(&tgt[..amount]); + Ok(amount) + } +} + +impl<'r, R: Read> DigestingReader<'r, R> { + pub fn new(inner: &'r mut R) -> Self { + Self { + inner, + digest: Sha256::new(), + } + } + + pub fn finalize(self) -> Vec { + // XXX representation is not ideal, but this leaks to the public interface and I don't + // really like exposing the GenericArray. + Vec::from(self.digest.finalize().as_slice()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/envelope.rs b/net/gurk-rs/files/vendor/libsignal-service/src/envelope.rs new file mode 100644 index 0000000..af57f3f --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/envelope.rs @@ -0,0 +1,246 @@ +#![allow(dead_code)] // XXX: remove when all constants on bottom are used. + +use prost::Message; +use uuid::Uuid; + +use crate::{ + configuration::SignalingKey, push_service::ServiceError, + utils::serde_optional_base64, ParseServiceAddressError, ServiceAddress, +}; + +pub use crate::proto::Envelope; + +#[derive(thiserror::Error, Debug, Clone)] +pub enum EnvelopeParseError { + #[error("Supplied phone number could not be parsed in E164 format")] + InvalidPhoneNumber(#[from] phonenumber::ParseError), + + #[error("Supplied uuid could not be parsed")] + InvalidUuidError(#[from] uuid::Error), + + #[error("Envelope with neither Uuid or E164")] + NoSenderError, +} + +impl std::convert::TryFrom for Envelope { + type Error = EnvelopeParseError; + + fn try_from( + entity: EnvelopeEntity, + ) -> Result { + use ParseServiceAddressError::*; + if entity.source.is_none() && entity.source_uuid.is_none() { + return Err(EnvelopeParseError::NoSenderError); + } + + // XXX: throwing allocations like it's Java. + let source = ServiceAddress::parse( + entity.source.as_deref(), + entity.source_uuid.as_deref(), + ); + match source { + // Valid source + Ok(source) if entity.source_device > 0 => { + Ok(Envelope::new_with_source(entity, source)) + }, + // No source + Ok(_) | Err(NoSenderError) => Ok(Envelope::new_from_entity(entity)), + // Source specified, but unparsable + Err(InvalidPhoneNumber(e)) => { + Err(EnvelopeParseError::InvalidPhoneNumber(e)) + }, + Err(InvalidUuidError(e)) => { + Err(EnvelopeParseError::InvalidUuidError(e)) + }, + } + } +} + +impl Envelope { + pub fn decrypt( + input: &[u8], + signaling_key: &SignalingKey, + is_signaling_key_encrypted: bool, + ) -> Result { + if !is_signaling_key_encrypted { + log::trace!("Envelope::decrypt: not encrypted"); + Ok(Envelope::decode(input)?) + } else { + log::trace!("Envelope::decrypt: decrypting"); + if input.len() < VERSION_LENGTH + || input[VERSION_OFFSET] != SUPPORTED_VERSION + { + return Err(ServiceError::InvalidFrameError { + reason: "Unsupported signaling cryptogram version".into(), + }); + } + + let aes_key = &signaling_key[..CIPHER_KEY_SIZE]; + let mac_key = &signaling_key[CIPHER_KEY_SIZE..]; + let mac = &input[(input.len() - MAC_SIZE)..]; + let input_for_mac = &input[..(input.len() - MAC_SIZE)]; + let iv = &input[IV_OFFSET..(IV_OFFSET + IV_LENGTH)]; + debug_assert_eq!(mac_key.len(), MAC_KEY_SIZE); + debug_assert_eq!(aes_key.len(), CIPHER_KEY_SIZE); + debug_assert_eq!(iv.len(), IV_LENGTH); + + // Verify MAC + use hmac::{Hmac, Mac, NewMac}; + use sha2::Sha256; + let mut verifier = Hmac::::new_from_slice(mac_key) + .expect("Hmac can take any size key"); + verifier.update(input_for_mac); + // XXX: possible timing attack, but we need the bytes for a + // truncated view... + let our_mac = verifier.finalize().into_bytes(); + if &our_mac[..MAC_SIZE] != mac { + return Err(ServiceError::MacError); + } + + use aes::Aes256; + // libsignal-service-java uses Pkcs5, + // but that should not matter. + // https://crypto.stackexchange.com/questions/9043/what-is-the-difference-between-pkcs5-padding-and-pkcs7-padding + use block_modes::{block_padding::Pkcs7, BlockMode, Cbc}; + let cipher = Cbc::::new_from_slices(aes_key, iv) + .expect("initalization of CBC/AES/PKCS7"); + let input = &input[CIPHERTEXT_OFFSET..(input.len() - MAC_SIZE)]; + let input = cipher.decrypt_vec(input).expect("decryption"); + + log::trace!("Envelope::decrypt: decrypted, decoding"); + + Ok(Envelope::decode(&input as &[u8])?) + } + } + + fn new_from_entity(entity: EnvelopeEntity) -> Self { + Envelope { + r#type: Some(entity.r#type), + timestamp: Some(entity.timestamp), + server_timestamp: Some(entity.server_timestamp), + server_guid: entity.source_uuid, + legacy_message: entity.message, + content: entity.content, + ..Default::default() + } + } + + fn new_with_source(entity: EnvelopeEntity, source: ServiceAddress) -> Self { + Envelope { + r#type: Some(entity.r#type), + source_device: Some(entity.source_device), + timestamp: Some(entity.timestamp), + server_timestamp: Some(entity.server_timestamp), + source_e164: source.e164(), + source_uuid: source.uuid.as_ref().map(|s| s.to_string()), + legacy_message: entity.message, + content: entity.content, + ..Default::default() + } + } + + pub fn is_unidentified_sender(&self) -> bool { + self.r#type() == crate::proto::envelope::Type::UnidentifiedSender + } + + pub fn is_prekey_signal_message(&self) -> bool { + self.r#type() == crate::proto::envelope::Type::PrekeyBundle + } + + pub fn is_receipt(&self) -> bool { + self.r#type() == crate::proto::envelope::Type::Receipt + } + + pub fn is_signal_message(&self) -> bool { + self.r#type() == crate::proto::envelope::Type::Ciphertext + } + + pub fn source_address(&self) -> ServiceAddress { + let phonenumber = self + .source_e164 + .as_ref() + .map(|s| phonenumber::parse(None, s)) + .transpose() + .expect("valid e164 checked in constructor"); + + let uuid = self + .source_uuid + .as_deref() + .map(Uuid::parse_str) + .transpose() + .expect("valid e164 checked in constructor"); + ServiceAddress { + phonenumber, + uuid, + relay: self.relay.clone(), + } + } +} + +#[derive(serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct EnvelopeEntity { + pub r#type: i32, + pub relay: String, + pub timestamp: u64, + pub source: Option, + pub source_uuid: Option, + pub source_device: u32, + #[serde(default, with = "serde_optional_base64")] + pub message: Option>, + #[serde(default, with = "serde_optional_base64")] + pub content: Option>, + pub server_timestamp: u64, + pub guid: String, +} + +#[derive(serde::Serialize, serde::Deserialize)] +pub(crate) struct EnvelopeEntityList { + pub messages: Vec, +} + +pub(crate) const SUPPORTED_VERSION: u8 = 1; +pub(crate) const CIPHER_KEY_SIZE: usize = 32; +pub(crate) const MAC_KEY_SIZE: usize = 20; +pub(crate) const MAC_SIZE: usize = 10; + +pub(crate) const VERSION_OFFSET: usize = 0; +pub(crate) const VERSION_LENGTH: usize = 1; +pub(crate) const IV_OFFSET: usize = VERSION_OFFSET + VERSION_LENGTH; +pub(crate) const IV_LENGTH: usize = 16; +pub(crate) const CIPHERTEXT_OFFSET: usize = IV_OFFSET + IV_LENGTH; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn decrypt_envelope() { + // This is a real message, reencrypted with the zero-key. + let body = [ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 32, 12, 100, + 26, 157, 130, 210, 254, 174, 87, 45, 238, 126, 68, 39, 188, 171, + 156, 16, 10, 138, 233, 73, 202, 52, 125, 102, 121, 182, 71, 148, 8, + 3, 134, 149, 154, 67, 116, 40, 146, 253, 242, 196, 139, 203, 14, + 174, 254, 78, 27, 47, 108, 60, 202, 60, 42, 210, 242, 58, 13, 185, + 67, 147, 166, 191, 71, 164, 128, 81, 177, 199, 147, 252, 162, 229, + 143, 98, 141, 222, 46, 83, 109, 82, 196, 109, 161, 40, 108, 207, + 82, 53, 162, 205, 171, 33, 140, 5, 74, 76, 150, 22, 122, 176, 189, + 228, 176, 234, 176, 13, 118, 181, 134, 35, 133, 164, 160, 205, 176, + 32, 188, 185, 166, 73, 24, 164, 20, 187, 2, 226, 186, 238, 98, 57, + 51, 76, 156, 83, 113, 72, 184, 50, 220, 49, 138, 46, 36, 4, 49, + 215, 66, 173, 58, 139, 187, 6, 252, 97, 191, 69, 246, 82, 48, 177, + 11, 149, 168, 93, 15, 170, 125, 131, 101, 103, 253, 177, 165, 71, + 85, 219, 207, 106, 12, 58, 47, 159, 33, 243, 107, 6, 117, 141, 209, + 115, 207, 19, 236, 137, 195, 230, 167, 225, 172, 99, 204, 113, 125, + 69, 125, 97, 252, 90, 248, 198, 175, 240, 187, 246, 164, 220, 102, + 7, 224, 124, 28, 170, 6, 4, 137, 155, 233, 85, 125, 93, 119, 97, + 183, 114, 193, 10, 184, 191, 202, 109, 97, 116, 194, 152, 40, 46, + 202, 49, 195, 138, 14, 2, 255, 44, 107, 160, 45, 150, 6, 78, 145, + 99, + ]; + + let signaling_key = [0u8; 52]; + let _ = Envelope::decrypt(&body, &signaling_key, true).unwrap(); + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/manager.rs b/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/manager.rs new file mode 100644 index 0000000..4ed7c13 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/manager.rs @@ -0,0 +1,230 @@ +use std::{ + collections::HashMap, + time::{SystemTime, UNIX_EPOCH}, +}; + +use crate::{ + configuration::Endpoint, + prelude::{PushService, ServiceError}, + proto::DecryptedGroup, + push_service::{HttpAuth, HttpAuthOverride}, +}; + +use rand::RngCore; +use serde::Deserialize; +use uuid::Uuid; +use zkgroup::{ + auth::AuthCredentialResponse, groups::GroupSecretParams, ServerPublicParams, +}; + +use super::operations::GroupOperations; + +#[derive(Debug, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TemporalCredential { + credential: String, + redemption_time: i64, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CredentialResponse { + credentials: Vec, +} + +impl CredentialResponse { + pub fn parse( + self, + ) -> Result, ServiceError> { + self.credentials + .into_iter() + .map(|c| { + let bytes = base64::decode(c.credential)?; + let data = bincode::deserialize(&bytes)?; + Ok((c.redemption_time, data)) + }) + .collect::>() + } +} + +#[derive(Debug, thiserror::Error)] +pub enum CredentialsCacheError { + #[error("failed to read values from cache: {0}")] + ReadError(String), + #[error("failed to write values from cache: {0}")] + WriteError(String), +} + +/// Global cache for groups v2 credentials, as demonstrated in the libsignal-service +/// java library of Signal-Android. +/// +/// A basic in-memory implementation is provided with `InMemoryCredentialsCache`. +pub trait CredentialsCache { + fn clear(&mut self) -> Result<(), CredentialsCacheError>; + + /// Get an entry of the cache, key usually represents the day number since EPOCH. + fn get( + &self, + key: &i64, + ) -> Result, CredentialsCacheError>; + + /// Overwrite the entire contents of the cache with new data. + fn write( + &mut self, + map: HashMap, + ) -> Result<(), CredentialsCacheError>; +} + +#[derive(Default)] +pub struct InMemoryCredentialsCache { + map: HashMap, +} + +impl CredentialsCache for InMemoryCredentialsCache { + fn clear(&mut self) -> Result<(), CredentialsCacheError> { + self.map.clear(); + Ok(()) + } + + fn get( + &self, + key: &i64, + ) -> Result, CredentialsCacheError> { + Ok(self.map.get(key)) + } + + fn write( + &mut self, + map: HashMap, + ) -> Result<(), CredentialsCacheError> { + self.map = map; + Ok(()) + } +} + +pub struct GroupsManager<'a, S: PushService, C: CredentialsCache> { + push_service: S, + credentials_cache: &'a mut C, + server_public_params: ServerPublicParams, +} + +impl<'a, S: PushService, C: CredentialsCache> GroupsManager<'a, S, C> { + pub fn new( + push_service: S, + credentials_cache: &'a mut C, + server_public_params: ServerPublicParams, + ) -> Self { + Self { + push_service, + credentials_cache, + server_public_params, + } + } + + pub async fn get_authorization_for_today( + &mut self, + uuid: Uuid, + group_secret_params: GroupSecretParams, + ) -> Result { + let today = Self::current_time_days(); + let auth_credential_response = if let Some(auth_credential_response) = + self.credentials_cache.get(&today)? + { + auth_credential_response + } else { + let credentials_map = + self.get_authorization(today).await?.parse()?; + self.credentials_cache.write(credentials_map)?; + self.credentials_cache.get(&today)?.ok_or_else(|| { + ServiceError::ResponseError { + reason: + "credentials received did not contain requested day" + .into(), + } + })? + }; + + self.get_authorization_string( + uuid, + group_secret_params, + auth_credential_response, + today as u32, + ) + } + + async fn get_authorization( + &mut self, + today: i64, + ) -> Result { + let today_plus_7_days = today + 7; + + let path = + format!("/v1/certificate/group/{}/{}", today, today_plus_7_days); + + self.push_service + .get_json(Endpoint::Service, &path, HttpAuthOverride::NoOverride) + .await + } + + fn current_time_days() -> i64 { + let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + let today = chrono::Duration::from_std(now).unwrap(); + today.num_days() + } + + fn get_authorization_string( + &self, + uuid: Uuid, + group_secret_params: GroupSecretParams, + credential_response: &AuthCredentialResponse, + today: u32, + ) -> Result { + let auth_credential = self + .server_public_params + .receive_auth_credential( + *uuid.as_bytes(), + today, + credential_response, + ) + .map_err(|e| { + log::error!("zero-knowledge group error: {:?}", e); + ServiceError::GroupsV2Error + })?; + + let mut random_bytes = [0u8; 32]; + rand::thread_rng().fill_bytes(&mut random_bytes); + + let auth_credential_presentation = self + .server_public_params + .create_auth_credential_presentation( + random_bytes, + group_secret_params, + auth_credential, + ); + + // see simpleapi.rs GroupSecretParams_getPublicParams, everything is bincode encoded + // across the boundary of Rust/Java + let username = hex::encode(bincode::serialize( + &group_secret_params.get_public_params(), + )?); + + let password = + hex::encode(bincode::serialize(&auth_credential_presentation)?); + + Ok(HttpAuth { username, password }) + } + + pub async fn get_group( + &mut self, + group_secret_params: GroupSecretParams, + credentials: HttpAuth, + ) -> Result { + let encrypted_group = self.push_service.get_group(credentials).await?; + let decrypted_group = GroupOperations::decrypt_group( + group_secret_params, + encrypted_group, + )?; + + Ok(decrypted_group) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/mod.rs b/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/mod.rs new file mode 100644 index 0000000..5d96264 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/mod.rs @@ -0,0 +1,10 @@ +//! Everything needed to support [Signal Groups v2](https://signal.org/blog/new-groups/) +mod manager; +mod operations; +pub mod utils; + +pub use manager::{ + CredentialsCache, CredentialsCacheError, GroupsManager, + InMemoryCredentialsCache, +}; +pub use operations::GroupDecryptionError; diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/operations.rs b/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/operations.rs new file mode 100644 index 0000000..9a60efd --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/operations.rs @@ -0,0 +1,229 @@ +use bytes::Bytes; +use prost::Message; +use zkgroup::{ + groups::GroupSecretParams, + profiles::{ProfileKey, ProfileKeyCredentialPresentation}, +}; + +use crate::proto::{ + group_attribute_blob, DecryptedGroup, DecryptedMember, + DecryptedPendingMember, DecryptedRequestingMember, DecryptedTimer, + Group as EncryptedGroup, GroupAttributeBlob, Member as EncryptedMember, + PendingMember as EncryptedPendingMember, + RequestingMember as EncryptedRequestingMember, +}; + +pub(crate) struct GroupOperations { + group_secret_params: GroupSecretParams, +} + +#[derive(Debug, thiserror::Error)] +pub enum GroupDecryptionError { + #[error("zero-knowledge group error")] + ZkGroupError, + #[error(transparent)] + BincodeError(#[from] bincode::Error), + #[error("protobuf message decoding error: {0}")] + ProtobufDecodeError(#[from] prost::DecodeError), + #[error("wrong group attribute blob")] + WrongBlob, +} + +impl From for GroupDecryptionError { + fn from(_: zkgroup::ZkGroupError) -> Self { + GroupDecryptionError::ZkGroupError + } +} + +impl GroupOperations { + fn decrypt_uuid( + &self, + uuid: &[u8], + ) -> Result<[u8; 16], GroupDecryptionError> { + let bytes = self + .group_secret_params + .decrypt_uuid(bincode::deserialize(uuid)?) + .map_err(|_| GroupDecryptionError::ZkGroupError)?; + Ok(bytes) + } + + fn decrypt_profile_key( + &self, + profile_key: &[u8], + decrypted_uuid: [u8; 16], + ) -> Result { + Ok(self.group_secret_params.decrypt_profile_key( + bincode::deserialize(profile_key)?, + decrypted_uuid, + )?) + } + + fn decrypt_member( + &self, + member: EncryptedMember, + ) -> Result { + let (uuid, profile_key) = if member.presentation.is_empty() { + let uuid = self.decrypt_uuid(&member.user_id)?; + let profile_key = + self.decrypt_profile_key(&member.profile_key, uuid)?; + (uuid, profile_key) + } else { + let profile_key_credential_presentation: ProfileKeyCredentialPresentation = bincode::deserialize(&member.presentation)?; + let uuid = self.group_secret_params.decrypt_uuid( + profile_key_credential_presentation.get_uuid_ciphertext(), + )?; + let profile_key = self.group_secret_params.decrypt_profile_key( + profile_key_credential_presentation + .get_profile_key_ciphertext(), + uuid, + )?; + (uuid, profile_key) + }; + Ok(DecryptedMember { + uuid: uuid.to_vec(), + profile_key: bincode::serialize(&profile_key)?, + role: member.role, + joined_at_revision: member.joined_at_revision, + }) + } + + fn decrypt_pending_member( + &self, + member: EncryptedPendingMember, + ) -> Result { + let inner_member = + member.member.ok_or(GroupDecryptionError::WrongBlob)?; + // "Unknown" UUID with zeroes in case of errors, see: UuidUtil.java:16 + let uuid = self.decrypt_uuid(&inner_member.user_id).unwrap_or_default(); + let added_by = self.decrypt_uuid(&member.added_by_user_id)?; + + Ok(DecryptedPendingMember { + uuid: uuid.to_vec(), + role: inner_member.role, + added_by_uuid: added_by.to_vec(), + timestamp: member.timestamp, + uuid_cipher_text: inner_member.user_id, + }) + } + + fn decrypt_requesting_member( + &self, + member: EncryptedRequestingMember, + ) -> Result { + let (uuid, profile_key) = if member.presentation.is_empty() { + let uuid = self.decrypt_uuid(&member.user_id)?; + let profile_key = + self.decrypt_profile_key(&member.profile_key, uuid)?; + (uuid, profile_key) + } else { + let profile_key_credential_presentation: ProfileKeyCredentialPresentation = bincode::deserialize(&member.presentation)?; + let uuid = self.group_secret_params.decrypt_uuid( + profile_key_credential_presentation.get_uuid_ciphertext(), + )?; + let profile_key = self.group_secret_params.decrypt_profile_key( + profile_key_credential_presentation + .get_profile_key_ciphertext(), + uuid, + )?; + (uuid, profile_key) + }; + Ok(DecryptedRequestingMember { + profile_key: bincode::serialize(&profile_key)?, + uuid: uuid.to_vec(), + timestamp: member.timestamp, + }) + } + + fn decrypt_blob(&self, bytes: &[u8]) -> GroupAttributeBlob { + if bytes.is_empty() { + GroupAttributeBlob::default() + } else if bytes.len() < 29 { + log::warn!("bad encrypted blob length"); + GroupAttributeBlob::default() + } else { + self.group_secret_params + .decrypt_blob(bytes) + .map_err(|_| GroupDecryptionError::ZkGroupError) + .and_then(|b| { + GroupAttributeBlob::decode(Bytes::copy_from_slice(&b[4..])) + .map_err(GroupDecryptionError::ProtobufDecodeError) + }) + .unwrap_or_else(|e| { + log::warn!("bad encrypted blob: {}", e); + GroupAttributeBlob::default() + }) + } + } + + fn decrypt_title(&self, ciphertext: &[u8]) -> String { + use group_attribute_blob::Content; + match self.decrypt_blob(ciphertext).content { + Some(Content::Title(title)) => title, + _ => "".into(), // TODO: return an error here? + } + } + + fn decrypt_description(&self, ciphertext: &[u8]) -> String { + use group_attribute_blob::Content; + match self.decrypt_blob(ciphertext).content { + Some(Content::Description(title)) => title, + _ => "".into(), // TODO: return an error here? + } + } + + fn decrypt_disappearing_message_timer( + &self, + ciphertext: &[u8], + ) -> Option { + use group_attribute_blob::Content; + match self.decrypt_blob(ciphertext).content { + Some(Content::DisappearingMessagesDuration(duration)) => { + Some(DecryptedTimer { duration }) + }, + _ => None, + } + } + + pub fn decrypt_group( + group_secret_params: GroupSecretParams, + group: EncryptedGroup, + ) -> Result { + let group_operations = Self { + group_secret_params, + }; + let title = group_operations.decrypt_title(&group.title); + let description = + group_operations.decrypt_description(&group.description); + let disappearing_messages_timer = group_operations + .decrypt_disappearing_message_timer( + &group.disappearing_messages_timer, + ); + let members = group + .members + .into_iter() + .map(|m| group_operations.decrypt_member(m)) + .collect::>()?; + let pending_members = group + .pending_members + .into_iter() + .map(|m| group_operations.decrypt_pending_member(m)) + .collect::>()?; + let requesting_members = group + .requesting_members + .into_iter() + .map(|m| group_operations.decrypt_requesting_member(m)) + .collect::>()?; + Ok(DecryptedGroup { + title, + avatar: group.avatar, + disappearing_messages_timer, + access_control: group.access_control, + revision: group.revision, + members, + pending_members, + requesting_members, + invite_link_password: group.invite_link_password, + description, + }) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/utils.rs b/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/utils.rs new file mode 100644 index 0000000..c731236 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/groups_v2/utils.rs @@ -0,0 +1,18 @@ +use libsignal_protocol::error::SignalProtocolError; +use zkgroup::groups::GroupMasterKey; +use zkgroup::GROUP_MASTER_KEY_LEN; + +/// Given a 16-byte GroupV1 ID, derive the migration key. +/// +/// Panics if the group_id is not 16 bytes long. +pub fn derive_v2_migration_master_key( + group_id: &[u8], +) -> Result { + assert_eq!(group_id.len(), 16, "Group ID must be exactly 16 bytes"); + + let mut bytes = [0; GROUP_MASTER_KEY_LEN]; + hkdf::Hkdf::::new(None, group_id) + .expand(b"GV2 Migration", &mut bytes) + .expect("valid output length"); + Ok(GroupMasterKey::new(bytes)) +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/kat.bin.rs b/net/gurk-rs/files/vendor/libsignal-service/src/kat.bin.rs new file mode 100644 index 0000000..71f9c5b --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/kat.bin.rs @@ -0,0 +1,44 @@ +vec![ + 49, 179, 68, 75, 164, 216, 109, 15, 131, 54, 38, 23, 120, 221, 36, + 66, 191, 65, 137, 85, 175, 13, 209, 217, 219, 46, 103, 95, 73, 181, + 31, 75, 36, 113, 103, 0, 91, 81, 71, 168, 66, 209, 100, 66, 80, + 157, 170, 63, 118, 175, 214, 201, 135, 71, 166, 8, 152, 129, 220, + 68, 248, 127, 66, 144, 215, 43, 80, 230, 254, 233, 27, 71, 111, 61, + 131, 101, 197, 107, 52, 12, 241, 100, 29, 117, 200, 115, 243, 113, + 86, 86, 232, 161, 147, 61, 213, 221, 177, 148, 118, 202, 208, 184, + 251, 213, 21, 255, 54, 49, 51, 197, 45, 216, 236, 77, 197, 218, + 178, 56, 219, 246, 136, 24, 100, 173, 178, 74, 184, 92, 239, 181, + 95, 91, 7, 128, 37, 205, 19, 152, 167, 46, 10, 151, 235, 168, 2, + 247, 79, 33, 252, 139, 191, 98, 40, 201, 232, 43, 54, 228, 234, + 241, 94, 157, 59, 196, 25, 15, 94, 38, 247, 203, 66, 196, 71, 166, + 196, 58, 193, 13, 139, 141, 171, 86, 187, 44, 144, 22, 89, 143, + 100, 193, 190, 161, 227, 29, 109, 68, 176, 194, 73, 169, 135, 200, + 208, 235, 99, 173, 45, 149, 116, 197, 76, 113, 198, 178, 118, 164, + 189, 135, 52, 223, 92, 229, 169, 227, 89, 58, 10, 238, 124, 46, + 175, 183, 73, 57, 140, 79, 252, 76, 170, 217, 199, 165, 204, 44, + 114, 114, 240, 207, 249, 205, 0, 22, 167, 167, 136, 173, 220, 250, + 109, 136, 124, 232, 26, 204, 146, 151, 232, 130, 151, 43, 16, 119, + 77, 246, 96, 38, 81, 13, 2, 151, 147, 76, 32, 79, 80, 23, 181, 6, + 188, 254, 24, 9, 139, 238, 141, 224, 215, 160, 133, 179, 131, 153, + 121, 72, 165, 204, 50, 86, 248, 209, 90, 46, 100, 197, 86, 230, + 124, 151, 167, 218, 236, 77, 188, 153, 255, 33, 237, 97, 194, 193, + 153, 149, 221, 35, 22, 114, 43, 64, 110, 204, 241, 176, 6, 168, 25, + 46, 166, 10, 242, 26, 130, 97, 236, 255, 166, 75, 222, 205, 25, + 212, 114, 203, 10, 242, 220, 230, 81, 3, 226, 233, 35, 1, 42, 11, + 25, 35, 83, 188, 38, 215, 191, 78, 72, 85, 51, 32, 219, 104, 135, + 79, 35, 152, 62, 138, 243, 181, 57, 222, 246, 45, 164, 134, 60, + 162, 177, 220, 218, 58, 52, 148, 8, 177, 119, 69, 6, 5, 253, 20, + 56, 50, 100, 161, 89, 145, 91, 119, 16, 24, 231, 76, 120, 96, 183, + 63, 87, 117, 12, 126, 50, 205, 89, 42, 107, 115, 64, 147, 180, 164, + 208, 173, 15, 241, 128, 130, 205, 199, 52, 31, 176, 77, 197, 149, + 114, 115, 197, 22, 214, 30, 243, 246, 204, 10, 178, 124, 225, 249, + 44, 18, 143, 243, 178, 46, 166, 61, 174, 136, 155, 61, 228, 59, + 219, 242, 240, 121, 15, 131, 163, 94, 79, 173, 198, 9, 110, 64, + 222, 32, 234, 172, 29, 10, 158, 114, 53, 161, 200, 144, 174, 161, + 180, 34, 245, 51, 44, 139, 138, 168, 231, 139, 105, 126, 5, 143, + 83, 186, 101, 66, 19, 1, 15, 129, 173, 239, 102, 150, 97, 189, 191, + 128, 136, 183, 242, 163, 137, 146, 134, 133, 72, 81, 243, 245, 100, + 115, 70, 27, 98, 227, 146, 35, 198, 3, 35, 236, 236, 104, 103, 100, + 148, 183, 133, 25, 37, 224, 29, 234, 248, 26, 209, 199, 34, 52, 82, + 167, +] diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/lib.rs b/net/gurk-rs/files/vendor/libsignal-service/src/lib.rs new file mode 100644 index 0000000..d2a6b29 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/lib.rs @@ -0,0 +1,93 @@ +#![recursion_limit = "256"] +#![deny(clippy::dbg_macro)] + +mod account_manager; +pub mod attachment_cipher; +pub mod cipher; +pub mod profile_cipher; +pub mod sealed_session_cipher; + +pub mod configuration; +pub mod content; +mod digeststream; +pub mod envelope; +pub mod groups_v2; +pub mod messagepipe; +pub mod models; +pub mod pre_keys; +pub mod profile_name; +pub mod proto; +pub mod provisioning; +pub mod push_service; +pub mod receiver; +pub mod sender; +pub mod service_address; +mod session_store; +pub mod utils; + +pub use crate::account_manager::{ + AccountManager, Profile, ProfileManagerError, +}; +pub use crate::service_address::*; + +pub const USER_AGENT: &str = + concat!(env!("CARGO_PKG_NAME"), "-rs-", env!("CARGO_PKG_VERSION")); + +/// GROUP_UPDATE_FLAG signals that this message updates the group membership or +/// name. +pub const GROUP_UPDATE_FLAG: u32 = 1; + +/// GROUP_LEAVE_FLAG signals that this message is a group leave message. +pub const GROUP_LEAVE_FLAG: u32 = 2; + +/// This trait allows for the conditional support of Send compatible futures +/// depending on whether or not the `unsend-futures` feature flag is enabled. +/// As this feature is disabled by default, Send is supported by default. +/// +/// This is necessary as actix does not support Send, which means unconditionally +/// imposing this requirement would break libsignal-service-actix. +/// +/// Conversely, hyper does support Send, which is why libsignal-service-hyper +/// does not enable the `unsend-futures` feature flag. +#[cfg(not(feature = "unsend-futures"))] +pub trait MaybeSend: Send {} +#[cfg(not(feature = "unsend-futures"))] +impl MaybeSend for T where T: Send {} + +#[cfg(feature = "unsend-futures")] +pub trait MaybeSend {} +#[cfg(feature = "unsend-futures")] +impl MaybeSend for T {} + +pub mod prelude { + pub use super::ServiceAddress; + pub use crate::{ + cipher::ServiceCipher, + configuration::{ + ServiceConfiguration, ServiceCredentials, SignalingKey, + }, + content::Content, + envelope::Envelope, + proto::{ + attachment_pointer::AttachmentIdentifier, sync_message::Contacts, + AttachmentPointer, + }, + push_service::{PushService, ServiceError}, + receiver::MessageReceiver, + sender::{MessageSender, MessageSenderError}, + }; + pub use phonenumber; + pub use prost::Message as ProtobufMessage; + pub use uuid::{Error as UuidError, Uuid}; + pub use zkgroup::groups::{GroupMasterKey, GroupSecretParams}; + + pub mod protocol { + pub use crate::session_store::SessionStoreExt; + pub use libsignal_protocol::{ + Context, Direction, IdentityKey, IdentityKeyPair, IdentityKeyStore, + KeyPair, PreKeyRecord, PreKeyStore, PrivateKey, ProtocolAddress, + PublicKey, SessionRecord, SessionStore, SignalProtocolError, + SignedPreKeyRecord, SignedPreKeyStore, + }; + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/messagepipe.rs b/net/gurk-rs/files/vendor/libsignal-service/src/messagepipe.rs new file mode 100644 index 0000000..e1d332a --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/messagepipe.rs @@ -0,0 +1,306 @@ +use std::collections::HashMap; + +use bytes::Bytes; +use futures::{ + channel::{ + mpsc::{self, Sender}, + oneshot, + }, + prelude::*, + stream::{FusedStream, FuturesUnordered}, +}; +use pin_project::pin_project; +use prost::Message; + +pub use crate::{ + configuration::ServiceCredentials, + proto::{ + web_socket_message, Envelope, WebSocketMessage, + WebSocketRequestMessage, WebSocketResponseMessage, + }, +}; + +use crate::push_service::ServiceError; + +pub enum WebSocketStreamItem { + Message(Bytes), + KeepAliveRequest, +} + +#[cfg_attr(feature = "unsend-futures", async_trait::async_trait(?Send))] +#[cfg_attr(not(feature = "unsend-futures"), async_trait::async_trait)] +pub trait WebSocketService { + type Stream: FusedStream + Unpin; + + async fn send_message(&mut self, msg: Bytes) -> Result<(), ServiceError>; +} + +#[pin_project] +pub struct MessagePipe { + ws: WS, + #[pin] + stream: WS::Stream, + credentials: ServiceCredentials, + requests: HashMap>, +} + +impl MessagePipe { + pub fn from_socket( + ws: WS, + stream: WS::Stream, + credentials: ServiceCredentials, + ) -> Self { + MessagePipe { + ws, + stream, + credentials, + requests: HashMap::new(), + } + } + + async fn send_response( + &mut self, + r: WebSocketResponseMessage, + ) -> Result<(), ServiceError> { + let msg = WebSocketMessage { + r#type: Some(web_socket_message::Type::Response.into()), + response: Some(r), + ..Default::default() + }; + let buffer = msg.encode_to_vec(); + self.ws.send_message(buffer.into()).await + } + + /// Sends a request without returning a response. + async fn transmit_request( + &mut self, + r: WebSocketRequestMessage, + ) -> Result<(), ServiceError> { + log::trace!("Sending request {:?}", r); + let msg = WebSocketMessage { + r#type: Some(web_socket_message::Type::Request.into()), + request: Some(r), + ..Default::default() + }; + let buffer = msg.encode_to_vec(); + self.ws.send_message(buffer.into()).await?; + log::trace!("request on route."); + Ok(()) + } + + /// Send request and returns the response as a *nested* Future. + /// + /// The outer Future sends the request, the inner Future resolves to the + /// response. + pub async fn send_request( + &mut self, + r: WebSocketRequestMessage, + ) -> Result< + impl Future>, + ServiceError, + > { + let id = r.id; + + self.transmit_request(r).await?; + + let (sink, send) = oneshot::channel(); + + if let Some(id) = id { + self.requests.insert(id, sink); + Ok(send.map_err(|_| ServiceError::WsClosing { + reason: "WebSocket closing while sending request.".into(), + })) + } else { + Err(ServiceError::InvalidFrameError { + reason: "Send request without ID".into(), + }) + } + } + + /// Worker task that + async fn run( + mut self, + mut sink: Sender>, + ) -> Result<(), mpsc::SendError> { + use futures::future::LocalBoxFuture; + + // This is a runtime-agnostic, poor man's `::spawn(Future)`. + let mut background_work = FuturesUnordered::>::new(); + // a pending task is added, as to never end the background worker until + // it's dropped. + background_work.push(futures::future::pending().boxed_local()); + + loop { + futures::select! { + // WebsocketConnection::onMessage(ByteString) + frame = self.stream.next() => match frame { + Some(WebSocketStreamItem::Message(frame)) => { + let env = self.process_frame(frame).await.transpose(); + if let Some(env) = env { + sink.send(env).await?; + } + }, + Some(WebSocketStreamItem::KeepAliveRequest) => { + let request = self.send_keep_alive().await; + match request { + Ok(request) => { + let request = request.map(|response| { + if let Err(e) = response { + log::warn!("Error from keep alive: {:?}", e); + } + }); + background_work.push(request.boxed_local()); + }, + Err(e) => log::warn!("Could not send keep alive: {}", e), + } + }, + None => { + log::debug!("WebSocket stream ended."); + break; + }, + }, + _ = background_work.next() => { + // no op + }, + complete => { + log::info!("select! complete"); + } + } + } + + Ok(()) + } + + async fn send_keep_alive( + &mut self, + ) -> Result>, ServiceError> + { + let request = WebSocketRequestMessage { + id: Some( + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_millis() as u64, + ), + path: Some("/v1/keepalive".into()), + verb: Some("GET".into()), + ..Default::default() + }; + let request = self.send_request(request).await?; + Ok(async move { + let response = request.await?; + if response.status() == 200 { + Ok(()) + } else { + log::warn!( + "Response code for keep-alive is not 200: {:?}", + response + ); + Err(ServiceError::UnhandledResponseCode { + http_code: response.status() as u16, + }) + } + }) + } + + async fn process_frame( + &mut self, + frame: Bytes, + ) -> Result, ServiceError> { + let msg = WebSocketMessage::decode(frame)?; + log::trace!("Decoded {:?}", msg); + + use web_socket_message::Type; + match (msg.r#type(), msg.request, msg.response) { + (Type::Unknown, _, _) => Err(ServiceError::InvalidFrameError { + reason: "Unknown frame type".into(), + }), + (Type::Request, Some(request), _) => { + // Java: MessagePipe::read + let response = WebSocketResponseMessage::from_request(&request); + + let result = if request.is_signal_service_envelope() { + let body = if let Some(body) = request.body.as_ref() { + body + } else { + return Err(ServiceError::InvalidFrameError { + reason: "Request without body.".into(), + }); + }; + Some(Envelope::decrypt( + body, + self.credentials.signaling_key.as_ref().expect( + "signaling_key required to decrypt envelopes", + ), + request.is_signal_key_encrypted(), + )?) + } else { + None + }; + + if let Err(e) = self.send_response(response).await { + log::error!("Could not send response: {}", e); + } + + Ok(result) + }, + (Type::Request, None, _) => Err(ServiceError::InvalidFrameError { + reason: "Type was request, but does not contain request." + .into(), + }), + (Type::Response, _, Some(response)) => { + if let Some(id) = response.id { + if let Some(responder) = self.requests.remove(&id) { + if let Err(e) = responder.send(response) { + log::warn!( + "Could not deliver response for id {}: {:?}", + id, + e + ); + } + } else { + log::warn!( + "Response for non existing request: {:?}", + response + ); + } + } + + Ok(None) + }, + (Type::Response, _, None) => Err(ServiceError::InvalidFrameError { + reason: "Type was response, but does not contain response." + .into(), + }), + } + } + + /// Returns the stream of `Envelope`s + /// + /// Envelopes yielded are acknowledged. + pub fn stream(self) -> impl Stream> { + let (sink, stream) = mpsc::channel(1); + + let stream = stream.map(Some); + let runner = self.run(sink).map(|e| { + log::info!("Sink was closed. Reason: {:?}", e); + None + }); + + let combined = futures::stream::select(stream, runner.into_stream()); + combined.filter_map(|x| async { x }) + } +} + +/// WebSocketService that panics on every request, mainly for example code. +pub struct PanicingWebSocketService; + +#[cfg_attr(feature = "unsend-futures", async_trait::async_trait(?Send))] +#[cfg_attr(not(feature = "unsend-futures"), async_trait::async_trait)] +impl WebSocketService for PanicingWebSocketService { + type Stream = futures::channel::mpsc::Receiver; + + async fn send_message(&mut self, _msg: Bytes) -> Result<(), ServiceError> { + unimplemented!(); + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/models.rs b/net/gurk-rs/files/vendor/libsignal-service/src/models.rs new file mode 100644 index 0000000..5246841 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/models.rs @@ -0,0 +1,78 @@ +use crate::{proto::Verified, ParseServiceAddressError, ServiceAddress}; + +use bytes::Bytes; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +/// Attachment represents an attachment received from a peer +#[derive(Debug, Serialize, Deserialize)] +pub struct Attachment { + pub content_type: String, + pub reader: R, +} + +/// Mirror of the protobuf ContactDetails message +/// but with stronger types (e.g. `ServiceAddress` instead of optional uuid and string phone numbers) +/// and some helper functions +#[derive(Debug, Serialize, Deserialize)] +pub struct Contact { + pub address: ServiceAddress, + pub name: String, + pub color: Option, + #[serde(skip)] + pub verified: Verified, + pub profile_key: Vec, + pub blocked: bool, + pub expire_timer: u32, + pub inbox_position: u32, + pub archived: bool, + #[serde(skip)] + pub avatar: Option>, +} + +#[derive(Error, Debug)] +pub enum ParseContactError { + #[error(transparent)] + ProtobufError(#[from] prost::DecodeError), + #[error(transparent)] + ServiceAddress(#[from] ParseServiceAddressError), + #[error("missing profile key")] + MissingProfileKey, + #[error("missing avatar content-type")] + MissingAvatarContentType, +} + +impl Contact { + pub fn from_proto( + contact_details: crate::proto::ContactDetails, + avatar_data: Option, + ) -> Result { + Ok(Self { + address: ServiceAddress::parse( + contact_details.number.as_deref(), + contact_details.uuid.as_deref(), + )?, + name: contact_details.name().into(), + color: contact_details.color.clone(), + verified: contact_details.verified.clone().unwrap_or_default(), + profile_key: contact_details.profile_key().to_vec(), + blocked: contact_details.blocked(), + expire_timer: contact_details.expire_timer(), + inbox_position: contact_details.inbox_position(), + archived: contact_details.archived(), + avatar: contact_details.avatar.and_then(|avatar| { + if let (Some(content_type), Some(avatar_data)) = + (avatar.content_type, avatar_data) + { + Some(Attachment { + content_type, + reader: avatar_data, + }) + } else { + log::warn!("missing avatar content-type, skipping."); + None + } + }), + }) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/pre_keys.rs b/net/gurk-rs/files/vendor/libsignal-service/src/pre_keys.rs new file mode 100644 index 0000000..5ed0aed --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/pre_keys.rs @@ -0,0 +1,70 @@ +use std::convert::TryFrom; + +use crate::utils::{serde_base64, serde_public_key}; +use libsignal_protocol::{ + error::SignalProtocolError, PreKeyRecord, PublicKey, SignedPreKeyRecord, +}; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PreKeyEntity { + pub key_id: u32, + #[serde(with = "serde_base64")] + pub public_key: Vec, +} + +impl TryFrom for PreKeyEntity { + type Error = SignalProtocolError; + + fn try_from(key: PreKeyRecord) -> Result { + Ok(PreKeyEntity { + key_id: key.id()?, + public_key: key.key_pair()?.public_key.serialize().to_vec(), + }) + } +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SignedPreKeyEntity { + pub key_id: u32, + #[serde(with = "serde_base64")] + pub public_key: Vec, + #[serde(with = "serde_base64")] + pub signature: Vec, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignedPreKey { + key_id: u32, + #[serde(with = "serde_public_key")] + public_key: PublicKey, + #[serde(with = "serde_base64")] + signature: Vec, +} + +impl TryFrom for SignedPreKey { + type Error = SignalProtocolError; + + fn try_from(key: SignedPreKeyRecord) -> Result { + Ok(SignedPreKey { + key_id: key.id()?, + public_key: key.key_pair()?.public_key, + signature: key.signature()?, + }) + } +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PreKeyState { + pub pre_keys: Vec, + pub signed_pre_key: SignedPreKey, + #[serde(with = "serde_public_key")] + pub identity_key: PublicKey, + #[serde(skip_serializing_if = "Option::is_none")] + pub last_resort_key: Option, +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/profile_cipher.rs b/net/gurk-rs/files/vendor/libsignal-service/src/profile_cipher.rs new file mode 100644 index 0000000..413c359 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/profile_cipher.rs @@ -0,0 +1,276 @@ +use aes_gcm::{ + aead::{ + generic_array::typenum::U32, generic_array::GenericArray, Aead, + AeadInPlace, + }, + Aes256Gcm, NewAead, +}; +use rand::Rng; +use zkgroup::profiles::ProfileKey; + +use crate::profile_name::ProfileName; + +/// Encrypt and decrypt a [`ProfileName`] and other profile information. +/// +/// # Example +/// +/// ```rust +/// # use libsignal_service::{profile_name::ProfileName, profile_cipher::ProfileCipher}; +/// # use zkgroup::profiles::ProfileKey; +/// # use rand::Rng; +/// # let mut rng = rand::thread_rng(); +/// # let some_randomness = rng.gen(); +/// let profile_key = ProfileKey::generate(some_randomness); +/// let name = ProfileName::<&str> { +/// given_name: "Bill", +/// family_name: None, +/// }; +/// let cipher = ProfileCipher::from(profile_key); +/// let encrypted = cipher.encrypt_name(&name).unwrap(); +/// let decrypted = cipher.decrypt_name(&encrypted).unwrap().unwrap(); +/// assert_eq!(decrypted.as_ref(), name); +/// ``` +pub struct ProfileCipher { + profile_key: ProfileKey, +} + +impl From for ProfileCipher { + fn from(profile_key: ProfileKey) -> Self { + ProfileCipher { profile_key } + } +} + +const NAME_PADDED_LENGTH_1: usize = 53; +const NAME_PADDED_LENGTH_2: usize = 257; +const NAME_PADDING_BRACKETS: &[usize] = + &[NAME_PADDED_LENGTH_1, NAME_PADDED_LENGTH_2]; + +const ABOUT_PADDED_LENGTH_1: usize = 128; +const ABOUT_PADDED_LENGTH_2: usize = 254; +const ABOUT_PADDED_LENGTH_3: usize = 512; +const ABOUT_PADDING_BRACKETS: &[usize] = &[ + ABOUT_PADDED_LENGTH_1, + ABOUT_PADDED_LENGTH_2, + ABOUT_PADDED_LENGTH_3, +]; + +const EMOJI_PADDED_LENGTH: usize = 32; + +#[derive(thiserror::Error, Debug)] +pub enum ProfileCipherError { + #[error("Encryption error")] + EncryptionError, + #[error("UTF-8 decode error {0}")] + Utf8Error(#[from] std::str::Utf8Error), + #[error("Input name too long")] + InputTooLong, +} + +fn pad_plaintext( + bytes: &mut Vec, + brackets: &[usize], +) -> Result { + let len = brackets + .iter() + .find(|x| **x >= bytes.len()) + .ok_or(ProfileCipherError::InputTooLong)?; + let len: usize = *len; + + bytes.resize(len, 0); + assert!(brackets.contains(&bytes.len())); + + Ok(len) +} + +impl ProfileCipher { + pub fn into_inner(self) -> ProfileKey { + self.profile_key + } + + fn get_key(&self) -> GenericArray { + GenericArray::from(self.profile_key.get_bytes()) + } + + fn pad_and_encrypt( + &self, + mut bytes: Vec, + padding_brackets: &[usize], + ) -> Result, ProfileCipherError> { + let _len = pad_plaintext(&mut bytes, padding_brackets)?; + + let cipher = Aes256Gcm::new(&self.get_key()); + let nonce: [u8; 12] = rand::thread_rng().gen(); + let nonce = GenericArray::from_slice(&nonce); + + cipher + .encrypt_in_place(nonce, b"", &mut bytes) + .map_err(|_| ProfileCipherError::EncryptionError)?; + + let mut concat = Vec::with_capacity(nonce.len() + bytes.len()); + concat.extend_from_slice(nonce); + concat.extend_from_slice(&bytes); + Ok(concat) + } + + fn decrypt_and_unpad( + &self, + bytes: Vec, + ) -> Result, ProfileCipherError> { + let nonce = GenericArray::from_slice(&bytes[0..12]); + let cipher = Aes256Gcm::new(&self.get_key()); + + let mut plaintext = cipher + .decrypt(nonce, &bytes[12..]) + .map_err(|_| ProfileCipherError::EncryptionError)?; + + // Unpad + let len = plaintext + .iter() + // Search the first non-0 char... + .rposition(|x| *x != 0) + // ...and strip until right after. + .map(|x| x + 1) + // If it's all zeroes, the string is 0-length. + .unwrap_or(0); + plaintext.truncate(len); + Ok(plaintext) + } + + pub fn encrypt_name<'inp>( + &self, + name: impl std::borrow::Borrow>, + ) -> Result, ProfileCipherError> { + let name = name.borrow(); + let bytes = name.serialize(); + self.pad_and_encrypt(bytes, NAME_PADDING_BRACKETS) + } + + pub fn decrypt_name( + &self, + bytes: impl AsRef<[u8]>, + ) -> Result>, ProfileCipherError> { + let bytes = bytes.as_ref(); + + let plaintext = self.decrypt_and_unpad(bytes.into())?; + + Ok(ProfileName::::deserialize(&plaintext)?) + } + + pub fn encrypt_about( + &self, + about: String, + ) -> Result, ProfileCipherError> { + let bytes = about.into_bytes(); + self.pad_and_encrypt(bytes, ABOUT_PADDING_BRACKETS) + } + + pub fn decrypt_about( + &self, + bytes: impl AsRef<[u8]>, + ) -> Result { + let bytes = bytes.as_ref(); + + let plaintext = self.decrypt_and_unpad(bytes.into())?; + + // XXX This re-allocates. + Ok(std::str::from_utf8(&plaintext)?.into()) + } + + pub fn encrypt_emoji( + &self, + emoji: String, + ) -> Result, ProfileCipherError> { + let bytes = emoji.into_bytes(); + self.pad_and_encrypt(bytes, &[EMOJI_PADDED_LENGTH]) + } + + pub fn decrypt_emoji( + &self, + bytes: impl AsRef<[u8]>, + ) -> Result { + let bytes = bytes.as_ref(); + + let plaintext = self.decrypt_and_unpad(bytes.into())?; + + // XXX This re-allocates. + Ok(std::str::from_utf8(&plaintext)?.into()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::profile_name::ProfileName; + use rand::Rng; + use zkgroup::profiles::ProfileKey; + + #[test] + fn roundtrip_name() { + let names = [ + "Me and my guitar", // shorter that 53 + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", // one shorter than 53 + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzx", // exactly 53 + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzxf", // one more than 53 + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzxfoobar", // a bit more than 53 + ]; + + // Test the test cases + assert_eq!(names[1].len(), NAME_PADDED_LENGTH_1 - 1); + assert_eq!(names[2].len(), NAME_PADDED_LENGTH_1); + assert_eq!(names[3].len(), NAME_PADDED_LENGTH_1 + 1); + + let mut rng = rand::thread_rng(); + let some_randomness = rng.gen(); + let profile_key = ProfileKey::generate(some_randomness); + let cipher = ProfileCipher::from(profile_key); + for name in &names { + let profile_name = ProfileName::<&str> { + given_name: name, + family_name: None, + }; + assert_eq!(profile_name.serialize().len(), name.len()); + let encrypted = cipher.encrypt_name(&profile_name).unwrap(); + let decrypted = cipher.decrypt_name(&encrypted).unwrap().unwrap(); + + assert_eq!(decrypted.as_ref(), profile_name); + assert_eq!(decrypted.serialize(), profile_name.serialize()); + assert_eq!(&decrypted.given_name, name); + } + } + + #[test] + fn roundtrip_about() { + let abouts = [ + "Me and my guitar", // shorter that 53 + ]; + + let mut rng = rand::thread_rng(); + let some_randomness = rng.gen(); + let profile_key = ProfileKey::generate(some_randomness); + let cipher = ProfileCipher::from(profile_key); + + for &about in &abouts { + let encrypted = cipher.encrypt_about(about.into()).unwrap(); + let decrypted = cipher.decrypt_about(&encrypted).unwrap(); + + assert_eq!(decrypted, about); + } + } + + #[test] + fn roundtrip_emoji() { + let emojii = ["❤️", "💩", "🤣", "😲", "🐠"]; + + let mut rng = rand::thread_rng(); + let some_randomness = rng.gen(); + let profile_key = ProfileKey::generate(some_randomness); + let cipher = ProfileCipher::from(profile_key); + + for &emoji in &emojii { + let encrypted = cipher.encrypt_emoji(emoji.into()).unwrap(); + let decrypted = cipher.decrypt_emoji(&encrypted).unwrap(); + + assert_eq!(decrypted, emoji); + } + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/profile_name.rs b/net/gurk-rs/files/vendor/libsignal-service/src/profile_name.rs new file mode 100644 index 0000000..bc06706 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/profile_name.rs @@ -0,0 +1,106 @@ +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct ProfileName { + pub given_name: S, + pub family_name: Option, +} + +impl> ProfileName { + pub fn as_ref(&self) -> ProfileName<&str> { + ProfileName { + given_name: self.given_name.as_ref(), + family_name: self.family_name.as_ref().map(|x| x.as_ref()), + } + } + + pub fn serialize(&self) -> Vec { + if let Some(family_name) = self.family_name.as_ref() { + self.given_name + .as_ref() + .as_bytes() + .iter() + .chain(std::iter::once(&0u8)) + .chain(family_name.as_ref().as_bytes()) + .copied() + .collect() + } else { + self.given_name.as_ref().as_bytes().into() + } + } + + pub fn is_empty(&self) -> bool { + self.given_name.as_ref() == "" && self.family_name.is_none() + } +} + +impl ProfileName { + /// Copying deserialization of a ProfileName. + pub fn deserialize( + data: &[u8], + ) -> Result, std::str::Utf8Error> { + let parts: Vec<&[u8]> = data.split(|x| *x == 0).collect(); + match parts.len() { + 0 => Ok(None), + 1 => Ok(Some(Self { + given_name: std::str::from_utf8(parts[0])?.to_string(), + family_name: None, + })), + _ => Ok(Some(Self { + given_name: std::str::from_utf8(parts[0])?.to_string(), + family_name: Some(std::str::from_utf8(parts[1])?.to_string()), + })), + } + } +} + +impl<'de> ProfileName<&'de str> { + pub fn empty() -> Self { + ProfileName { + given_name: "", + family_name: None, + } + } + + /// Zero-copy deserialization of a ProfileName. + pub fn deserialize<'inp: 'de>( + data: &'inp [u8], + ) -> Result, std::str::Utf8Error> { + let parts: Vec<&[u8]> = data.split(|x| *x == 0).collect(); + match parts.len() { + 0 => Ok(None), + 1 => Ok(Some(Self { + given_name: std::str::from_utf8(parts[0])?, + family_name: None, + })), + _ => Ok(Some(Self { + given_name: std::str::from_utf8(parts[0])?, + family_name: Some(std::str::from_utf8(parts[1])?), + })), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn roundtrip_name() { + let names = [ + ("foo", Some("bar")), + ("foo", None), + ("", None), + ("", Some("bar")), + ]; + + for &(given_name, family_name) in &names { + let uut_name = ProfileName::<&str> { + given_name, + family_name, + }; + let ser = uut_name.serialize(); + let deserialized = + ProfileName::<&str>::deserialize(&ser).expect("utf8"); + assert_eq!(Some(uut_name), deserialized); + } + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/proto.rs b/net/gurk-rs/files/vendor/libsignal-service/src/proto.rs new file mode 100644 index 0000000..a65befc --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/proto.rs @@ -0,0 +1,61 @@ +include!(concat!(env!("OUT_DIR"), "/signalservice.rs")); +include!(concat!(env!("OUT_DIR"), "/signal.rs")); + +impl WebSocketRequestMessage { + /// Equivalent of + /// `SignalServiceMessagePipe::isSignalServiceEnvelope(WebSocketMessage)`. + pub fn is_signal_service_envelope(&self) -> bool { + self.verb.as_deref() == Some("PUT") + && self.path.as_deref() == Some("/api/v1/message") + } + + /// Equivalent of + /// `SignalServiceMessagePipe::isSignalKeyEncrypted(WebSocketMessage)`. + pub fn is_signal_key_encrypted(&self) -> bool { + if self.headers.is_empty() { + return true; + } + + for header in &self.headers { + let parts: Vec<_> = header.split(':').collect(); + if parts.len() != 2 { + log::warn!( + "Got a weird header: {:?}, split in {:?}", + header, + parts + ); + continue; + } + + if parts[0].trim().eq_ignore_ascii_case("X-Signal-Key") + && parts[1].trim().eq_ignore_ascii_case("false") + { + return false; + } + } + + true + } +} + +impl WebSocketResponseMessage { + /// Equivalent of + /// `SignalServiceMessagePipe::isSignalServiceEnvelope(WebSocketMessage)`. + pub fn from_request(msg: &WebSocketRequestMessage) -> Self { + if msg.is_signal_service_envelope() { + WebSocketResponseMessage { + id: msg.id, + status: Some(200), + message: Some("OK".to_string()), + ..Default::default() + } + } else { + WebSocketResponseMessage { + id: msg.id, + status: Some(400), + message: Some("Unknown".to_string()), + ..Default::default() + } + } + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/cipher.rs b/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/cipher.rs new file mode 100644 index 0000000..9aa5b9a --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/cipher.rs @@ -0,0 +1,221 @@ +use std::fmt::{self, Debug}; + +use aes::Aes256; +use block_modes::{block_padding::Pkcs7, BlockMode, Cbc}; +use bytes::Bytes; +use hmac::{Hmac, Mac, NewMac}; +use libsignal_protocol::{KeyPair, PublicKey}; +use prost::Message; +use rand::Rng; +use sha2::Sha256; + +pub use crate::proto::{ + ProvisionEnvelope, ProvisionMessage, ProvisioningVersion, +}; + +use crate::{ + envelope::{CIPHER_KEY_SIZE, IV_LENGTH, IV_OFFSET}, + provisioning::ProvisioningError, +}; + +enum CipherMode { + DecryptAndEncrypt(KeyPair), + EncryptOnly(PublicKey), +} + +impl Debug for CipherMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + match self { + CipherMode::DecryptAndEncrypt(key_pair) => f + .debug_tuple("CipherMode::DecryptAndEncrypt") + .field(&key_pair.public_key) + .finish(), + CipherMode::EncryptOnly(public) => f + .debug_tuple("CipherMode::EncryptOnly") + .field(&public) + .finish(), + } + } +} + +impl CipherMode { + fn public(&self) -> &PublicKey { + match self { + CipherMode::DecryptAndEncrypt(pair) => &pair.public_key, + CipherMode::EncryptOnly(pub_key) => pub_key, + } + } +} + +const VERSION: u8 = 1; + +#[derive(Debug)] +pub struct ProvisioningCipher { + key_material: CipherMode, +} + +impl ProvisioningCipher { + /// Generate a random key pair + pub fn generate(rng: &mut R) -> Result + where + R: rand::Rng + rand::CryptoRng, + { + let key_pair = libsignal_protocol::KeyPair::generate(rng); + Ok(Self { + key_material: CipherMode::DecryptAndEncrypt(key_pair), + }) + } + + pub fn from_public(key: PublicKey) -> Self { + Self { + key_material: CipherMode::EncryptOnly(key), + } + } + + pub fn from_key_pair(key_pair: KeyPair) -> Self { + Self { + key_material: CipherMode::DecryptAndEncrypt(key_pair), + } + } + + pub fn public_key(&self) -> &PublicKey { + self.key_material.public() + } + + pub fn encrypt( + &self, + msg: ProvisionMessage, + ) -> Result { + let msg = msg.encode_to_vec(); + + let mut rng = rand::thread_rng(); + let our_key_pair = libsignal_protocol::KeyPair::generate(&mut rng); + let agreement = our_key_pair.calculate_agreement(self.public_key())?; + + let mut shared_secrets = [0; 64]; + hkdf::Hkdf::::new(None, &agreement) + .expand(b"TextSecure Provisioning Message", &mut shared_secrets) + .expect("valid output length"); + + let aes_key = &shared_secrets[0..32]; + let mac_key = &shared_secrets[32..]; + let iv: [u8; IV_LENGTH] = rng.gen(); + + let cipher = Cbc::::new_from_slices(aes_key, &iv) + .expect("initalization of CBC/AES/PKCS7"); + let ciphertext = cipher.encrypt_vec(&msg); + let mut mac = Hmac::::new_from_slice(mac_key) + .expect("HMAC can take any size key"); + mac.update(&[VERSION]); + mac.update(&iv); + mac.update(&ciphertext); + let mac = mac.finalize().into_bytes(); + + let body: Vec = std::iter::once(VERSION) + .chain(iv.iter().cloned()) + .chain(ciphertext) + .chain(mac) + .collect(); + + Ok(ProvisionEnvelope { + public_key: Some(our_key_pair.public_key.serialize().into()), + body: Some(body), + }) + } + + pub fn decrypt( + &self, + provision_envelope: ProvisionEnvelope, + ) -> Result { + let key_pair = match self.key_material { + CipherMode::DecryptAndEncrypt(ref key_pair) => key_pair, + CipherMode::EncryptOnly(_) => { + return Err(ProvisioningError::EncryptOnlyProvisioningCipher); + }, + }; + let master_ephemeral = PublicKey::deserialize( + &provision_envelope.public_key.expect("no public key"), + )?; + let body = provision_envelope + .body + .expect("no body in ProvisionMessage"); + if body[0] != VERSION { + return Err(ProvisioningError::InvalidData { + reason: "Bad version number".into(), + }); + } + + let iv = &body[IV_OFFSET..(IV_LENGTH + IV_OFFSET)]; + let mac = &body[(body.len() - 32)..]; + let cipher_text = &body[16 + 1..(body.len() - CIPHER_KEY_SIZE)]; + let iv_and_cipher_text = &body[0..(body.len() - CIPHER_KEY_SIZE)]; + debug_assert_eq!(iv.len(), IV_LENGTH); + debug_assert_eq!(mac.len(), 32); + + let agreement = key_pair.calculate_agreement(&master_ephemeral)?; + + let mut shared_secrets = [0; 64]; + hkdf::Hkdf::::new(None, &agreement) + .expand(b"TextSecure Provisioning Message", &mut shared_secrets) + .expect("valid output length"); + + let parts1 = &shared_secrets[0..32]; + let parts2 = &shared_secrets[32..]; + + let mut verifier = Hmac::::new_from_slice(parts2) + .expect("HMAC can take any size key"); + verifier.update(iv_and_cipher_text); + let our_mac = verifier.finalize().into_bytes(); + debug_assert_eq!(our_mac.len(), mac.len()); + if &our_mac[..32] != mac { + return Err(ProvisioningError::InvalidData { + reason: "wrong MAC".into(), + }); + } + + // libsignal-service-java uses Pkcs5, + // but that should not matter. + // https://crypto.stackexchange.com/questions/9043/what-is-the-difference-between-pkcs5-padding-and-pkcs7-padding + let cipher = Cbc::::new_from_slices(parts1, iv) + .expect("initalization of CBC/AES/PKCS7"); + let input = cipher.decrypt_vec(cipher_text).map_err(|e| { + ProvisioningError::InvalidData { + reason: format!("CBC/Padding error: {:?}", e), + } + })?; + + Ok(prost::Message::decode(Bytes::from(input))?) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn encrypt_provisioning_roundtrip() -> anyhow::Result<()> { + let mut rng = rand::thread_rng(); + let cipher = ProvisioningCipher::generate(&mut rng)?; + let encrypt_cipher = + ProvisioningCipher::from_public(*cipher.public_key()); + + assert_eq!( + cipher.public_key(), + encrypt_cipher.public_key(), + "copy public key" + ); + + let msg = ProvisionMessage::default(); + let encrypted = encrypt_cipher.encrypt(msg.clone())?; + + assert!(matches!( + encrypt_cipher.decrypt(encrypted.clone()), + Err(ProvisioningError::EncryptOnlyProvisioningCipher) + )); + + let decrypted = cipher.decrypt(encrypted)?; + assert_eq!(msg, decrypted); + + Ok(()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/manager.rs b/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/manager.rs new file mode 100644 index 0000000..8699689 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/manager.rs @@ -0,0 +1,369 @@ +use futures::{channel::mpsc::Sender, pin_mut, SinkExt, StreamExt}; +use libsignal_protocol::{PrivateKey, PublicKey}; +use phonenumber::PhoneNumber; +use serde::{Deserialize, Serialize}; +use url::Url; +use uuid::Uuid; + +use super::{ + pipe::{ProvisioningPipe, ProvisioningStep}, + ProvisioningError, +}; + +use crate::{ + configuration::{Endpoint, ServiceCredentials, SignalingKey}, + push_service::{ + AccountAttributes, DeviceCapabilities, DeviceId, HttpAuthOverride, + PushService, ServiceError, + }, + utils::{serde_base64, serde_optional_base64}, +}; + +/// Message received after confirming the SMS/voice code on registration. +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ConfirmCodeMessage { + #[serde(with = "serde_base64")] + pub signaling_key: Vec, + pub supports_sms: bool, + pub registration_id: u32, + pub voice: bool, + pub video: bool, + pub fetches_messages: bool, + pub pin: Option, + #[serde(default, with = "serde_optional_base64")] + pub unidentified_access_key: Option>, + pub unrestricted_unidentified_access: bool, + pub discoverable_by_phone_number: bool, + pub capabilities: DeviceCapabilities, +} +/// Message received when linking a new secondary device. +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ConfirmDeviceMessage { + #[serde(with = "serde_base64")] + pub signaling_key: Vec, + pub supports_sms: bool, + pub fetches_messages: bool, + pub registration_id: u32, + // FIXME: the name goes back here when we send this via the websocket + //pub name: String, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ConfirmCodeResponse { + pub uuid: Uuid, + pub storage_capable: bool, +} + +#[derive(Debug, Eq, PartialEq)] +pub enum VerificationCodeResponse { + CaptchaRequired, + Issued, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct VerifyAccountResponse { + pub uuid: Uuid, + pub pni: String, + pub storage_capable: bool, +} + +pub struct ProvisioningManager<'a, P: PushService + 'a> { + push_service: &'a mut P, + phone_number: PhoneNumber, + password: String, +} + +pub enum SecondaryDeviceProvisioning { + Url(Url), + NewDeviceRegistration { + phone_number: phonenumber::PhoneNumber, + device_id: DeviceId, + registration_id: u32, + uuid: Uuid, + private_key: PrivateKey, + public_key: PublicKey, + profile_key: Vec, + }, +} + +impl<'a, P: PushService + 'a> ProvisioningManager<'a, P> { + pub fn new( + push_service: &'a mut P, + phone_number: PhoneNumber, + password: String, + ) -> Self { + Self { + push_service, + phone_number, + password, + } + } + + pub async fn request_sms_verification_code( + &mut self, + captcha: Option<&str>, + challenge: Option<&str>, + ) -> Result { + let res = match self + .push_service + .get_json( + Endpoint::Service, + self.build_verification_code_request_url( + "sms", captcha, challenge, + ) + .as_ref(), + self.auth_override(), + ) + .await + { + Err(ServiceError::JsonDecodeError { .. }) => Ok(()), + r => r, + }; + match res { + Ok(_) => Ok(VerificationCodeResponse::Issued), + Err(ServiceError::UnhandledResponseCode { http_code: 402 }) => { + Ok(VerificationCodeResponse::CaptchaRequired) + }, + Err(e) => Err(e), + } + } + + pub async fn request_voice_verification_code( + &mut self, + captcha: Option<&str>, + challenge: Option<&str>, + ) -> Result { + let res = match self + .push_service + .get_json( + Endpoint::Service, + self.build_verification_code_request_url( + "voice", captcha, challenge, + ) + .as_ref(), + self.auth_override(), + ) + .await + { + Err(ServiceError::JsonDecodeError { .. }) => Ok(()), + r => r, + }; + match res { + Ok(_) => Ok(VerificationCodeResponse::Issued), + Err(ServiceError::UnhandledResponseCode { http_code: 402 }) => { + Ok(VerificationCodeResponse::CaptchaRequired) + }, + Err(e) => Err(e), + } + } + + pub async fn confirm_verification_code( + &mut self, + confirm_code: u32, + account_attributes: AccountAttributes, + ) -> Result { + self.push_service + .put_json( + Endpoint::Service, + &format!("/v1/accounts/code/{}", confirm_code), + self.auth_override(), + account_attributes, + ) + .await + } + + pub async fn confirm_device( + &mut self, + confirm_code: u32, + confirm_code_message: ConfirmDeviceMessage, + ) -> Result { + self.push_service + .put_json( + Endpoint::Service, + &format!("/v1/devices/{}", confirm_code), + self.auth_override(), + confirm_code_message, + ) + .await + } + + fn build_verification_code_request_url( + &self, + msg_type: &str, + captcha: Option<&str>, + challenge: Option<&str>, + ) -> String { + let phone_number = + self.phone_number.format().mode(phonenumber::Mode::E164); + if let Some(cl) = challenge { + format!( + "/v1/accounts/{}/code/{}?challenge={}", + msg_type, phone_number, cl + ) + } else if let Some(cc) = captcha { + format!( + "/v1/accounts/{}/code/{}?captcha={}", + msg_type, phone_number, cc + ) + } else { + format!("/v1/accounts/{}/code/{}", msg_type, phone_number) + } + } + + fn auth_override(&self) -> HttpAuthOverride { + let credentials = ServiceCredentials { + uuid: None, + phonenumber: self.phone_number.clone(), + password: Some(self.password.clone()), + signaling_key: None, + device_id: None, + }; + if let Some(auth) = credentials.authorization() { + HttpAuthOverride::Identified(auth) + } else { + HttpAuthOverride::NoOverride + } + } +} + +#[derive(Clone)] +pub struct LinkingManager { + push_service: P, + // forwarded to the `ProvisioningManager` + password: String, +} + +impl LinkingManager

{ + pub fn new(push_service: P, password: String) -> Self { + Self { + push_service, + password, + } + } + + pub async fn provision_secondary_device( + &mut self, + csprng: &mut R, + signaling_key: SignalingKey, + mut tx: Sender, + ) -> Result<(), ProvisioningError> { + // open a websocket without authentication, to receive a tsurl:// + let (ws, stream) = self + .push_service + .ws("/v1/websocket/provisioning/", None) + .await?; + + // see libsignal-protocol-c / signal_protocol_key_helper_generate_registration_id + let registration_id = csprng.gen_range(1, 16380); + + let provisioning_pipe = ProvisioningPipe::from_socket(ws, stream)?; + let provision_stream = provisioning_pipe.stream(); + pin_mut!(provision_stream); + while let Some(step) = provision_stream.next().await { + match step { + Ok(ProvisioningStep::Url(url)) => { + tx.send(SecondaryDeviceProvisioning::Url(url)) + .await + .expect("failed to send provisioning Url in channel"); + }, + Ok(ProvisioningStep::Message(message)) => { + let uuid = message + .uuid + .ok_or(ProvisioningError::InvalidData { + reason: "missing client UUID".into(), + }) + .and_then(|ref s| { + Uuid::parse_str(s).map_err(|e| { + ProvisioningError::InvalidData { + reason: format!("invalid UUID: {}", e), + } + }) + })?; + + let public_key = PublicKey::deserialize( + &message.identity_key_public.ok_or( + ProvisioningError::InvalidData { + reason: "missing public key".into(), + }, + )?, + )?; + + let private_key = PrivateKey::deserialize( + &message.identity_key_private.ok_or( + ProvisioningError::InvalidData { + reason: "missing public key".into(), + }, + )?, + )?; + + let profile_key = message.profile_key.ok_or( + ProvisioningError::InvalidData { + reason: "missing profile key".into(), + }, + )?; + + let phone_number = message.number.ok_or( + ProvisioningError::InvalidData { + reason: "missing phone number".into(), + }, + )?; + + let phone_number = phonenumber::parse(None, phone_number) + .map_err(|e| { + ProvisioningError::InvalidData { + reason: format!("invalid phone number ({})", e), + } + })?; + + let mut provisioning_manager = ProvisioningManager::new( + &mut self.push_service, + phone_number.clone(), + self.password.clone(), + ); + + let device_id = provisioning_manager + .confirm_device( + message + .provisioning_code + .ok_or(ProvisioningError::InvalidData { + reason: "no provisioning confirmation code" + .into(), + })? + .parse() + .unwrap(), + ConfirmDeviceMessage { + signaling_key: signaling_key.to_vec(), + supports_sms: false, + fetches_messages: true, + registration_id, + }, + ) + .await?; + + tx.send( + SecondaryDeviceProvisioning::NewDeviceRegistration { + phone_number, + device_id, + registration_id, + uuid, + private_key, + public_key, + profile_key, + }, + ) + .await + .expect( + "failed to send provisioning message in rx channel", + ); + }, + Err(e) => return Err(e), + } + } + + Ok(()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/mod.rs b/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/mod.rs new file mode 100644 index 0000000..9377809 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/mod.rs @@ -0,0 +1,40 @@ +mod cipher; +mod manager; +mod pipe; + +pub use cipher::ProvisioningCipher; +pub use manager::{ + ConfirmCodeMessage, ConfirmCodeResponse, LinkingManager, + ProvisioningManager, SecondaryDeviceProvisioning, VerificationCodeResponse, + VerifyAccountResponse, +}; + +use crate::prelude::ServiceError; + +pub use crate::proto::{ + ProvisionEnvelope, ProvisionMessage, ProvisioningVersion, +}; + +#[derive(thiserror::Error, Debug)] +pub enum ProvisioningError { + #[error("Invalid provisioning data: {reason}")] + InvalidData { reason: String }, + #[error("Protobuf decoding error: {0}")] + DecodeError(#[from] prost::DecodeError), + #[error("Websocket error: {reason}")] + WsError { reason: String }, + #[error("Websocket closing: {reason}")] + WsClosing { reason: String }, + #[error("Service error: {0}")] + ServiceError(#[from] ServiceError), + #[error("libsignal-protocol error: {0}")] + ProtocolError(#[from] libsignal_protocol::error::SignalProtocolError), + #[error("ProvisioningCipher in encrypt-only mode")] + EncryptOnlyProvisioningCipher, +} + +pub fn generate_registration_id( + csprng: &mut R, +) -> u32 { + csprng.gen_range(1, 16380) +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/pipe.rs b/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/pipe.rs new file mode 100644 index 0000000..5147000 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/provisioning/pipe.rs @@ -0,0 +1,214 @@ +use bytes::Bytes; +use futures::{ + channel::mpsc::{self, Sender}, + prelude::*, + stream::FuturesUnordered, +}; +use pin_project::pin_project; +use prost::Message; +use url::Url; + +pub use crate::proto::{ + ProvisionEnvelope, ProvisionMessage, ProvisioningVersion, +}; + +use crate::{ + messagepipe::{WebSocketService, WebSocketStreamItem}, + proto::{ + web_socket_message, ProvisioningUuid, WebSocketMessage, + WebSocketRequestMessage, WebSocketResponseMessage, + }, + provisioning::ProvisioningError, +}; + +use super::cipher::ProvisioningCipher; + +#[pin_project] +pub struct ProvisioningPipe { + ws: WS, + #[pin] + stream: WS::Stream, + provisioning_cipher: ProvisioningCipher, +} + +#[derive(Debug)] +pub enum ProvisioningStep { + Url(Url), + Message(ProvisionMessage), +} + +impl ProvisioningPipe { + pub fn from_socket( + ws: WS, + stream: WS::Stream, + ) -> Result { + Ok(ProvisioningPipe { + ws, + stream, + provisioning_cipher: ProvisioningCipher::generate( + &mut rand::thread_rng(), + )?, + }) + } + + async fn send_ok_response( + &mut self, + id: Option, + ) -> Result<(), ProvisioningError> { + self.send_response(WebSocketResponseMessage { + id, + status: Some(200), + message: Some("OK".into()), + body: None, + headers: vec![], + }) + .await + } + + async fn send_response( + &mut self, + r: WebSocketResponseMessage, + ) -> Result<(), ProvisioningError> { + let msg = WebSocketMessage { + r#type: Some(web_socket_message::Type::Response.into()), + response: Some(r), + ..Default::default() + }; + let buffer = msg.encode_to_vec(); + Ok(self.ws.send_message(buffer.into()).await?) + } + + /// Worker task that + async fn run( + mut self, + mut sink: Sender>, + ) -> Result<(), mpsc::SendError> { + use futures::future::LocalBoxFuture; + + // This is a runtime-agnostic, poor man's `::spawn(Future)`. + let mut background_work = FuturesUnordered::>::new(); + // a pending task is added, as to never end the background worker until + // it's dropped. + background_work.push(futures::future::pending().boxed_local()); + + loop { + futures::select! { + // WebsocketConnection::onMessage(ByteString) + frame = self.stream.next() => match frame { + Some(WebSocketStreamItem::Message(frame)) => { + let env = self.process_frame(frame).await.transpose(); + if let Some(env) = env { + sink.send(env).await?; + } + }, + // TODO: implement keep-alive? + Some(WebSocketStreamItem::KeepAliveRequest) => continue, + None => break, + }, + _ = background_work.next() => { + // no op + }, + complete => { + log::info!("select! complete"); + } + } + } + + Ok(()) + } + + async fn process_frame( + &mut self, + frame: Bytes, + ) -> Result, ProvisioningError> { + let msg = WebSocketMessage::decode(frame)?; + use web_socket_message::Type; + match (msg.r#type(), msg.request, msg.response) { + (Type::Request, Some(request), _) => { + match request { + // step 1: we get a ProvisioningUUID that we need to build a + // registration link + WebSocketRequestMessage { + id, + verb, + path, + body, + .. + } if verb == Some("PUT".into()) + && path == Some("/v1/address".into()) => + { + let uuid: ProvisioningUuid = + prost::Message::decode(Bytes::from(body.unwrap()))?; + let mut provisioning_url = + Url::parse("sgnl://linkdevice").map_err(|e| { + ProvisioningError::WsError { + reason: e.to_string(), + } + })?; + provisioning_url + .query_pairs_mut() + .append_pair("uuid", &uuid.uuid.unwrap()) + .append_pair( + "pub_key", + &base64::encode( + self.provisioning_cipher + .public_key() + .serialize(), + ), + ); + + // acknowledge + self.send_ok_response(id).await?; + + Ok(Some(ProvisioningStep::Url(provisioning_url))) + }, + // step 2: once the QR code is scanned by the (already + // validated) main device + // we get a ProvisionMessage, that contains a bunch of + // useful things + WebSocketRequestMessage { + id, + verb, + path, + body, + .. + } if verb == Some("PUT".into()) + && path == Some("/v1/message".into()) => + { + let provision_envelope: ProvisionEnvelope = + prost::Message::decode(Bytes::from(body.unwrap()))?; + let provision_message = self + .provisioning_cipher + .decrypt(provision_envelope)?; + + // acknowledge + self.send_ok_response(id).await?; + + Ok(Some(ProvisioningStep::Message(provision_message))) + }, + _ => Err(ProvisioningError::WsError { + reason: "Incorrect request".into(), + }), + } + }, + _ => Err(ProvisioningError::WsError { + reason: "Incorrect request".into(), + }), + } + } + + pub fn stream( + self, + ) -> impl Stream> { + let (sink, stream) = mpsc::channel(1); + + let stream = stream.map(Some); + let runner = self.run(sink).map(|_| { + log::info!("Sink closed, provisioning is done!"); + None + }); + + let combined = futures::stream::select(stream, runner.into_stream()); + combined.filter_map(|x| async { x }) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/push_service.rs b/net/gurk-rs/files/vendor/libsignal-service/src/push_service.rs new file mode 100644 index 0000000..3ab59f9 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/push_service.rs @@ -0,0 +1,799 @@ +use std::{convert::TryInto, fmt, ops::Deref, time::Duration}; + +use crate::{ + configuration::{Endpoint, ServiceCredentials}, + envelope::*, + groups_v2::GroupDecryptionError, + messagepipe::WebSocketService, + pre_keys::{PreKeyEntity, PreKeyState, SignedPreKeyEntity}, + proto::{attachment_pointer::AttachmentIdentifier, AttachmentPointer}, + sender::{OutgoingPushMessages, SendMessageResponse}, + utils::{serde_base64, serde_optional_base64}, + MaybeSend, ServiceAddress, +}; + +use aes_gcm::{ + aead::{generic_array::GenericArray, Aead}, + Aes256Gcm, NewAead, +}; +use chrono::prelude::*; +use libsignal_protocol::{ + error::SignalProtocolError, IdentityKey, PreKeyBundle, PublicKey, +}; +use prost::Message as ProtobufMessage; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; +use zkgroup::profiles::{ProfileKeyCommitment, ProfileKeyVersion}; + +/** +Since we can't use format!() with constants, the URLs here are just for reference purposes +pub const REGISTER_GCM_PATH: &str = "/v1/accounts/gcm/"; +pub const TURN_SERVER_INFO: &str = "/v1/accounts/turn"; +pub const SET_ACCOUNT_ATTRIBUTES: &str = "/v1/accounts/attributes/"; +pub const PIN_PATH: &str = "/v1/accounts/pin/"; +pub const REQUEST_PUSH_CHALLENGE: &str = "/v1/accounts/fcm/preauth/%s/%s"; +pub const WHO_AM_I: &str = "/v1/accounts/whoami"; + +pub const PREKEY_PATH: &str = "/v2/keys/%s"; +pub const PREKEY_DEVICE_PATH: &str = "/v2/keys/%s/%s"; +pub const SIGNED_PREKEY_PATH: &str = "/v2/keys/signed"; + +pub const PROVISIONING_CODE_PATH: &str = "/v1/devices/provisioning/code"; +pub const PROVISIONING_MESSAGE_PATH: &str = "/v1/provisioning/%s"; + +pub const DIRECTORY_TOKENS_PATH: &str = "/v1/directory/tokens"; +pub const DIRECTORY_VERIFY_PATH: &str = "/v1/directory/%s"; +pub const DIRECTORY_AUTH_PATH: &str = "/v1/directory/auth"; +pub const DIRECTORY_FEEDBACK_PATH: &str = "/v1/directory/feedback-v3/%s"; +pub const SENDER_ACK_MESSAGE_PATH: &str = "/v1/messages/%s/%d"; +pub const UUID_ACK_MESSAGE_PATH: &str = "/v1/messages/uuid/%s"; +pub const ATTACHMENT_PATH: &str = "/v2/attachments/form/upload"; + +pub const PROFILE_PATH: &str = "/v1/profile/"; + +pub const SENDER_CERTIFICATE_LEGACY_PATH: &str = "/v1/certificate/delivery"; +pub const SENDER_CERTIFICATE_PATH: &str = + "/v1/certificate/delivery?includeUuid=true"; + +pub const ATTACHMENT_DOWNLOAD_PATH: &str = "attachments/%d"; + +pub const STICKER_MANIFEST_PATH: &str = "stickers/%s/manifest.proto"; +pub const STICKER_PATH: &str = "stickers/%s/full/%d"; +**/ + +pub const KEEPALIVE_TIMEOUT_SECONDS: Duration = Duration::from_secs(55); +pub const DEFAULT_DEVICE_ID: u32 = 1; + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DeviceId { + pub device_id: u32, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DeviceInfo { + pub id: i64, + pub name: Option, + #[serde(with = "chrono::serde::ts_milliseconds")] + pub created: DateTime, + #[serde(with = "chrono::serde::ts_milliseconds")] + pub last_seen: DateTime, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AccountAttributes { + #[serde(default, with = "serde_optional_base64")] + pub signaling_key: Option>, + pub registration_id: u32, + pub voice: bool, + pub video: bool, + pub fetches_messages: bool, + pub pin: Option, + pub registration_lock: Option, + #[serde(default, with = "serde_optional_base64")] + pub unidentified_access_key: Option>, + pub unrestricted_unidentified_access: bool, + pub discoverable_by_phone_number: bool, + pub capabilities: DeviceCapabilities, +} + +#[derive(Debug, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct DeviceCapabilities { + pub uuid: bool, + #[serde(rename = "gv2-3")] + pub gv2: bool, + pub storage: bool, + #[serde(rename = "gv1-migration")] + pub gv1_migration: bool, +} + +#[derive(Clone)] +pub struct ProfileKey(pub [u8; 32]); + +#[derive(Debug, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct PreKeyStatus { + pub count: u32, +} + +#[derive(Clone)] +pub struct HttpAuth { + pub username: String, + pub password: String, +} + +#[derive(Debug, Clone)] +pub enum HttpAuthOverride { + NoOverride, + Unidentified, + Identified(HttpAuth), +} + +impl fmt::Debug for HttpAuth { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "HTTP auth with username {}", self.username) + } +} + +impl ProfileKey { + pub fn derive_access_key(&self) -> Vec { + let key = GenericArray::from_slice(&self.0); + let cipher = Aes256Gcm::new(key); + let nonce = GenericArray::from_slice(&[0u8; 12]); + let buf = [0u8; 16]; + let mut ciphertext = cipher.encrypt(nonce, &buf[..]).unwrap(); + ciphertext.truncate(16); + ciphertext + } +} + +impl Deref for ProfileKey { + type Target = [u8; 32]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Serialize for ProfileKey { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&base64::encode(self.0)) + } +} + +impl<'de> Deserialize<'de> for ProfileKey { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Ok(ProfileKey( + base64::decode(String::deserialize(deserializer)?) + .map_err(serde::de::Error::custom)? + .try_into() + .map_err(|buf: Vec| { + serde::de::Error::invalid_length( + buf.len(), + &"invalid profile key length", + ) + })?, + )) + } +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PreKeyResponse { + #[serde(with = "serde_base64")] + pub identity_key: Vec, + pub devices: Vec, +} + +#[derive(Debug, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct WhoAmIResponse { + pub uuid: Uuid, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PreKeyResponseItem { + pub device_id: u32, + pub registration_id: u32, + pub signed_pre_key: SignedPreKeyEntity, + pub pre_key: Option, +} + +impl PreKeyResponseItem { + fn into_bundle( + self, + identity: IdentityKey, + ) -> Result { + PreKeyBundle::new( + self.registration_id, + self.device_id, + self.pre_key + .map(|pk| -> Result<_, SignalProtocolError> { + Ok((pk.key_id, PublicKey::deserialize(&pk.public_key)?)) + }) + .transpose()?, + // pre_key: Option<(u32, PublicKey)>, + self.signed_pre_key.key_id, + PublicKey::deserialize(&self.signed_pre_key.public_key)?, + self.signed_pre_key.signature, + identity, + ) + } +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MismatchedDevices { + pub missing_devices: Vec, + pub extra_devices: Vec, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct StaleDevices { + pub stale_devices: Vec, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SignalServiceProfile { + #[serde(default, with = "serde_optional_base64")] + pub name: Option>, + #[serde(default, with = "serde_optional_base64")] + pub about: Option>, + #[serde(default, with = "serde_optional_base64")] + pub about_emoji: Option>, +} + +#[derive(Debug, serde::Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct CdnUploadAttributes { + path: String, + acl: String, + key: String, + policy: String, + algorithm: String, + credential: String, + date: String, + signature: String, + content_type: String, + length: u64, +} + +#[derive(Debug, serde::Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct AttachmentV2UploadAttributes { + url: Option, + key: String, + credential: String, + acl: String, + algorithm: String, + date: String, + policy: String, + signature: String, + // This is different from Java's implementation, + // and I (Ruben) am unsure why they decide to force-parse at upload-time instead of at registration + // time. + attachment_id: u64, + attachment_id_string: String, +} + +#[derive(thiserror::Error, Debug)] +pub enum ServiceError { + #[error("Service request timed out: {reason}")] + Timeout { reason: String }, + + #[error("invalid URL: {0}")] + InvalidUrl(#[from] url::ParseError), + + #[error("Error sending request: {reason}")] + SendError { reason: String }, + + #[error("Error decoding response: {reason}")] + ResponseError { reason: String }, + + #[error("Error decoding JSON response: {reason}")] + JsonDecodeError { reason: String }, + #[error("Error decoding protobuf frame: {0}")] + ProtobufDecodeError(#[from] prost::DecodeError), + #[error("error encoding or decoding bincode: {0}")] + BincodeError(#[from] bincode::Error), + #[error("error decoding base64 string: {0}")] + Base64DecodeError(#[from] base64::DecodeError), + + #[error("Rate limit exceeded")] + RateLimitExceeded, + #[error("Authorization failed")] + Unauthorized, + #[error("Unexpected response: HTTP {http_code}")] + UnhandledResponseCode { http_code: u16 }, + + #[error("Websocket error: {reason}")] + WsError { reason: String }, + #[error("Websocket closing: {reason}")] + WsClosing { reason: String }, + + #[error("Invalid frame: {reason}")] + InvalidFrameError { reason: String }, + + #[error("MAC error")] + MacError, + + #[error("Protocol error: {0}")] + SignalProtocolError(#[from] SignalProtocolError), + + #[error("{0:?}")] + MismatchedDevicesException(MismatchedDevices), + + #[error("{0:?}")] + StaleDevices(StaleDevices), + + #[error("SealedSessionCipher error: {0}")] + SealedSessionError( + #[from] crate::sealed_session_cipher::SealedSessionError, + ), + + #[error(transparent)] + CredentialsCacheError(#[from] crate::groups_v2::CredentialsCacheError), + + #[error("groups v2 (zero-knowledge) error")] + GroupsV2Error, + + #[error(transparent)] + GroupsV2DecryptionError(#[from] GroupDecryptionError), +} + +#[cfg_attr(feature = "unsend-futures", async_trait::async_trait(?Send))] +#[cfg_attr(not(feature = "unsend-futures"), async_trait::async_trait)] +pub trait PushService: MaybeSend { + type WebSocket: WebSocketService; + type ByteStream: futures::io::AsyncRead + Unpin; + + async fn get_json( + &mut self, + service: Endpoint, + path: &str, + credentials_override: HttpAuthOverride, + ) -> Result + where + for<'de> T: Deserialize<'de>; + + async fn delete_json( + &mut self, + service: Endpoint, + path: &str, + ) -> Result + where + for<'de> T: Deserialize<'de>; + + async fn put_json( + &mut self, + service: Endpoint, + path: &str, + credentials_override: HttpAuthOverride, + value: S, + ) -> Result + where + for<'de> D: Deserialize<'de>, + S: MaybeSend + Serialize; + + async fn get_protobuf( + &mut self, + service: Endpoint, + path: &str, + credentials_override: HttpAuthOverride, + ) -> Result + where + T: Default + ProtobufMessage; + + async fn put_protobuf( + &mut self, + service: Endpoint, + path: &str, + value: S, + ) -> Result + where + D: Default + ProtobufMessage, + S: Sized + ProtobufMessage; + + /// Downloads larger files in streaming fashion, e.g. attachments. + async fn get_from_cdn( + &mut self, + cdn_id: u32, + path: &str, + ) -> Result; + + /// Upload larger file to CDN0 in legacy fashion, e.g. for attachments. + /// + /// Implementations are allowed to *panic* when the Read instance throws an IO-Error + async fn post_to_cdn0<'s, C: std::io::Read + Send + 's>( + &mut self, + path: &str, + value: &[(&str, &str)], + file: Option<(&str, &'s mut C)>, + ) -> Result<(), ServiceError>; + + async fn ws( + &mut self, + path: &str, + credentials: Option, + ) -> Result< + ( + Self::WebSocket, + ::Stream, + ), + ServiceError, + >; + + /// Fetches a list of all devices tied to the authenticated account. + /// + /// This list include the device that sends the request. + async fn devices(&mut self) -> Result, ServiceError> { + #[derive(serde::Deserialize)] + struct DeviceInfoList { + devices: Vec, + } + + let devices: DeviceInfoList = self + .get_json( + Endpoint::Service, + "/v1/devices/", + HttpAuthOverride::NoOverride, + ) + .await?; + + Ok(devices.devices) + } + + async fn unlink_device(&mut self, id: i64) -> Result<(), ServiceError> { + self.delete_json(Endpoint::Service, &format!("/v1/devices/{}", id)) + .await + } + + async fn get_pre_key_status( + &mut self, + ) -> Result { + self.get_json( + Endpoint::Service, + "/v2/keys/", + HttpAuthOverride::NoOverride, + ) + .await + } + + async fn register_pre_keys( + &mut self, + pre_key_state: PreKeyState, + ) -> Result<(), ServiceError> { + match self + .put_json( + Endpoint::Service, + "/v2/keys/", + HttpAuthOverride::NoOverride, + pre_key_state, + ) + .await + { + Err(ServiceError::JsonDecodeError { .. }) => Ok(()), + r => r, + } + } + + async fn get_attachment_by_id( + &mut self, + id: &str, + cdn_id: u32, + ) -> Result { + let path = format!("attachments/{}", id); + self.get_from_cdn(cdn_id, &path).await + } + + async fn get_attachment( + &mut self, + ptr: &AttachmentPointer, + ) -> Result { + match ptr.attachment_identifier.as_ref().unwrap() { + AttachmentIdentifier::CdnId(id) => { + // cdn_number did not exist for this part of the protocol. + // cdn_number(), however, returns 0 when the field does not + // exist. + self.get_attachment_by_id(&format!("{}", id), ptr.cdn_number()) + .await + }, + AttachmentIdentifier::CdnKey(key) => { + self.get_attachment_by_id(key, ptr.cdn_number()).await + }, + } + } + + async fn send_messages<'a>( + &mut self, + messages: OutgoingPushMessages<'a>, + ) -> Result { + let path = format!("/v1/messages/{}", messages.destination); + self.put_json( + Endpoint::Service, + &path, + HttpAuthOverride::NoOverride, + messages, + ) + .await + } + + /// Request AttachmentV2UploadAttributes + /// + /// Equivalent with getAttachmentV2UploadAttributes + async fn get_attachment_v2_upload_attributes( + &mut self, + ) -> Result { + self.get_json( + Endpoint::Service, + "/v2/attachments/form/upload", + HttpAuthOverride::NoOverride, + ) + .await + } + + /// Upload attachment to CDN + /// + /// Returns attachment ID and the attachment digest + async fn upload_attachment<'s, C: std::io::Read + Send + 's>( + &mut self, + attrs: &AttachmentV2UploadAttributes, + content: &'s mut C, + ) -> Result<(u64, Vec), ServiceError> { + let values = [ + ("acl", &attrs.acl as &str), + ("key", &attrs.key), + ("policy", &attrs.policy), + ("Content-Type", "application/octet-stream"), + ("x-amz-algorithm", &attrs.algorithm), + ("x-amz-credential", &attrs.credential), + ("x-amz-date", &attrs.date), + ("x-amz-signature", &attrs.signature), + ]; + + let mut digester = crate::digeststream::DigestingReader::new(content); + + self.post_to_cdn0( + "attachments/", + &values, + Some(("file", &mut digester)), + ) + .await?; + Ok((attrs.attachment_id, digester.finalize())) + } + + async fn get_messages( + &mut self, + ) -> Result, ServiceError> { + let entity_list: EnvelopeEntityList = self + .get_json( + Endpoint::Service, + "/v1/messages/", + HttpAuthOverride::NoOverride, + ) + .await?; + Ok(entity_list.messages) + } + + /// Method used to check our own UUID + async fn whoami(&mut self) -> Result { + self.get_json( + Endpoint::Service, + "/v1/accounts/whoami", + HttpAuthOverride::NoOverride, + ) + .await + } + + async fn retrieve_profile_by_id( + &mut self, + id: &str, + ) -> Result { + self.get_json( + Endpoint::Service, + &format!("/v1/profile/{}", id), + HttpAuthOverride::NoOverride, + ) + .await + } + async fn retrieve_versioned_profile_by_id( + &mut self, + id: &str, + version: &ProfileKeyVersion, + ) -> Result { + // Bincode is transparent and will return a hex-encoded string. + let version = bincode::serialize(version)?; + let version = std::str::from_utf8(&version) + .expect("profile_key_version is hex encoded string"); + self.get_json( + Endpoint::Service, + &format!("/v1/profile/{}/{}", id, version), + HttpAuthOverride::NoOverride, + ) + .await + } + + async fn get_pre_key( + &mut self, + destination: &ServiceAddress, + device_id: u32, + ) -> Result { + let path = if let Some(ref relay) = destination.relay { + format!( + "/v2/keys/{}/{}?relay={}", + destination.identifier(), + device_id, + relay + ) + } else { + format!("/v2/keys/{}/{}", destination.identifier(), device_id) + }; + + let mut pre_key_response: PreKeyResponse = self + .get_json(Endpoint::Service, &path, HttpAuthOverride::NoOverride) + .await?; + assert!(!pre_key_response.devices.is_empty()); + + let identity = IdentityKey::decode(&pre_key_response.identity_key)?; + let device = pre_key_response.devices.remove(0); + Ok(device.into_bundle(identity)?) + } + + async fn get_pre_keys( + &mut self, + destination: &ServiceAddress, + device_id: u32, + ) -> Result, ServiceError> { + let path = match (device_id, destination.relay.as_ref()) { + (1, None) => format!("/v2/keys/{}/*", destination.identifier()), + (device_id, None) => { + format!("/v2/keys/{}/{}", destination.identifier(), device_id) + }, + (1, Some(relay)) => format!( + "/v2/keys/{}/*?relay={}", + destination.identifier(), + relay + ), + (device_id, Some(relay)) => format!( + "/v2/keys/{}/{}?relay={}", + destination.identifier(), + device_id, + relay + ), + }; + let pre_key_response: PreKeyResponse = self + .get_json(Endpoint::Service, &path, HttpAuthOverride::NoOverride) + .await?; + let mut pre_keys = vec![]; + let identity = IdentityKey::decode(&pre_key_response.identity_key)?; + for device in pre_key_response.devices { + pre_keys.push(device.into_bundle(identity)?); + } + Ok(pre_keys) + } + + async fn get_group( + &mut self, + credentials: HttpAuth, + ) -> Result { + self.get_protobuf( + Endpoint::Storage, + "/v1/groups/", + HttpAuthOverride::Identified(credentials), + ) + .await + } + + async fn set_account_attributes( + &mut self, + attributes: AccountAttributes, + ) -> Result<(), ServiceError> { + assert!( + attributes.pin.is_none() || attributes.registration_lock.is_none(), + "only one of PIN and registration lock can be set." + ); + + match self + .put_json( + Endpoint::Service, + "/v1/accounts/attributes/", + HttpAuthOverride::NoOverride, + attributes, + ) + .await + { + Err(ServiceError::JsonDecodeError { .. }) => Ok(()), + r => r, + } + } + + /// Writes a profile and returns the avatar URL, if one was provided. + /// + /// The name, about and emoji fields are encrypted with an [`ProfileCipher`]. + /// See [`AccountManager`] for a convenience method. + /// + /// Java equivalent: `writeProfile` + async fn write_profile( + &mut self, + version: &ProfileKeyVersion, + name: &[u8], + about: &[u8], + emoji: &[u8], + commitment: &ProfileKeyCommitment, + // FIXME cfr also account manager + avatar: Option<()>, + ) -> Result, ServiceError> { + #[derive(Debug, Serialize)] + #[serde(rename_all = "camelCase")] + struct SignalServiceProfileWrite<'s> { + /// Hex-encoded + version: &'s str, + #[serde(with = "serde_base64")] + name: &'s [u8], + #[serde(with = "serde_base64")] + about: &'s [u8], + #[serde(with = "serde_base64")] + about_emoji: &'s [u8], + avatar: bool, + #[serde(with = "serde_base64")] + commitment: &'s [u8], + } + + // Bincode is transparent and will return a hex-encoded string. + let version = bincode::serialize(version)?; + let version = std::str::from_utf8(&version) + .expect("profile_key_version is hex encoded string"); + let commitment = bincode::serialize(commitment)?; + + let command = SignalServiceProfileWrite { + version, + name, + about, + about_emoji: emoji, + avatar: avatar.is_some(), + commitment: &commitment, + }; + + // XXX this should be a struct; cfr ProfileAvatarUploadAttributes + let response: Result = self + .put_json( + Endpoint::Service, + "/v1/profile", + HttpAuthOverride::NoOverride, + command, + ) + .await; + match (response, avatar) { + (Ok(_url), Some(_avatar)) => { + // FIXME + unreachable!("Uploading avatar unimplemented"); + }, + // FIXME cleanup when #54883 is stable and MSRV: + // or-patterns syntax is experimental + // see issue #54883 for more information + (Err(ServiceError::JsonDecodeError { .. }), None) => { + // OWS sends an empty string when there's no attachment + Ok(None) + }, + (Err(e), _) => Err(e), + (Ok(_resp), None) => { + log::warn!( + "No avatar supplied but got avatar upload URL. Ignoring" + ); + Ok(None) + }, + } + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/receiver.rs b/net/gurk-rs/files/vendor/libsignal-service/src/receiver.rs new file mode 100644 index 0000000..6a38445 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/receiver.rs @@ -0,0 +1,157 @@ +use bytes::{Buf, Bytes}; + +use crate::{ + attachment_cipher::decrypt_in_place, + configuration::ServiceCredentials, + envelope::Envelope, + messagepipe::MessagePipe, + models::{Contact, ParseContactError}, + push_service::*, +}; + +/// Equivalent of Java's `SignalServiceMessageReceiver`. +#[derive(Clone)] +pub struct MessageReceiver { + service: Service, +} + +#[derive(thiserror::Error, Debug)] +pub enum MessageReceiverError { + #[error("ServiceError")] + ServiceError(#[from] ServiceError), + + #[error("Envelope parsing error")] + EnvelopeParseError(#[from] crate::envelope::EnvelopeParseError), +} + +impl MessageReceiver { + // TODO: to avoid providing the wrong service/wrong credentials + // change it like LinkingManager or ProvisioningManager + pub fn new(service: Service) -> Self { + MessageReceiver { service } + } + + /// One-off method to receive all pending messages. + /// + /// Equivalent with Java's `SignalServiceMessageReceiver::retrieveMessages`. + /// + /// For streaming messages, use a `MessagePipe` through + /// [`MessageReceiver::create_message_pipe()`]. + pub async fn retrieve_messages( + &mut self, + ) -> Result, MessageReceiverError> { + use std::convert::TryFrom; + + let entities = self.service.get_messages().await?; + let entities = entities + .into_iter() + .map(Envelope::try_from) + .collect::>()?; + Ok(entities) + } + + pub async fn create_message_pipe( + &mut self, + credentials: ServiceCredentials, + ) -> Result, MessageReceiverError> { + let (ws, stream) = self + .service + .ws("/v1/websocket/", Some(credentials.clone())) + .await?; + Ok(MessagePipe::from_socket(ws, stream, credentials)) + } + + pub async fn retrieve_contacts( + &mut self, + contacts: &crate::proto::sync_message::Contacts, + ) -> Result< + impl Iterator>, + ServiceError, + > { + if let Some(ref blob) = contacts.blob { + use futures::io::AsyncReadExt; + + const MAX_DOWNLOAD_RETRIES: u8 = 3; + let mut retries = 0; + + let mut stream = loop { + let r = self.service.get_attachment(blob).await; + match r { + Ok(stream) => break stream, + Err(ServiceError::Timeout { .. }) => { + log::warn!("get_attachment timed out, retrying"); + retries += 1; + if retries >= MAX_DOWNLOAD_RETRIES { + return Err(ServiceError::Timeout { + reason: "too many retries".into(), + }); + } + }, + Err(e) => return Err(e), + } + }; + + let mut ciphertext = Vec::new(); + stream + .read_to_end(&mut ciphertext) + .await + .expect("streamed attachment"); + + let key_material = blob.key(); + assert_eq!( + key_material.len(), + 64, + "key material for attachments is ought to be 64 bytes" + ); + let mut key = [0u8; 64]; + key.copy_from_slice(key_material); + + decrypt_in_place(key, &mut ciphertext) + .expect("attachment decryption"); + + Ok(DeviceContactsIterator::new(Bytes::from(ciphertext))) + } else { + Ok(DeviceContactsIterator::default()) + } + } +} + +#[derive(Default)] +struct DeviceContactsIterator { + decrypted_buffer: Bytes, +} + +impl DeviceContactsIterator { + fn new(decrypted_buffer: Bytes) -> Self { + Self { decrypted_buffer } + } +} + +impl Iterator for DeviceContactsIterator { + type Item = Result; + + fn next(&mut self) -> Option { + use crate::proto::{contact_details::Avatar, ContactDetails}; + + if !self.decrypted_buffer.has_remaining() { + return None; + } + + let contact_details: ContactDetails = + prost::Message::decode_length_delimited(&mut self.decrypted_buffer) + .map_err(ParseContactError::ProtobufError) + .ok()?; + + let avatar_data = if let Some(Avatar { + length: Some(length), + .. + }) = contact_details.avatar + { + Some(self.decrypted_buffer.copy_to_bytes(length as usize)) + } else { + None + }; + + Some(Contact::from_proto(contact_details, avatar_data)) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/sealed_session_cipher.rs b/net/gurk-rs/files/vendor/libsignal-service/src/sealed_session_cipher.rs new file mode 100644 index 0000000..088316b --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/sealed_session_cipher.rs @@ -0,0 +1,1118 @@ +use std::convert::TryFrom; + +use aes::{ + cipher::{NewCipher, StreamCipher}, + Aes256Ctr, +}; + +use hmac::{Hmac, Mac, NewMac}; +use libsignal_protocol::{ + error::SignalProtocolError, message_decrypt_prekey, message_decrypt_signal, + message_encrypt, CiphertextMessageType, IdentityKeyStore, KeyPair, + PreKeySignalMessage, PreKeyStore, PrivateKey, ProtocolAddress, PublicKey, + SessionStore, SignalMessage, SignedPreKeyStore, +}; +use log::error; +use phonenumber::PhoneNumber; +use rand::{CryptoRng, Rng}; +use sha2::Sha256; +use uuid::Uuid; + +use crate::{push_service::ProfileKey, ServiceAddress}; + +#[derive(Debug, thiserror::Error)] +pub enum SealedSessionError { + #[error("Unknown version {0}")] + InvalidMetadataVersionError(u8), + + #[error("{0}")] + InvalidMetadataMessageError(String), + + #[error("Invalid MAC: {0}")] + InvalidMacError(#[from] MacError), + + #[error("Invalid certificate")] + InvalidCertificate, + + #[error("Expired certificate")] + ExpiredCertificate, + + #[error("Failed to decode protobuf {0}")] + DecodeError(#[from] prost::DecodeError), + + #[error("Failed to encode protobuf: {0}")] + EncodeError(#[from] prost::EncodeError), + + #[error("Protocol error {0}")] + ProtocolError(#[from] SignalProtocolError), + + #[error("recipient not trusted")] + NoSessionWithRecipient, + + #[error("Supplied phone number could not be parsed in E164 format")] + InvalidPhoneNumber(#[from] phonenumber::ParseError), + + #[error("Supplied uuid could not be parsed")] + InvalidUuidError(#[from] uuid::Error), +} + +#[derive(thiserror::Error, Debug)] +pub enum MacError { + #[error("Invalid MAC key length")] + InvalidKeyLength, + #[error("Ciphertext not long enough ({0} bytes) for MAC")] + CiphertextNotLongEnough(usize), + #[error("Bad MAC")] + BadMac, +} + +#[derive(Clone)] +pub(crate) struct SealedSessionCipher { + session_store: S, + identity_key_store: I, + signed_pre_key_store: SP, + pre_key_store: P, + csprng: R, + certificate_validator: CertificateValidator, +} + +#[derive(Clone)] +pub struct UnidentifiedAccessPair { + target_unidentified_access: UnidentifiedAccess, + self_unidentified_access: UnidentifiedAccess, +} + +#[derive(Clone)] +pub struct UnidentifiedAccess { + access_key: Vec, + sender_certificate: SenderCertificate, +} + +#[derive(Debug, Clone)] +struct UnidentifiedSenderMessage { + ephemeral: PublicKey, + encrypted_static: Vec, + encrypted_message: Vec, +} + +#[derive(Debug, Clone)] +pub struct UnidentifiedSenderMessageContent { + r#type: CiphertextMessageType, + sender_certificate: SenderCertificate, + content: Vec, +} + +#[derive(Debug, Clone)] +pub struct SenderCertificate { + signer: ServerCertificate, + key: PublicKey, + sender_device_id: u32, + sender_uuid: Option, + sender_e164: Option, + expiration: u64, + pub certificate: Vec, + pub signature: Vec, +} + +#[derive(Debug, Clone)] +pub struct ServerCertificate { + key_id: u32, + key: PublicKey, + certificate: Vec, + signature: Vec, +} + +#[derive(Debug, Clone)] +struct EphemeralKeys { + chain_key: Vec, + cipher_key: Vec, + mac_key: Vec, +} + +#[derive(Debug, Clone)] +struct StaticKeys { + cipher_key: Vec, + mac_key: Vec, +} + +#[derive(Debug, Clone)] +pub struct CertificateValidator { + trust_root: PublicKey, +} + +#[derive(Default, Debug, Clone)] +pub(crate) struct DecryptionResult { + pub sender_uuid: Option, + pub sender_e164: Option, + pub device_id: u32, + pub padded_message: Vec, + pub version: u32, +} + +impl UnidentifiedAccess { + pub fn new( + profile_key: &ProfileKey, + sender_certificate: SenderCertificate, + ) -> Result { + Ok(UnidentifiedAccess { + access_key: profile_key.derive_access_key(), + sender_certificate, + }) + } +} + +impl UnidentifiedSenderMessage { + const CIPHERTEXT_VERSION: u8 = 1; + + fn from_bytes(serialized: &[u8]) -> Result { + let version = serialized[0] >> 4; + if version > Self::CIPHERTEXT_VERSION { + return Err(SealedSessionError::InvalidMetadataVersionError( + version, + )); + } + + let unidentified_sender_message: crate::proto::UnidentifiedSenderMessage = + prost::Message::decode(&serialized[1..serialized.len()])?; + + match ( + unidentified_sender_message.ephemeral_public, + unidentified_sender_message.encrypted_static, + unidentified_sender_message.encrypted_message, + ) { + ( + Some(ephemeral_public), + Some(encrypted_static), + Some(encrypted_message), + ) => Ok(Self { + ephemeral: PublicKey::deserialize(&ephemeral_public)?, + encrypted_static, + encrypted_message, + }), + _ => Err(SealedSessionError::InvalidMetadataMessageError( + "Missing fields".into(), + )), + } + } + + fn into_bytes(self) -> Result, SealedSessionError> { + use prost::Message; + let mut buf = + vec![Self::CIPHERTEXT_VERSION << 4 | Self::CIPHERTEXT_VERSION]; + crate::proto::UnidentifiedSenderMessage { + ephemeral_public: Some(self.ephemeral.serialize().to_vec()), + encrypted_static: Some(self.encrypted_static), + encrypted_message: Some(self.encrypted_message), + } + .encode(&mut buf)?; + Ok(buf) + } +} + +impl SealedSessionCipher +where + S: SessionStore, + I: IdentityKeyStore, + SP: SignedPreKeyStore, + P: PreKeyStore, + R: Rng + CryptoRng, +{ + pub(crate) fn new( + session_store: S, + identity_key_store: I, + signed_pre_key_store: SP, + pre_key_store: P, + csprng: R, + certificate_validator: CertificateValidator, + ) -> Self { + Self { + session_store, + identity_key_store, + signed_pre_key_store, + pre_key_store, + csprng, + certificate_validator, + } + } + + /// unused until we make progress on https://github.com/Michael-F-Bryan/libsignal-service-rs/issues/25 + /// messages from unidentified senders can only be sent via a unidentifiedPipe + #[allow(dead_code)] + pub async fn encrypt( + &mut self, + destination: &ProtocolAddress, + sender_certificate: SenderCertificate, + padded_plaintext: &[u8], + ) -> Result, SealedSessionError> { + let message = message_encrypt( + padded_plaintext, + destination, + &mut self.session_store, + &mut self.identity_key_store, + None, + ) + .await?; + + let our_identity = + &self.identity_key_store.get_identity_key_pair(None).await?; + let their_identity = self + .identity_key_store + .get_identity(destination, None) + .await? + .ok_or(SealedSessionError::NoSessionWithRecipient)?; + + let ephemeral = KeyPair::generate(&mut self.csprng); + let ephemeral_salt = [ + b"UnidentifiedDelivery", + their_identity.serialize().as_ref(), + ephemeral.public_key.serialize().as_ref(), + ] + .concat(); + + let ephemeral_keys = self.calculate_ephemeral_keys( + their_identity.public_key(), + &ephemeral.private_key, + &ephemeral_salt, + )?; + + let static_key_ciphertext = self.encrypt_bytes( + &ephemeral_keys.cipher_key, + &ephemeral_keys.mac_key, + &our_identity.public_key().serialize(), + )?; + + let static_salt = [ + ephemeral_keys.chain_key.as_slice(), + static_key_ciphertext.as_slice(), + ] + .concat(); + + let static_keys = self.calculate_static_keys( + their_identity.public_key(), + our_identity.private_key(), + &static_salt, + )?; + + let content = UnidentifiedSenderMessageContent { + r#type: message.message_type(), + sender_certificate, + content: message.serialize().to_vec(), + }; + + let message_bytes = self.encrypt_bytes( + &static_keys.cipher_key, + &static_keys.mac_key, + &content.into_bytes()?, + )?; + + UnidentifiedSenderMessage { + ephemeral: ephemeral.public_key, + encrypted_static: static_key_ciphertext, + encrypted_message: message_bytes, + } + .into_bytes() + } + + pub async fn decrypt( + &mut self, + ciphertext: &[u8], + timestamp: u64, + ) -> Result { + let our_identity = + self.identity_key_store.get_identity_key_pair(None).await?; + + let wrapper = UnidentifiedSenderMessage::from_bytes(ciphertext)?; + + let ephemeral_salt = [ + b"UnidentifiedDelivery", + our_identity.public_key().serialize().as_ref(), + wrapper.ephemeral.serialize().as_ref(), + ] + .concat(); + + let ephemeral_keys = self.calculate_ephemeral_keys( + &wrapper.ephemeral, + our_identity.private_key(), + &ephemeral_salt, + )?; + + let static_key_bytes = Self::decrypt_bytes( + &ephemeral_keys.cipher_key, + &ephemeral_keys.mac_key, + &wrapper.encrypted_static, + )?; + + let static_key = PublicKey::deserialize(&static_key_bytes)?; + let static_salt = + [ephemeral_keys.chain_key, wrapper.encrypted_static].concat(); + let static_keys = self.calculate_static_keys( + &static_key, + our_identity.private_key(), + &static_salt, + )?; + + let message_bytes = Self::decrypt_bytes( + &static_keys.cipher_key, + &static_keys.mac_key, + &wrapper.encrypted_message, + )?; + + let content = UnidentifiedSenderMessageContent::try_from( + message_bytes.as_slice(), + )?; + self.certificate_validator + .validate(&content.sender_certificate, timestamp)?; + + self.decrypt_message_content(content).await + } + + fn calculate_ephemeral_keys( + &self, + public_key: &PublicKey, + private_key: &PrivateKey, + salt: &[u8], + ) -> Result { + let shared_secret = private_key.calculate_agreement(public_key)?; + let mut ephemeral_derived = [0; 96]; + hkdf::Hkdf::::new(Some(salt), &shared_secret) + .expand(&[], &mut ephemeral_derived) + .expect("valid output length"); + let ephemeral_keys = EphemeralKeys { + chain_key: ephemeral_derived[0..32].into(), + cipher_key: ephemeral_derived[32..64].into(), + mac_key: ephemeral_derived[64..96].into(), + }; + Ok(ephemeral_keys) + } + + fn calculate_static_keys( + &self, + public_key: &PublicKey, + private_key: &PrivateKey, + salt: &[u8], + ) -> Result { + let static_secret = private_key.calculate_agreement(public_key)?; + let mut static_derived = [0; 96]; + hkdf::Hkdf::::new(Some(salt), &static_secret) + .expand(&[], &mut static_derived) + .expect("valid output length"); + Ok(StaticKeys { + cipher_key: static_derived[32..64].into(), + mac_key: static_derived[64..96].into(), + }) + } + + fn encrypt_bytes( + &self, + cipher_key: &[u8], + mac_key: &[u8], + plaintext: &[u8], + ) -> Result, SealedSessionError> { + let mut cipher = Aes256Ctr::new(cipher_key.into(), &[0u8; 16].into()); + + let mut ciphertext = plaintext.to_vec(); + cipher.apply_keystream(&mut ciphertext); + + let mut mac = Hmac::::new_from_slice(mac_key) + .map_err(|_| MacError::InvalidKeyLength)?; + mac.update(&ciphertext); + let our_mac = mac.finalize().into_bytes(); + + let encrypted = [ciphertext.as_slice(), &our_mac[..10]].concat(); + + Ok(encrypted) + } + + fn decrypt_bytes( + cipher_key: &[u8], + mac_key: &[u8], + ciphertext: &[u8], + ) -> Result, SealedSessionError> { + if ciphertext.len() < 10 { + return Err(SealedSessionError::InvalidMacError( + MacError::CiphertextNotLongEnough(ciphertext.len()), + )); + } + + let (ciphertext_part1, their_mac) = + ciphertext.split_at(ciphertext.len() - 10); + + let mut verifier = Hmac::::new_from_slice(mac_key) + .map_err(|_| MacError::InvalidKeyLength)?; + verifier.update(ciphertext_part1); + let digest = verifier.finalize().into_bytes(); + let our_mac = &digest[..10]; + + if our_mac != their_mac { + return Err(SealedSessionError::InvalidMacError(MacError::BadMac)); + } + + let mut decrypted = ciphertext_part1.to_vec(); + let mut cipher = Aes256Ctr::new(cipher_key.into(), &[0u8; 16].into()); + cipher.apply_keystream(&mut decrypted); + + Ok(decrypted) + } + + async fn decrypt_message_content( + &mut self, + message: UnidentifiedSenderMessageContent, + ) -> Result { + let UnidentifiedSenderMessageContent { + r#type, + content, + sender_certificate, + } = message; + let sender = crate::cipher::get_preferred_protocol_address( + &self.session_store, + &sender_certificate.address(), + sender_certificate.sender_device_id, + ) + .await?; + + let msg = match r#type { + CiphertextMessageType::Whisper => { + let msg = message_decrypt_signal( + &SignalMessage::try_from(&content[..])?, + &sender, + &mut self.session_store, + &mut self.identity_key_store, + &mut self.csprng, + None, + ) + .await?; + msg.as_slice().to_vec() + }, + CiphertextMessageType::PreKey => { + let msg = message_decrypt_prekey( + &PreKeySignalMessage::try_from(&content[..])?, + &sender, + &mut self.session_store, + &mut self.identity_key_store, + &mut self.pre_key_store, + &mut self.signed_pre_key_store, + &mut self.csprng, + None, + ) + .await?; + msg.as_slice().to_vec() + }, + _ => unreachable!("unknown message from unidentified sender type"), + }; + + let version = self + .session_store + .load_session(&sender, None) + .await? + .ok_or_else(|| { + SignalProtocolError::SessionNotFound(format!("{}", sender)) + })? + .session_version()?; + + Ok(DecryptionResult { + padded_message: msg, + version, + sender_uuid: sender_certificate.sender_uuid, + sender_e164: sender_certificate.sender_e164, + device_id: sender_certificate.sender_device_id, + }) + } +} + +impl UnidentifiedSenderMessageContent { + fn try_from(serialized: &[u8]) -> Result { + use crate::proto::unidentified_sender_message::{self, message}; + + let message: unidentified_sender_message::Message = + prost::Message::decode(serialized)?; + + match (message.r#type, message.sender_certificate, message.content) { + (Some(message_type), Some(sender_certificate), Some(content)) => { + Ok(Self { + r#type: match message::Type::from_i32(message_type) { + Some(message::Type::Message) => { + CiphertextMessageType::Whisper + }, + Some(message::Type::PrekeyMessage) => { + CiphertextMessageType::PreKey + }, + t => { + return Err( + SealedSessionError::InvalidMetadataMessageError( + format!("Wrong message type ({:?})", t), + ), + ) + }, + }, + sender_certificate: SenderCertificate::try_from( + sender_certificate, + )?, + content, + }) + }, + _ => Err(SealedSessionError::InvalidMetadataMessageError( + "Missing fields".into(), + )), + } + } + + fn into_bytes(self) -> Result, SealedSessionError> { + use crate::proto::unidentified_sender_message::{self, message}; + use prost::Message; + + let data = unidentified_sender_message::Message { + r#type: Some(match self.r#type { + CiphertextMessageType::PreKey => message::Type::PrekeyMessage, + CiphertextMessageType::Whisper => message::Type::Message, + _ => { + return Err( + SealedSessionError::InvalidMetadataMessageError( + "unknown ciphertext message type".into(), + ), + ) + }, + } as i32), + sender_certificate: Some(crate::proto::SenderCertificate { + certificate: Some(self.sender_certificate.certificate), + signature: Some(self.sender_certificate.signature), + }), + content: Some(self.content), + } + .encode_to_vec(); + + Ok(data) + } +} + +impl SenderCertificate { + fn try_from( + wrapper: crate::proto::SenderCertificate, + ) -> Result { + use crate::proto::sender_certificate::Certificate; + use prost::Message; + match (wrapper.signature, wrapper.certificate) { + (Some(signature), Some(certificate)) => { + let Certificate { + sender_e164, + sender_uuid, + sender_device, + expires, + identity_key, + signer, + } = Message::decode(&certificate[..])?; + match (sender_device, expires, identity_key, signer) { + ( + Some(sender_device_id), + Some(expires), + Some(identity_key), + Some(signer), + ) => { + if sender_e164.is_none() && sender_uuid.is_none() { + return Err(SealedSessionError::InvalidCertificate); + } + + let sender_e164 = sender_e164 + .map(|s| phonenumber::parse(None, s)) + .transpose()?; + let sender_uuid = sender_uuid + .as_deref() + .map(Uuid::parse_str) + .transpose()?; + + Ok(Self { + signer: ServerCertificate::try_from(signer)?, + key: PublicKey::deserialize(&identity_key)?, + sender_e164, + sender_uuid, + sender_device_id, + expiration: expires, + certificate, + signature, + }) + }, + _ => Err(SealedSessionError::InvalidCertificate), + } + }, + _ => Err(SealedSessionError::InvalidCertificate), + } + } + + fn address(&self) -> ServiceAddress { + ServiceAddress { + uuid: self.sender_uuid, + phonenumber: self.sender_e164.clone(), + relay: None, + } + } +} + +impl ServerCertificate { + fn try_from( + wrapper: crate::proto::ServerCertificate, + ) -> Result { + use crate::proto::server_certificate; + use prost::Message; + + match (wrapper.certificate, wrapper.signature) { + (Some(certificate), Some(signature)) => { + let server_certificate: server_certificate::Certificate = + Message::decode(&certificate[..])?; + match (server_certificate.id, server_certificate.key) { + (Some(id), Some(key)) => Ok(Self { + key_id: id, + key: PublicKey::deserialize(&key)?, + certificate, + signature, + }), + _ => Err(SealedSessionError::InvalidCertificate), + } + }, + _ => Err(SealedSessionError::InvalidCertificate), + } + } +} + +impl CertificateValidator { + pub fn new(trust_root: PublicKey) -> Self { + Self { trust_root } + } + + pub(crate) fn validate( + &self, + certificate: &SenderCertificate, + validation_time: u64, + ) -> Result<(), SealedSessionError> { + let server_certificate = &certificate.signer; + + match self.trust_root.verify_signature( + &server_certificate.certificate, + &server_certificate.signature, + ) { + Err(_) | Ok(false) => { + return Err(SealedSessionError::InvalidCertificate) + }, + _ => (), + }; + + match server_certificate + .key + .verify_signature(&certificate.certificate, &certificate.signature) + { + Err(_) | Ok(false) => { + return Err(SealedSessionError::InvalidCertificate) + }, + _ => (), + } + + if validation_time > certificate.expiration { + return Err(SealedSessionError::ExpiredCertificate); + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use std::time::{SystemTime, UNIX_EPOCH}; + + use libsignal_protocol::{ + process_prekey_bundle, IdentityKeyPair, IdentityKeyStore, + InMemIdentityKeyStore, InMemPreKeyStore, InMemSessionStore, + InMemSignedPreKeyStore, KeyPair, PreKeyBundle, PreKeyRecord, + PreKeyStore, ProtocolAddress, PublicKey, SignedPreKeyRecord, + SignedPreKeyStore, + }; + + use crate::{provisioning::generate_registration_id, ServiceAddress}; + + use super::{ + CertificateValidator, SealedSessionCipher, SealedSessionError, + SenderCertificate, + }; + + use prost::Message; + + fn alice_address() -> ServiceAddress { + ServiceAddress::parse( + Some("+14151111111"), + Some("9d0652a3-dcc3-4d11-975f-74d61598733f"), + ) + .unwrap() + } + + struct Stores { + identity_key_store: InMemIdentityKeyStore, + session_store: InMemSessionStore, + signed_pre_key_store: InMemSignedPreKeyStore, + pre_key_store: InMemPreKeyStore, + } + + #[tokio::test] + async fn test_encrypt_decrypt() -> anyhow::Result<()> { + let mut csprng = rand::thread_rng(); + + let (alice_stores, bob_stores) = create_stores(&mut csprng).await?; + + let trust_root = KeyPair::generate(&mut csprng); + let certificate_validator = + CertificateValidator::new(trust_root.public_key); + let sender_certificate = create_certificate_for( + &trust_root, + alice_address(), + 1, + *alice_stores + .identity_key_store + .get_identity_key_pair(None) + .await? + .public_key(), + 31337, + &mut csprng, + )?; + + let mut alice_cipher = SealedSessionCipher::new( + alice_stores.session_store, + alice_stores.identity_key_store, + alice_stores.signed_pre_key_store, + alice_stores.pre_key_store, + csprng, + certificate_validator.clone(), + ); + + let ciphertext = alice_cipher + .encrypt( + &ProtocolAddress::new("+14152222222".into(), 1), + sender_certificate, + "smert za smert".as_bytes(), + ) + .await?; + + let mut bob_cipher = SealedSessionCipher::new( + bob_stores.session_store, + bob_stores.identity_key_store, + bob_stores.signed_pre_key_store, + bob_stores.pre_key_store, + csprng, + certificate_validator, + ); + + let plaintext = bob_cipher.decrypt(&ciphertext, 31335).await?; + + assert_eq!( + String::from_utf8_lossy(&plaintext.padded_message), + "smert za smert".to_string() + ); + assert_eq!(plaintext.sender_uuid, alice_address().uuid); + assert_eq!(plaintext.sender_e164, alice_address().phonenumber); + assert_eq!(plaintext.device_id, 1); + + Ok(()) + } + + #[tokio::test] + async fn test_encrypt_decrypt_untrusted() -> anyhow::Result<()> { + let mut csprng = rand::thread_rng(); + let (alice_stores, bob_stores) = create_stores(&mut csprng).await?; + + let trust_root = KeyPair::generate(&mut csprng); + let certificate_validator = + CertificateValidator::new(trust_root.public_key); + + let false_trust_root = KeyPair::generate(&mut csprng); + let false_certificate_validator = + CertificateValidator::new(false_trust_root.public_key); + + let sender_certificate = create_certificate_for( + &trust_root, + alice_address(), + 1, + *alice_stores + .identity_key_store + .get_identity_key_pair(None) + .await? + .public_key(), + 31337, + &mut csprng, + )?; + + let mut alice_cipher = SealedSessionCipher::new( + alice_stores.session_store, + alice_stores.identity_key_store, + alice_stores.signed_pre_key_store, + alice_stores.pre_key_store, + csprng, + certificate_validator, + ); + + let ciphertext = alice_cipher + .encrypt( + &ProtocolAddress::new("+14152222222".into(), 1), + sender_certificate, + "и вот я".as_bytes(), + ) + .await?; + + let mut bob_cipher = SealedSessionCipher::new( + bob_stores.session_store, + bob_stores.identity_key_store, + bob_stores.signed_pre_key_store, + bob_stores.pre_key_store, + csprng, + false_certificate_validator, + ); + + let plaintext = bob_cipher.decrypt(&ciphertext, 31335).await; + + match plaintext { + Err(SealedSessionError::InvalidCertificate) => Ok(()), + _ => panic!("decryption succeeded, this should not happen here!1!"), + } + } + + #[tokio::test] + async fn test_encrypt_decrypt_expired() -> anyhow::Result<()> { + let mut csprng = rand::thread_rng(); + let (alice_stores, bob_stores) = create_stores(&mut csprng).await?; + + let trust_root = KeyPair::generate(&mut csprng); + let certificate_validator = + CertificateValidator::new(trust_root.public_key); + let sender_certificate = create_certificate_for( + &trust_root, + alice_address(), + 1, + *alice_stores + .identity_key_store + .get_identity_key_pair(None) + .await? + .public_key(), + 31337, + &mut csprng, + )?; + + let mut alice_cipher = SealedSessionCipher::new( + alice_stores.session_store, + alice_stores.identity_key_store, + alice_stores.signed_pre_key_store, + alice_stores.pre_key_store, + csprng, + certificate_validator.clone(), + ); + + let ciphertext = alice_cipher + .encrypt( + &ProtocolAddress::new("+14152222222".into(), 1), + sender_certificate, + "smert za smert".as_bytes(), + ) + .await?; + + let mut bob_cipher = SealedSessionCipher::new( + bob_stores.session_store, + bob_stores.identity_key_store, + bob_stores.signed_pre_key_store, + bob_stores.pre_key_store, + csprng, + certificate_validator, + ); + + match bob_cipher.decrypt(&ciphertext, 31338).await { + Err(SealedSessionError::ExpiredCertificate) => Ok(()), + _ => panic!("certificate is expired, we should not get decrypted data here!11!") + } + } + + #[tokio::test] + async fn test_encrypt_from_wrong_identity() -> anyhow::Result<()> { + let mut csprng = rand::thread_rng(); + let (alice_stores, bob_stores) = create_stores(&mut csprng).await?; + + let trust_root = KeyPair::generate(&mut csprng); + let random_key_pair = KeyPair::generate(&mut csprng); + let certificate_validator = + CertificateValidator::new(trust_root.public_key); + let sender_certificate = create_certificate_for( + &random_key_pair, + alice_address(), + 1, + *alice_stores + .identity_key_store + .get_identity_key_pair(None) + .await? + .public_key(), + 31337, + &mut csprng, + )?; + + let mut alice_cipher = SealedSessionCipher::new( + alice_stores.session_store, + alice_stores.identity_key_store, + alice_stores.signed_pre_key_store, + alice_stores.pre_key_store, + csprng, + certificate_validator.clone(), + ); + + let ciphertext = alice_cipher + .encrypt( + &ProtocolAddress::new("+14152222222".into(), 1), + sender_certificate, + "smert za smert".as_bytes(), + ) + .await?; + + let mut bob_cipher = SealedSessionCipher::new( + bob_stores.session_store, + bob_stores.identity_key_store, + bob_stores.signed_pre_key_store, + bob_stores.pre_key_store, + csprng, + certificate_validator, + ); + + match bob_cipher.decrypt(&ciphertext, 31335).await { + Err(SealedSessionError::InvalidCertificate) => Ok(()), + _ => panic!("the certificate is invalid here!11"), + } + } + + async fn create_stores( + csprng: &mut R, + ) -> anyhow::Result<(Stores, Stores)> { + let mut alice_stores = Stores { + identity_key_store: InMemIdentityKeyStore::new( + IdentityKeyPair::generate(csprng), + generate_registration_id(csprng), + ), + session_store: InMemSessionStore::new(), + signed_pre_key_store: InMemSignedPreKeyStore::new(), + pre_key_store: InMemPreKeyStore::new(), + }; + + let mut bob_stores = Stores { + identity_key_store: InMemIdentityKeyStore::new( + IdentityKeyPair::generate(csprng), + generate_registration_id(csprng), + ), + session_store: InMemSessionStore::new(), + signed_pre_key_store: InMemSignedPreKeyStore::new(), + pre_key_store: InMemPreKeyStore::new(), + }; + + initialize_session(&mut alice_stores, &mut bob_stores, csprng).await?; + + Ok((alice_stores, bob_stores)) + } + + fn create_certificate_for( + trust_root: &KeyPair, + addr: ServiceAddress, + device_id: u32, + identity_key: PublicKey, + expires: u64, + csprng: &mut R, + ) -> Result { + let server_key = KeyPair::generate(csprng); + + let uuid = addr.uuid.as_ref().map(uuid::Uuid::to_string); + let e164 = addr.e164(); + + let server_certificate_bytes = + crate::proto::server_certificate::Certificate { + id: Some(1), + key: Some(server_key.public_key.serialize().into_vec()), + } + .encode_to_vec(); + + let server_certificate_signature = trust_root + .private_key + .calculate_signature(&server_certificate_bytes, csprng)?; + + let server_certificate = crate::proto::ServerCertificate { + certificate: Some(server_certificate_bytes), + signature: Some(server_certificate_signature.into_vec()), + }; + + let sender_certificate_bytes = + crate::proto::sender_certificate::Certificate { + sender_uuid: uuid, + sender_e164: e164, + sender_device: Some(device_id), + identity_key: Some(identity_key.serialize().into_vec()), + expires: Some(expires), + signer: Some(server_certificate), + } + .encode_to_vec(); + + let sender_certificate_signature = server_key + .private_key + .calculate_signature(&sender_certificate_bytes, csprng)?; + + SenderCertificate::try_from(crate::proto::SenderCertificate { + certificate: Some(sender_certificate_bytes), + signature: Some(sender_certificate_signature.into_vec()), + }) + } + + async fn initialize_session( + alice_stores: &mut Stores, + bob_stores: &mut Stores, + csprng: &mut R, + ) -> Result<(), SealedSessionError> { + let bob_pre_key = PreKeyRecord::new(1, &KeyPair::generate(csprng)); + let bob_identity_key_pair = bob_stores + .identity_key_store + .get_identity_key_pair(None) + .await?; + + // TODO: check + let signed_pre_key_pair = KeyPair::generate(csprng); + let signed_pre_key_signature = bob_identity_key_pair + .private_key() + .calculate_signature( + &signed_pre_key_pair.public_key.serialize(), + csprng, + )? + .into_vec(); + + let bob_signed_pre_key_record = SignedPreKeyRecord::new( + 2, + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() as u64, + &signed_pre_key_pair, + &signed_pre_key_signature, + ); + + let bob_bundle = PreKeyBundle::new( + 1, + 1, + Some((1, bob_pre_key.public_key()?)), + 2, + signed_pre_key_pair.public_key, + signed_pre_key_signature, + *bob_identity_key_pair.identity_key(), + )?; + + process_prekey_bundle( + &ProtocolAddress::new("+14152222222".into(), 1), + &mut alice_stores.session_store, + &mut alice_stores.identity_key_store, + &bob_bundle, + csprng, + None, + ) + .await?; + + bob_stores + .signed_pre_key_store + .save_signed_pre_key(2, &bob_signed_pre_key_record, None) + .await?; + bob_stores + .pre_key_store + .save_pre_key(1, &bob_pre_key, None) + .await?; + Ok(()) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/sender.rs b/net/gurk-rs/files/vendor/libsignal-service/src/sender.rs new file mode 100644 index 0000000..78a7524 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/sender.rs @@ -0,0 +1,765 @@ +use std::time::SystemTime; + +use chrono::prelude::*; +use libsignal_protocol::{ + process_prekey_bundle, IdentityKeyStore, PreKeyStore, ProtocolAddress, + SessionStore, SignalProtocolError, SignedPreKeyStore, +}; +use log::{info, trace}; +use rand::{CryptoRng, Rng}; + +use crate::{ + cipher::{get_preferred_protocol_address, ServiceCipher}, + content::ContentBody, + proto::{ + attachment_pointer::AttachmentIdentifier, + attachment_pointer::Flags as AttachmentPointerFlags, sync_message, + AttachmentPointer, SyncMessage, + }, + push_service::*, + sealed_session_cipher::UnidentifiedAccess, + session_store::SessionStoreExt, + ServiceAddress, +}; + +pub use crate::proto::{ContactDetails, GroupDetails}; + +#[derive(serde::Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct OutgoingPushMessage { + pub r#type: u32, + pub destination_device_id: u32, + pub destination_registration_id: u32, + pub content: String, +} + +#[derive(serde::Serialize, Debug)] +pub struct OutgoingPushMessages<'a> { + pub destination: &'a str, + pub timestamp: u64, + pub messages: Vec, + pub online: bool, +} + +#[derive(serde::Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct SendMessageResponse { + pub needs_sync: bool, +} + +pub type SendMessageResult = Result; + +#[derive(Debug, Clone)] +pub struct SentMessage { + recipient: ServiceAddress, + unidentified: bool, + needs_sync: bool, +} + +/// Attachment specification to be used for uploading. +/// +/// Loose equivalent of Java's `SignalServiceAttachmentStream`. +pub struct AttachmentSpec { + pub content_type: String, + pub length: usize, + pub file_name: Option, + pub preview: Option>, + pub voice_note: Option, + pub borderless: Option, + pub width: Option, + pub height: Option, + pub caption: Option, + pub blur_hash: Option, +} + +/// Equivalent of Java's `SignalServiceMessageSender`. +#[derive(Clone)] +pub struct MessageSender { + service: Service, + cipher: ServiceCipher, + csprng: R, + session_store: S, + identity_key_store: I, + local_address: ServiceAddress, + device_id: u32, +} + +#[derive(thiserror::Error, Debug)] +pub enum AttachmentUploadError { + #[error("{0}")] + ServiceError(#[from] ServiceError), + + #[error("Could not read attachment contents")] + IoError(#[from] std::io::Error), +} + +#[derive(thiserror::Error, Debug)] +pub enum MessageSenderError { + #[error("{0}")] + ServiceError(#[from] ServiceError), + #[error("protocol error: {0}")] + ProtocolError(#[from] SignalProtocolError), + #[error("Failed to upload attachment {0}")] + AttachmentUploadError(#[from] AttachmentUploadError), + + #[error("Untrusted identity key with {identifier}")] + UntrustedIdentity { identifier: String }, + + #[error("No pre-key found to establish session with {0:?}")] + NoPreKey(ServiceAddress), + + #[error("Please try again")] + TryAgain, + + #[error("Exceeded maximum number of retries")] + MaximumRetriesLimitExceeded, + + #[error("Network failure sending message to {recipient}")] + NetworkFailure { recipient: ServiceAddress }, + + #[error("Unregistered recipient {recipient}")] + UnregisteredFailure { recipient: ServiceAddress }, + + #[error("Identity verification failure with {recipient}")] + IdentityFailure { recipient: ServiceAddress }, +} + +impl MessageSender +where + Service: PushService + Clone, + S: SessionStore + SessionStoreExt + Sync + Clone, + I: IdentityKeyStore + Clone, + SP: SignedPreKeyStore + Clone, + P: PreKeyStore + Clone, + R: Rng + CryptoRng + Clone, +{ + pub fn new( + service: Service, + cipher: ServiceCipher, + csprng: R, + session_store: S, + identity_key_store: I, + local_address: ServiceAddress, + device_id: u32, + ) -> Self { + MessageSender { + service, + cipher, + csprng, + session_store, + identity_key_store, + local_address, + device_id, + } + } + + /// Encrypts and uploads an attachment + /// + /// Contents are accepted as an owned, plain text Vec, because encryption happens in-place. + pub async fn upload_attachment( + &mut self, + spec: AttachmentSpec, + mut contents: Vec, + ) -> Result { + let len = contents.len(); + // Encrypt + let (key, iv) = { + use rand::RngCore; + let mut key = [0u8; 64]; + let mut iv = [0u8; 16]; + // thread_rng is guaranteed to be cryptographically secure + rand::thread_rng().fill_bytes(&mut key); + rand::thread_rng().fill_bytes(&mut iv); + (key, iv) + }; + + // Padded length uses an exponential bracketting thingy. + // If you want to see how it looks: + // https://www.wolframalpha.com/input/?i=plot+floor%281.05%5Eceil%28log_1.05%28x%29%29%29+for+x+from+0+to+5000000 + let padded_len: usize = { + // Java: + // return (int) Math.max(541, Math.floor(Math.pow(1.05, Math.ceil(Math.log(size) / Math.log(1.05))))) + std::cmp::max( + 541, + 1.05f64.powf((len as f64).log(1.05).ceil()).floor() as usize, + ) + }; + if padded_len < len { + log::error!( + "Padded len {} < len {}. Continuing with a privacy risk.", + padded_len, + len + ); + } else { + contents.resize(padded_len, 0); + } + + crate::attachment_cipher::encrypt_in_place(iv, key, &mut contents); + + // Request upload attributes + log::trace!("Requesting upload attributes"); + let attrs = self.service.get_attachment_v2_upload_attributes().await?; + + log::trace!("Uploading attachment"); + let (id, digest) = self + .service + .upload_attachment(&attrs, &mut std::io::Cursor::new(&contents)) + .await?; + + Ok(AttachmentPointer { + content_type: Some(spec.content_type), + key: Some(key.to_vec()), + size: Some(len as u32), + // thumbnail: Option>, + digest: Some(digest), + file_name: spec.file_name, + flags: Some( + if spec.voice_note == Some(true) { + AttachmentPointerFlags::VoiceMessage as u32 + } else { + 0 + } | if spec.borderless == Some(true) { + AttachmentPointerFlags::Borderless as u32 + } else { + 0 + }, + ), + width: spec.width, + height: spec.height, + caption: spec.caption, + blur_hash: spec.blur_hash, + upload_timestamp: Some( + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("unix epoch in the past") + .as_millis() as u64, + ), + cdn_number: Some(0), + attachment_identifier: Some(AttachmentIdentifier::CdnId(id)), + ..Default::default() + }) + } + + /// Upload group details to the CDN + /// + /// Returns attachment ID and the attachment digest + async fn upload_group_details( + &mut self, + groups: Groups, + ) -> Result + where + Groups: IntoIterator, + { + use prost::Message; + let mut out = Vec::new(); + for group in groups { + group + .encode_length_delimited(&mut out) + .expect("infallible encoding"); + // XXX add avatar here + } + + let spec = AttachmentSpec { + content_type: "application/octet-stream".into(), + length: out.len(), + file_name: None, + preview: None, + voice_note: None, + borderless: None, + width: None, + height: None, + caption: None, + blur_hash: None, + }; + self.upload_attachment(spec, out).await + } + + /// Upload contact details to the CDN + /// + /// Returns attachment ID and the attachment digest + async fn upload_contact_details( + &mut self, + contacts: Contacts, + ) -> Result + where + Contacts: IntoIterator, + { + use prost::Message; + let mut out = Vec::new(); + for contact in contacts { + contact + .encode_length_delimited(&mut out) + .expect("infallible encoding"); + // XXX add avatar here + } + + let spec = AttachmentSpec { + content_type: "application/octet-stream".into(), + length: out.len(), + file_name: None, + preview: None, + voice_note: None, + borderless: None, + width: None, + height: None, + caption: None, + blur_hash: None, + }; + self.upload_attachment(spec, out).await + } + + /// Send a message `content` to a single `recipient`. + pub async fn send_message( + &mut self, + recipient: &ServiceAddress, + unidentified_access: Option<&UnidentifiedAccess>, + message: impl Into, + timestamp: u64, + online: bool, + ) -> SendMessageResult { + let content_body = message.into(); + + use crate::proto::data_message::Flags; + let end_session = match &content_body { + ContentBody::DataMessage(message) => { + message.flags == Some(Flags::EndSession as u32) + }, + _ => false, + }; + + let mut results = vec![ + self.try_send_message( + recipient.clone(), + unidentified_access, + &content_body, + timestamp, + online, + ) + .await, + ]; + + match (&content_body, &results[0]) { + // if we sent a data message and we have linked devices, we need to send a sync message + ( + ContentBody::DataMessage(message), + Ok(SentMessage { needs_sync, .. }), + ) if *needs_sync => { + log::debug!("sending multi-device sync message"); + let sync_message = self + .create_multi_device_sent_transcript_content( + Some(recipient), + Some(message.clone()), + timestamp, + &results, + ); + self.try_send_message( + (&self.local_address).clone(), + None, + &sync_message, + timestamp, + false, + ) + .await?; + }, + _ => (), + } + + if end_session { + log::debug!("ending session with {}", recipient); + if let Some(ref uuid) = recipient.uuid { + self.session_store + .delete_all_sessions(&uuid.to_string()) + .await?; + } + if let Some(e164) = recipient.e164() { + self.session_store.delete_all_sessions(&e164).await?; + } + } + + results.remove(0) + } + + /// Send a message to the recipients in a group. + pub async fn send_message_to_group( + &mut self, + recipients: impl AsRef<[ServiceAddress]>, + unidentified_access: Option<&UnidentifiedAccess>, + message: crate::proto::DataMessage, + timestamp: u64, + online: bool, + ) -> Vec { + let content_body: ContentBody = message.clone().into(); + let mut results = vec![]; + + let recipients = recipients.as_ref(); + let mut needs_sync_in_results = false; + for recipient in recipients.iter() { + let result = self + .try_send_message( + recipient.clone(), + unidentified_access, + &content_body, + timestamp, + online, + ) + .await; + + match result { + Ok(SentMessage { needs_sync, .. }) if needs_sync => { + needs_sync_in_results = true; + }, + _ => (), + }; + + results.push(result); + } + + // we only need to send a synchronization message once + if needs_sync_in_results { + let sync_message = self + .create_multi_device_sent_transcript_content( + None, + Some(message.clone()), + timestamp, + &results, + ); + + let result = self + .try_send_message( + self.local_address.clone(), + unidentified_access, + &sync_message, + timestamp, + false, + ) + .await; + + results.push(result); + } + + results + } + + /// Send a message (`content`) to an address (`recipient`). + async fn try_send_message( + &mut self, + recipient: ServiceAddress, + unidentified_access: Option<&UnidentifiedAccess>, + content_body: &ContentBody, + timestamp: u64, + online: bool, + ) -> SendMessageResult { + use prost::Message; + let content = content_body.clone().into_proto(); + let content_bytes = content.encode_to_vec(); + + for _ in 0..4u8 { + let messages = self + .create_encrypted_messages(&recipient, None, &content_bytes) + .await?; + + let destination = recipient.identifier(); + let messages = OutgoingPushMessages { + destination: &destination, + timestamp, + messages, + online, + }; + + match self.service.send_messages(messages).await { + Ok(SendMessageResponse { needs_sync }) => { + log::debug!("message sent!"); + return Ok(SentMessage { + recipient, + unidentified: unidentified_access.is_some(), + needs_sync, + }); + }, + Err(ServiceError::MismatchedDevicesException(ref m)) => { + log::debug!("{:?}", m); + for extra_device_id in &m.extra_devices { + log::debug!( + "dropping session with device {}", + extra_device_id + ); + self.session_store + .delete_service_addr_device_session( + &recipient, + *extra_device_id, + ) + .await?; + } + + for missing_device_id in &m.missing_devices { + log::debug!( + "creating session with missing device {}", + missing_device_id + ); + let remote_address = ProtocolAddress::new( + recipient.identifier(), + *missing_device_id, + ); + let pre_key = self + .service + .get_pre_key(&recipient, *missing_device_id) + .await?; + + process_prekey_bundle( + &remote_address, + &mut self.session_store, + &mut self.identity_key_store, + &pre_key, + &mut self.csprng, + None, + ) + .await + .map_err(|e| { + log::error!("failed to create session: {}", e); + MessageSenderError::UntrustedIdentity { + identifier: recipient.identifier(), + } + })?; + } + }, + Err(ServiceError::StaleDevices(ref m)) => { + log::debug!("{:?}", m); + for extra_device_id in &m.stale_devices { + log::debug!( + "dropping session with device {}", + extra_device_id + ); + self.session_store + .delete_service_addr_device_session( + &recipient, + *extra_device_id, + ) + .await?; + } + }, + Err(e) => return Err(MessageSenderError::ServiceError(e)), + } + } + + Err(MessageSenderError::MaximumRetriesLimitExceeded) + } + + /// Upload group details to the CDN and send a sync message + pub async fn send_groups_details( + &mut self, + recipient: &ServiceAddress, + unidentified_access: Option<&UnidentifiedAccess>, + // XXX It may be interesting to use an intermediary type, + // instead of GroupDetails directly, + // because it allows us to add the avatar content. + groups: Groups, + online: bool, + ) -> Result<(), MessageSenderError> + where + Groups: IntoIterator, + { + let ptr = self.upload_group_details(groups).await?; + + let msg = SyncMessage { + groups: Some(sync_message::Groups { blob: Some(ptr) }), + ..Default::default() + }; + + self.send_message( + recipient, + unidentified_access, + msg, + Utc::now().timestamp_millis() as u64, + online, + ) + .await?; + + Ok(()) + } + + /// Upload contact details to the CDN and send a sync message + pub async fn send_contact_details( + &mut self, + recipient: &ServiceAddress, + unidentified_access: Option<&UnidentifiedAccess>, + // XXX It may be interesting to use an intermediary type, + // instead of ContactDetails directly, + // because it allows us to add the avatar content. + contacts: Contacts, + online: bool, + complete: bool, + ) -> Result<(), MessageSenderError> + where + Contacts: IntoIterator, + { + let ptr = self.upload_contact_details(contacts).await?; + + let msg = SyncMessage { + contacts: Some(sync_message::Contacts { + blob: Some(ptr), + complete: Some(complete), + }), + ..Default::default() + }; + + self.send_message( + recipient, + unidentified_access, + msg, + Utc::now().timestamp_millis() as u64, + online, + ) + .await?; + + Ok(()) + } + + // Equivalent with `getEncryptedMessages` + async fn create_encrypted_messages( + &mut self, + recipient: &ServiceAddress, + unidentified_access: Option, + content: &[u8], + ) -> Result, MessageSenderError> { + let mut messages = vec![]; + + let myself = recipient.matches(&self.local_address); + if !myself || unidentified_access.is_some() { + trace!("sending message to default device"); + messages.push( + self.create_encrypted_message( + recipient, + unidentified_access.as_ref(), + DEFAULT_DEVICE_ID, + content, + ) + .await?, + ); + } + + for device_id in + recipient.sub_device_sessions(&self.session_store).await? + { + trace!("sending message to device {}", device_id); + let ppa = get_preferred_protocol_address( + &self.session_store, + recipient, + device_id, + ) + .await?; + if self.session_store.load_session(&ppa, None).await?.is_some() { + messages.push( + self.create_encrypted_message( + recipient, + unidentified_access.as_ref(), + device_id, + content, + ) + .await?, + ) + } + } + + Ok(messages) + } + + /// Equivalent to `getEncryptedMessage` + /// + /// When no session with the recipient exists, we need to create one. + async fn create_encrypted_message( + &mut self, + recipient: &ServiceAddress, + unidentified_access: Option<&UnidentifiedAccess>, + device_id: u32, + content: &[u8], + ) -> Result { + let recipient_address = get_preferred_protocol_address( + &self.session_store, + recipient, + device_id, + ) + .await?; + log::trace!("encrypting message for {:?}", recipient_address); + + if self + .session_store + .load_session(&recipient_address, None) + .await? + .is_none() + { + info!("establishing new session with {:?}", recipient_address); + let pre_keys = + self.service.get_pre_keys(recipient, device_id).await?; + for pre_key_bundle in pre_keys { + if recipient.matches(&self.local_address) + && self.device_id == pre_key_bundle.device_id()? + { + trace!("not establishing a session with myself!"); + continue; + } + + let pre_key_address = get_preferred_protocol_address( + &self.session_store, + recipient, + pre_key_bundle.device_id()?, + ) + .await?; + + process_prekey_bundle( + &pre_key_address, + &mut self.session_store, + &mut self.identity_key_store, + &pre_key_bundle, + &mut self.csprng, + None, + ) + .await?; + } + } + + let message = self + .cipher + .encrypt(&recipient_address, unidentified_access, content) + .await?; + Ok(message) + } + + fn create_multi_device_sent_transcript_content( + &self, + recipient: Option<&ServiceAddress>, + data_message: Option, + timestamp: u64, + send_message_results: &[SendMessageResult], + ) -> ContentBody { + use sync_message::sent::UnidentifiedDeliveryStatus; + let unidentified_status: Vec = + send_message_results + .iter() + .filter_map(|result| result.as_ref().ok()) + .map(|sent| { + let SentMessage { + recipient, + unidentified, + .. + } = sent; + UnidentifiedDeliveryStatus { + destination_e164: recipient.e164(), + destination_uuid: recipient.uuid.map(|s| s.to_string()), + unidentified: Some(*unidentified), + } + }) + .collect(); + ContentBody::SynchronizeMessage(SyncMessage { + sent: Some(sync_message::Sent { + destination_uuid: recipient + .and_then(|r| r.uuid) + .map(|u| u.to_string()), + destination_e164: recipient.and_then(|r| r.e164()), + message: data_message, + timestamp: Some(timestamp), + unidentified_status, + ..Default::default() + }), + ..Default::default() + }) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/service_address.rs b/net/gurk-rs/files/vendor/libsignal-service/src/service_address.rs new file mode 100644 index 0000000..f183836 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/service_address.rs @@ -0,0 +1,119 @@ +use phonenumber::*; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::{push_service::ServiceError, session_store::SessionStoreExt}; + +#[derive(thiserror::Error, Debug)] +pub enum ParseServiceAddressError { + #[error("Supplied phone number could not be parsed in E164 format")] + InvalidPhoneNumber(#[from] phonenumber::ParseError), + + #[error("Supplied uuid could not be parsed")] + InvalidUuidError(#[from] uuid::Error), + + #[error("Envelope with neither Uuid or E164")] + NoSenderError, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct ServiceAddress { + pub uuid: Option, + pub phonenumber: Option, + pub relay: Option, +} + +impl ServiceAddress { + /// Formats the phone number, if present, as E164 + pub fn e164(&self) -> Option { + self.phonenumber + .as_ref() + .map(|pn| pn.format().mode(phonenumber::Mode::E164).to_string()) + } + + pub async fn sub_device_sessions( + &self, + session_store: &dyn SessionStoreExt, + ) -> Result, ServiceError> { + let mut sub_device_sessions = Vec::new(); + if let Some(uuid) = &self.uuid { + sub_device_sessions.extend( + session_store + .get_sub_device_sessions(&uuid.to_string()) + .await?, + ); + } + if let Some(e164) = &self.e164() { + sub_device_sessions + .extend(session_store.get_sub_device_sessions(e164).await?); + } + Ok(sub_device_sessions) + } +} + +impl std::fmt::Display for ServiceAddress { + fn fmt( + &self, + f: &mut std::fmt::Formatter<'_>, + ) -> Result<(), std::fmt::Error> { + match (&self.uuid, &self.phonenumber, &self.relay) { + (_, Some(e164), _) => write!(f, "ServiceAddress({})", e164), + (Some(uuid), _, _) => write!(f, "ServiceAddress({})", uuid), + _ => write!(f, "ServiceAddress(INVALID)"), + } + } +} + +impl ServiceAddress { + pub fn parse( + e164: Option<&str>, + uuid: Option<&str>, + ) -> Result { + let phonenumber = + e164.map(|s| phonenumber::parse(None, s)).transpose()?; + let uuid = uuid.map(Uuid::parse_str).transpose()?; + + Ok(ServiceAddress { + phonenumber, + uuid, + relay: None, + }) + } + + /// Returns uuid if present, e164 otherwise. + pub fn identifier(&self) -> String { + if let Some(ref uuid) = self.uuid { + return uuid.to_string(); + } else if let Some(e164) = self.e164() { + return e164; + } + unreachable!( + "an address requires either a UUID or a E164 phone number" + ); + } + + pub fn matches(&self, other: &Self) -> bool { + (self.phonenumber.is_some() && self.phonenumber == other.phonenumber) + || (self.uuid.is_some() && self.uuid == other.uuid) + } +} + +impl From for ServiceAddress { + fn from(uuid: Uuid) -> Self { + ServiceAddress { + uuid: Some(uuid), + phonenumber: None, + relay: None, + } + } +} + +impl From for ServiceAddress { + fn from(phone_number: PhoneNumber) -> Self { + ServiceAddress { + uuid: None, + phonenumber: Some(phone_number), + relay: None, + } + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/session_store.rs b/net/gurk-rs/files/vendor/libsignal-service/src/session_store.rs new file mode 100644 index 0000000..45a066b --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/session_store.rs @@ -0,0 +1,69 @@ +use libsignal_protocol::{ProtocolAddress, SessionStore, SignalProtocolError}; + +use crate::ServiceAddress; + +/// This is additional functions required to handle +/// session deletion. It might be a candidate for inclusion into +/// the bigger `SessionStore` trait. +#[cfg_attr(feature = "unsend-futures", async_trait::async_trait(?Send))] +#[cfg_attr(not(feature = "unsend-futures"), async_trait::async_trait)] +pub trait SessionStoreExt: SessionStore { + /// Get the IDs of all known devices with active sessions for a recipient. + async fn get_sub_device_sessions( + &self, + name: &str, + ) -> Result, SignalProtocolError>; + + /// Remove a session record for a recipient ID + device ID tuple. + async fn delete_session( + &self, + address: &ProtocolAddress, + ) -> Result<(), SignalProtocolError>; + + /// Remove the session records corresponding to all devices of a recipient + /// ID. + /// + /// Returns the number of deleted sessions. + async fn delete_all_sessions( + &self, + address: &str, + ) -> Result; + + /// Remove a session record for a recipient ID + device ID tuple. + async fn delete_service_addr_device_session( + &self, + address: &ServiceAddress, + device_id: u32, + ) -> Result { + let mut count = 0; + if let Some(ref uuid) = address.uuid { + match self + .delete_session(&ProtocolAddress::new( + uuid.to_string(), + device_id, + )) + .await + { + Ok(()) => { + count += 1; + }, + Err(SignalProtocolError::SessionNotFound(_)) => (), + Err(e) => return Err(e), + } + } + if let Some(e164) = address.e164() { + match self + .delete_session(&ProtocolAddress::new(e164, device_id)) + .await + { + Ok(()) => { + count += 1; + }, + Err(SignalProtocolError::SessionNotFound(_)) => (), + Err(e) => return Err(e), + } + } + + Ok(count) + } +} diff --git a/net/gurk-rs/files/vendor/libsignal-service/src/utils.rs b/net/gurk-rs/files/vendor/libsignal-service/src/utils.rs new file mode 100644 index 0000000..8b15447 --- /dev/null +++ b/net/gurk-rs/files/vendor/libsignal-service/src/utils.rs @@ -0,0 +1,145 @@ +pub mod serde_base64 { + use serde::{Deserialize, Deserializer, Serializer}; + + pub fn serialize(bytes: &T, serializer: S) -> Result + where + T: AsRef<[u8]>, + S: Serializer, + { + serializer.serialize_str(&base64::encode(bytes.as_ref())) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + use serde::de::Error; + String::deserialize(deserializer).and_then(|string| { + base64::decode(&string) + .map_err(|err| Error::custom(err.to_string())) + }) + } +} + +pub mod serde_optional_base64 { + use serde::{Deserialize, Deserializer, Serializer}; + + pub fn serialize( + bytes: &Option, + serializer: S, + ) -> Result + where + T: AsRef<[u8]>, + S: Serializer, + { + match bytes { + Some(bytes) => { + serializer.serialize_str(&base64::encode(bytes.as_ref())) + }, + None => serializer.serialize_none(), + } + } + + pub fn deserialize<'de, D>( + deserializer: D, + ) -> Result>, D::Error> + where + D: Deserializer<'de>, + { + use serde::de::Error; + match Option::::deserialize(deserializer)? { + Some(s) => base64::decode(&s) + .map_err(|err| Error::custom(err.to_string())) + .map(Some), + None => Ok(None), + } + } +} + +pub mod serde_public_key { + use libsignal_protocol::PublicKey; + use serde::{Deserialize, Deserializer, Serializer}; + + pub fn serialize( + public_key: &PublicKey, + serializer: S, + ) -> Result + where + S: Serializer, + { + let public_key = public_key.serialize(); + serializer.serialize_str(&base64::encode(&public_key)) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + PublicKey::deserialize( + &base64::decode(String::deserialize(deserializer)?) + .map_err(serde::de::Error::custom)?, + ) + .map_err(serde::de::Error::custom) + } +} + +pub mod serde_private_key { + use libsignal_protocol::PrivateKey; + use serde::{Deserialize, Deserializer, Serializer}; + + pub fn serialize( + public_key: &PrivateKey, + serializer: S, + ) -> Result + where + S: Serializer, + { + let public_key = public_key.serialize(); + serializer.serialize_str(&base64::encode(&public_key)) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + PrivateKey::deserialize( + &base64::decode(String::deserialize(deserializer)?) + .map_err(serde::de::Error::custom)?, + ) + .map_err(serde::de::Error::custom) + } +} + +pub mod serde_signaling_key { + use std::convert::TryInto; + + use crate::configuration::SignalingKey; + use serde::{Deserialize, Deserializer, Serializer}; + + pub fn serialize( + signaling_key: &SignalingKey, + serializer: S, + ) -> Result + where + S: Serializer, + { + serializer.serialize_str(&base64::encode(signaling_key)) + } + + pub fn deserialize<'de, D>( + deserializer: D, + ) -> Result + where + D: Deserializer<'de>, + { + base64::decode(String::deserialize(deserializer)?) + .map_err(serde::de::Error::custom)? + .try_into() + .map_err(|buf: Vec| { + serde::de::Error::invalid_length( + buf.len(), + &"invalid signaling key length", + ) + }) + } +} diff --git a/net/gurk-rs/files/vendor/poksho/.cargo-checksum.json b/net/gurk-rs/files/vendor/poksho/.cargo-checksum.json new file mode 100644 index 0000000..b613875 --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"bd6f15613c220593ac255bb0cbb00912a2f02fea81a677fa79eb8f0be791c301","LICENSE":"b464c1a66f1760ccd0d71b24dd294bf1c23dd6a6f0b08610a6572f6f7f81f0e8","README.md":"0e84814c851ccf230126962fa479871a9b7096c9fa8ab6355cacd069460247c3","src/args.rs":"7b575d1c4f7257d9a39279ebacc0578a84e6263ddd545871047faf23f1bb1dc2","src/errors.rs":"c2cca106ba437da185b598907a164f7f836495d65def764ba8210c0d6172072b","src/lib.rs":"70340dbc0f578f0dab5070099678a531db71fdcc046d56cb3a992b6faa51b89a","src/proof.rs":"2f98a4d74aa25ae074556df419447a8876450349c5c5398cae330a34ca8a712c","src/scalar.rs":"87c5537f03cee15dfaae506ca3a0b69ed2d52abe34e9e1e0b9bb2431329576d5","src/shoapi.rs":"40bd425df2395ffb29d010c4b4a69e98432cc34533efb38b825ef5734dcf9fe8","src/shohmacsha256.rs":"30fbf2a85a155f92de51e6868112489b3825c5f57b1370bed9f14f68f174b8bc","src/shosha256.rs":"d8351280043a05f56601333ea2695faaf5a117bd243764e4655019fe50a2b555","src/sign.rs":"398d9189faf4278986899bc00308ff0b6bc1f6902f6b36def10fc58ad454106c","src/simple_types.rs":"7129bf743e4c5affa238df63e1c806b79557a595bc39128e2b2a28a7abb6acc0","src/statement.rs":"60e0445cd819c3ad2dc65cf706e01286fba4b47748bc13f2b3d77da59975692f"},"package":null} \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/poksho/Cargo.toml b/net/gurk-rs/files/vendor/poksho/Cargo.toml new file mode 100644 index 0000000..8918384 --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/Cargo.toml @@ -0,0 +1,30 @@ +# +# Copyright (C) 2020 Signal Messenger, LLC. +# All rights reserved. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +[package] +name = "poksho" +version = "0.7.0" +authors = ["Trevor Perrin "] +edition = "2018" +license = "GPL-3.0-only" + +[dependencies] +sha2 = "0.8.0" +hmac = "0.7.1" + +[dependencies.curve25519-dalek] +features = ["serde", "alloc"] +version = "2.0.0" +git = "https://github.com/signalapp/curve25519-dalek.git" +branch = "lizard2" + +[features] +default = ["u64_backend"] +u32_backend = ["curve25519-dalek/u32_backend"] +u64_backend = ["curve25519-dalek/u64_backend"] +simd_backend = ["curve25519-dalek/simd_backend"] +nightly = ["curve25519-dalek/nightly"] diff --git a/net/gurk-rs/files/vendor/poksho/LICENSE b/net/gurk-rs/files/vendor/poksho/LICENSE new file mode 100644 index 0000000..82c2048 --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/LICENSE @@ -0,0 +1,628 @@ +This software is provided under: + + SPDX-License-Identifier: GPL-3.0-only + +The complete license text: + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + diff --git a/net/gurk-rs/files/vendor/poksho/README.md b/net/gurk-rs/files/vendor/poksho/README.md new file mode 100644 index 0000000..802ef7c --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/README.md @@ -0,0 +1,10 @@ +# poksho + +This is some incomplete code used for testing. + +Most of the cryptography here is going to change and has not been reviewed, so +this project should not be used. + + + + diff --git a/net/gurk-rs/files/vendor/poksho/src/args.rs b/net/gurk-rs/files/vendor/poksho/src/args.rs new file mode 100644 index 0000000..0f0bc7b --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/src/args.rs @@ -0,0 +1,38 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; +use std::collections::HashMap; + +// Simple 'newtype' wrappers around HashMap to make string literals more convenient + +#[derive(Clone)] +pub struct ScalarArgs(pub HashMap); + +#[derive(Clone)] +pub struct PointArgs(pub HashMap); + +impl ScalarArgs { + pub fn new() -> Self { + Self(HashMap::::new()) + } + + pub fn add(&mut self, s: &str, val: Scalar) { + self.0.insert(s.to_string(), val); + } +} + +impl PointArgs { + pub fn new() -> Self { + Self(HashMap::::new()) + } + + pub fn add(&mut self, s: &str, val: RistrettoPoint) { + self.0.insert(s.to_string(), val); + } +} diff --git a/net/gurk-rs/files/vendor/poksho/src/errors.rs b/net/gurk-rs/files/vendor/poksho/src/errors.rs new file mode 100644 index 0000000..30169cc --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/src/errors.rs @@ -0,0 +1,17 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#[derive(Debug)] +pub enum PokshoError { + BadArgs, // Bad arguments were passed to the function + BadArgsWrongNumberOfScalarArgs, // Bad arguments were passed to the function + BadArgsWrongNumberOfPointArgs, // Bad arguments were passed to the function + BadArgsMissingScalarArg, // Bad arguments were passed to the function + BadArgsMissingPointArg, // Bad arguments were passed to the function + VerificationFailure, // Proof verification failed + ProofCreationVerificationFailure, // Proof verification failed during proof creation, indicating bad inputs or faulty computation +} diff --git a/net/gurk-rs/files/vendor/poksho/src/lib.rs b/net/gurk-rs/files/vendor/poksho/src/lib.rs new file mode 100644 index 0000000..2aa0438 --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/src/lib.rs @@ -0,0 +1,27 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +pub mod args; +pub mod errors; +pub mod proof; +pub mod scalar; +pub mod shoapi; +pub mod shohmacsha256; +pub mod shosha256; +pub mod sign; +mod simple_types; +pub mod statement; + +pub use args::{PointArgs, ScalarArgs}; +pub use errors::PokshoError; +pub use proof::Proof; +pub use scalar::{scalar_from_slice_canonical, scalar_from_slice_wide}; +pub use shoapi::ShoApi; +pub use shohmacsha256::ShoHmacSha256; +pub use shosha256::ShoSha256; +pub use sign::{sign, verify_signature}; +pub use statement::Statement; diff --git a/net/gurk-rs/files/vendor/poksho/src/proof.rs b/net/gurk-rs/files/vendor/poksho/src/proof.rs new file mode 100644 index 0000000..140b30c --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/src/proof.rs @@ -0,0 +1,43 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +use crate::scalar::*; +use crate::simple_types::*; +use curve25519_dalek::scalar::Scalar; + +// We use compact Schnorr signatures, sending the challenge instead of commitments +pub struct Proof { + pub challenge: Scalar, + pub response: G1, +} + +impl Proof { + pub fn from_slice(bytes: &[u8]) -> Option { + let num_scalars = bytes.len() / 32; + if num_scalars < 2 || num_scalars > 257 || num_scalars * 32 != bytes.len() { + return None; + } + let challenge = scalar_from_slice_canonical(&bytes[0..32])?; + let mut response = Vec::::with_capacity(num_scalars - 1); + for i in 1..num_scalars { + response.push(scalar_from_slice_canonical(&bytes[32 * i..(32 * i) + 32])?); + } + Some(Proof { + challenge, + response, + }) + } + + pub fn to_bytes(&self) -> Vec { + let mut bytes = Vec::::with_capacity(self.response.len() * 32); + bytes.extend_from_slice(self.challenge.as_bytes()); + for scalar in &self.response { + bytes.extend_from_slice(scalar.as_bytes()); + } + bytes + } +} diff --git a/net/gurk-rs/files/vendor/poksho/src/scalar.rs b/net/gurk-rs/files/vendor/poksho/src/scalar.rs new file mode 100644 index 0000000..311b69d --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/src/scalar.rs @@ -0,0 +1,22 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +use curve25519_dalek::scalar::Scalar; + +// Because Rust can't create array references from slices (yet) +pub fn scalar_from_slice_wide(bytes: &[u8]) -> Scalar { + let mut scalar_bytes = [0u8; 64]; + scalar_bytes.copy_from_slice(bytes); + Scalar::from_bytes_mod_order_wide(&scalar_bytes) +} + +// Because Rust can't create array references from slices (yet) +pub fn scalar_from_slice_canonical(bytes: &[u8]) -> Option { + let mut scalar_bytes = [0u8; 32]; + scalar_bytes.copy_from_slice(bytes); + Scalar::from_canonical_bytes(scalar_bytes) +} diff --git a/net/gurk-rs/files/vendor/poksho/src/shoapi.rs b/net/gurk-rs/files/vendor/poksho/src/shoapi.rs new file mode 100644 index 0000000..450ec81 --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/src/shoapi.rs @@ -0,0 +1,33 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +pub trait ShoApi +where + Self: Sized, +{ + fn shohash(label: &[u8], input: &[u8], outlen: usize) -> Vec { + let mut sho = Self::new(label); + sho.absorb_and_ratchet(input); + sho.squeeze_and_ratchet(outlen) + } + + fn absorb_and_ratchet(&mut self, input: &[u8]) { + self.absorb(input); + self.ratchet(); + } + + fn new(label: &[u8]) -> Self; + + fn absorb(&mut self, input: &[u8]); + + fn ratchet(&mut self); + + // unimplemented; make this more generic later + // pub fn squeeze(&mut self, _outlen: usize) -> Vec; + + fn squeeze_and_ratchet(&mut self, outlen: usize) -> Vec; +} diff --git a/net/gurk-rs/files/vendor/poksho/src/shohmacsha256.rs b/net/gurk-rs/files/vendor/poksho/src/shohmacsha256.rs new file mode 100644 index 0000000..3fe57fe --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/src/shohmacsha256.rs @@ -0,0 +1,162 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +use hmac::{Hmac, Mac}; +use sha2::Sha256; +use std::cmp; + +use crate::shoapi::ShoApi; + +pub const BLOCK_LEN: usize = 64; +pub const HASH_LEN: usize = 32; + +#[derive(Clone)] +enum Mode { + ABSORBING, + RATCHETED, +} + +#[derive(Clone)] +pub struct ShoHmacSha256 { + hasher: Hmac, + cv: [u8; HASH_LEN], + mode: Mode, +} + +impl ShoApi for ShoHmacSha256 { + fn new(label: &[u8]) -> ShoHmacSha256 { + let mut sho = ShoHmacSha256 { + hasher: Hmac::::new_varkey(&[0; HASH_LEN]).unwrap(), + cv: [0; HASH_LEN], + mode: Mode::RATCHETED, + }; + sho.absorb_and_ratchet(label); + sho + } + + fn absorb(&mut self, input: &[u8]) { + if let Mode::RATCHETED = self.mode { + self.hasher = Hmac::::new_varkey(&self.cv).unwrap(); + self.mode = Mode::ABSORBING; + } + self.hasher.input(input); + } + + // called after absorb() only; streaming squeeze not yet supported + fn ratchet(&mut self) { + if let Mode::RATCHETED = self.mode { + panic!(); + } + self.hasher.input(&[0x00]); + self.cv + .copy_from_slice(&self.hasher.clone().result().code()[..]); + self.hasher.reset(); + self.mode = Mode::RATCHETED; + } + + fn squeeze_and_ratchet(&mut self, outlen: usize) -> Vec { + if let Mode::ABSORBING = self.mode { + panic!(); + } + let mut output = Vec::::new(); + let output_hasher_prefix = Hmac::::new_varkey(&self.cv).unwrap(); + let mut i = 0; + while i * HASH_LEN < outlen { + let mut output_hasher = output_hasher_prefix.clone(); + output_hasher.input(&(i as u64).to_be_bytes()); + output_hasher.input(&[0x01]); + let digest = output_hasher.result().code(); + let num_bytes = cmp::min(HASH_LEN, outlen - i * HASH_LEN); + output.extend_from_slice(&digest[0..num_bytes]); + i += 1 + } + + let mut next_hasher = output_hasher_prefix.clone(); + next_hasher.input(&(outlen as u64).to_be_bytes()); + next_hasher.input(&[0x02]); + self.cv.copy_from_slice(&next_hasher.result().code()[..]); + self.mode = Mode::RATCHETED; + output + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_vectors() { + let mut sho = ShoHmacSha256::new(b"asd"); + sho.absorb_and_ratchet(b"asdasd"); + let out = sho.squeeze_and_ratchet(64); + /* + for b in out.iter() { + print!("0x{:02x}, ", b); + } + println!(""); + */ + assert!( + out == vec![ + 0x39, 0x2c, 0xb9, 0x44, 0x93, 0x73, 0x03, 0x7f, 0xa0, 0xc1, 0x1a, 0xeb, 0xed, 0x69, + 0xcc, 0xa3, 0xb7, 0xd3, 0xbc, 0x97, 0x90, 0x87, 0x8f, 0x34, 0x17, 0x29, 0xc6, 0x5d, + 0x55, 0x06, 0x44, 0x2f, 0x04, 0x98, 0x6c, 0xb5, 0xc9, 0x09, 0x8f, 0x27, 0x7c, 0x3e, + 0xa6, 0x40, 0xa4, 0xdc, 0x6e, 0x90, 0x37, 0x2b, 0x43, 0x3a, 0x90, 0xaf, 0x9a, 0xea, + 0x70, 0x72, 0xea, 0xba, 0x33, 0x98, 0xc4, 0xfe, + ] + ); + + let mut sho = ShoHmacSha256::new(b"asd"); + sho.absorb_and_ratchet(b"asdasd"); + let out = sho.squeeze_and_ratchet(65); + /* + for b in out.iter() { + print!("0x{:02x}, ", b); + } + println!(""); + */ + assert!( + out == vec![ + 0x39, 0x2c, 0xb9, 0x44, 0x93, 0x73, 0x03, 0x7f, 0xa0, 0xc1, 0x1a, 0xeb, 0xed, 0x69, + 0xcc, 0xa3, 0xb7, 0xd3, 0xbc, 0x97, 0x90, 0x87, 0x8f, 0x34, 0x17, 0x29, 0xc6, 0x5d, + 0x55, 0x06, 0x44, 0x2f, 0x04, 0x98, 0x6c, 0xb5, 0xc9, 0x09, 0x8f, 0x27, 0x7c, 0x3e, + 0xa6, 0x40, 0xa4, 0xdc, 0x6e, 0x90, 0x37, 0x2b, 0x43, 0x3a, 0x90, 0xaf, 0x9a, 0xea, + 0x70, 0x72, 0xea, 0xba, 0x33, 0x98, 0xc4, 0xfe, 0x7a, + ] + ); + + let mut sho = ShoHmacSha256::new(b""); + sho.absorb_and_ratchet(b"abc"); + sho.absorb_and_ratchet(&[0u8; 63]); + sho.absorb_and_ratchet(&[0u8; 64]); + sho.absorb_and_ratchet(&[0u8; 65]); + sho.absorb_and_ratchet(&[0u8; 127]); + sho.absorb_and_ratchet(&[0u8; 128]); + sho.absorb_and_ratchet(&[0u8; 129]); + sho.squeeze_and_ratchet(63); + sho.squeeze_and_ratchet(64); + sho.squeeze_and_ratchet(65); + sho.squeeze_and_ratchet(127); + sho.squeeze_and_ratchet(128); + sho.squeeze_and_ratchet(129); + sho.absorb_and_ratchet(b"def"); + let out = sho.squeeze_and_ratchet(63); + for b in out.iter() { + print!("0x{:02x}, ", b); + } + println!(""); + assert!( + out == vec![ + 0xc5, 0xc1, 0x3b, 0xcc, 0x65, 0x96, 0xc2, 0x5f, 0xc4, 0x51, 0x4e, 0xac, 0x92, 0x69, + 0xdd, 0x6e, 0x3e, 0x57, 0xef, 0x70, 0xf4, 0xbf, 0xb8, 0xd6, 0x7f, 0xd3, 0x08, 0x2e, + 0xd9, 0x73, 0x2d, 0x77, 0x90, 0xd8, 0xd2, 0x68, 0x6f, 0x19, 0xeb, 0x25, 0x33, 0xa6, + 0x5c, 0x94, 0xbb, 0x8c, 0xed, 0xa0, 0xa0, 0x68, 0xe1, 0xb6, 0x15, 0xc8, 0x1b, 0xb2, + 0x6e, 0x41, 0x18, 0x89, 0xda, 0x9f, 0xb7, + ] + ); + } +} diff --git a/net/gurk-rs/files/vendor/poksho/src/shosha256.rs b/net/gurk-rs/files/vendor/poksho/src/shosha256.rs new file mode 100644 index 0000000..0a6cf17 --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/src/shosha256.rs @@ -0,0 +1,168 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +// implements the "innerpad" SHO/SHA256 proposal + +use sha2::{Digest, Sha256}; +use std::cmp; + +use crate::shoapi::ShoApi; + +pub const BLOCK_LEN: usize = 64; +pub const HASH_LEN: usize = 32; + +#[derive(Clone)] +enum Mode { + ABSORBING, + RATCHETED, +} + +#[derive(Clone)] +pub struct ShoSha256 { + hasher: Sha256, + cv: [u8; HASH_LEN], + mode: Mode, +} + +impl ShoApi for ShoSha256 { + fn new(label: &[u8]) -> ShoSha256 { + let mut sho = ShoSha256 { + hasher: Sha256::new(), + cv: [0; HASH_LEN], + mode: Mode::RATCHETED, + }; + sho.absorb_and_ratchet(label); + sho + } + + fn absorb(&mut self, input: &[u8]) { + if let Mode::RATCHETED = self.mode { + self.hasher.input(&[0u8; BLOCK_LEN][..]); + self.hasher.input(&self.cv); + self.mode = Mode::ABSORBING; + } + self.hasher.input(input); + } + + // called after absorb() only; streaming squeeze not yet supported + fn ratchet(&mut self) { + if let Mode::RATCHETED = self.mode { + panic!(); + } + self.cv + .copy_from_slice(&Sha256::digest(&self.hasher.result_reset()[..])[..]); + self.mode = Mode::RATCHETED; + } + + fn squeeze_and_ratchet(&mut self, outlen: usize) -> Vec { + if let Mode::ABSORBING = self.mode { + panic!(); + } + let mut output = Vec::::new(); + let mut output_hasher_prefix = Sha256::new(); + output_hasher_prefix.input(&[0u8; BLOCK_LEN - 1][..]); + output_hasher_prefix.input(&[1u8]); // domain separator byte + output_hasher_prefix.input(self.cv); + let mut i = 0; + while i * HASH_LEN < outlen { + let mut output_hasher = output_hasher_prefix.clone(); + output_hasher.input((i as u64).to_be_bytes()); + let digest = output_hasher.result(); + let num_bytes = cmp::min(HASH_LEN, outlen - i * HASH_LEN); + output.extend_from_slice(&digest[0..num_bytes]); + i += 1 + } + + let mut next_hasher = Sha256::new(); + next_hasher.input(&[0u8; BLOCK_LEN - 1][..]); + next_hasher.input(&[2u8]); // domain separator byte + next_hasher.input(self.cv); + next_hasher.input((outlen as u64).to_be_bytes()); + self.cv.copy_from_slice(&next_hasher.result()[..]); + self.mode = Mode::RATCHETED; + output + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_vectors() { + let mut sho = ShoSha256::new(b"asd"); + sho.absorb_and_ratchet(b"asdasd"); + let out = sho.squeeze_and_ratchet(64); + /* + for b in out.iter() { + print!("0x{:02x}, ", b); + } + println!(""); + */ + assert!( + out == vec![ + 0xeb, 0xe4, 0xef, 0x29, 0xe1, 0x8a, 0xa5, 0x41, 0x37, 0xed, 0xd8, 0x9c, 0x23, 0xf8, + 0xbf, 0xea, 0xc2, 0x73, 0x1c, 0x9f, 0x67, 0x5d, 0xa2, 0x0e, 0x7c, 0x67, 0xd5, 0xad, + 0x68, 0xd7, 0xee, 0x2d, 0x40, 0xa4, 0x52, 0x32, 0xb5, 0x99, 0x55, 0x2d, 0x46, 0xb5, + 0x20, 0x08, 0x2f, 0xb2, 0x70, 0x59, 0x71, 0xf0, 0x7b, 0x31, 0x58, 0xb0, 0x72, 0xb6, + 0x3a, 0xb0, 0x93, 0x4a, 0x05, 0xe6, 0xaf, 0x64, + ] + ); + + let mut sho = ShoSha256::new(b"asd"); + sho.absorb_and_ratchet(b"asdasd"); + let out = sho.squeeze_and_ratchet(65); + /* + for b in out.iter() { + print!("0x{:02x}, ", b); + } + println!(""); + */ + assert!( + out == vec![ + 0xeb, 0xe4, 0xef, 0x29, 0xe1, 0x8a, 0xa5, 0x41, 0x37, 0xed, 0xd8, 0x9c, 0x23, 0xf8, + 0xbf, 0xea, 0xc2, 0x73, 0x1c, 0x9f, 0x67, 0x5d, 0xa2, 0x0e, 0x7c, 0x67, 0xd5, 0xad, + 0x68, 0xd7, 0xee, 0x2d, 0x40, 0xa4, 0x52, 0x32, 0xb5, 0x99, 0x55, 0x2d, 0x46, 0xb5, + 0x20, 0x08, 0x2f, 0xb2, 0x70, 0x59, 0x71, 0xf0, 0x7b, 0x31, 0x58, 0xb0, 0x72, 0xb6, + 0x3a, 0xb0, 0x93, 0x4a, 0x05, 0xe6, 0xaf, 0x64, 0x48, + ] + ); + + let mut sho = ShoSha256::new(b""); + sho.absorb_and_ratchet(b"abc"); + sho.absorb_and_ratchet(&[0u8; 63]); + sho.absorb_and_ratchet(&[0u8; 64]); + sho.absorb_and_ratchet(&[0u8; 65]); + sho.absorb_and_ratchet(&[0u8; 127]); + sho.absorb_and_ratchet(&[0u8; 128]); + sho.absorb_and_ratchet(&[0u8; 129]); + sho.squeeze_and_ratchet(63); + sho.squeeze_and_ratchet(64); + sho.squeeze_and_ratchet(65); + sho.squeeze_and_ratchet(127); + sho.squeeze_and_ratchet(128); + sho.squeeze_and_ratchet(129); + sho.absorb_and_ratchet(b"def"); + let out = sho.squeeze_and_ratchet(63); + /* + for b in out.iter() { + print!("0x{:02x}, ", b); + } + println!(""); + */ + assert!( + out == vec![ + 0x0d, 0xde, 0xea, 0x97, 0x3f, 0x32, 0x10, 0xf7, 0x72, 0x5a, 0x3c, 0xdb, 0x24, 0x73, + 0xf8, 0x73, 0xae, 0xab, 0x8f, 0xeb, 0x32, 0xb8, 0x0d, 0xee, 0x67, 0xf0, 0xcd, 0xe7, + 0x95, 0x4e, 0x92, 0x9a, 0x4e, 0x78, 0x7a, 0xef, 0xee, 0x6d, 0xbe, 0x91, 0xd3, 0xff, + 0xf1, 0x62, 0x1a, 0xab, 0x8d, 0x0d, 0x29, 0x19, 0x4f, 0x8a, 0xf9, 0x86, 0xd6, 0xf3, + 0x57, 0xad, 0xd0, 0x15, 0x0d, 0xf7, 0xd9, + ] + ); + } +} diff --git a/net/gurk-rs/files/vendor/poksho/src/sign.rs b/net/gurk-rs/files/vendor/poksho/src/sign.rs new file mode 100644 index 0000000..205f2e1 --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/src/sign.rs @@ -0,0 +1,92 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +use crate::args::*; +use crate::errors::*; +use crate::statement::*; +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; + +// Signatures are such a common ZKP that we provide special functions for them: +pub fn sign( + private_key: Scalar, + public_key: RistrettoPoint, + message: &[u8], + randomness: &[u8], +) -> Result, PokshoError> { + let mut st = Statement::new(); + st.add("public_key", &[("private_key", "G")]); + + let mut scalar_args = ScalarArgs::new(); + scalar_args.add("private_key", private_key); + + let mut point_args = PointArgs::new(); + point_args.add("public_key", public_key); + + st.prove(&scalar_args, &point_args, &message, randomness) +} + +pub fn verify_signature( + signature: &[u8], + public_key: RistrettoPoint, + message: &[u8], +) -> Result<(), PokshoError> { + let mut st = Statement::new(); + st.add("public_key", &[("private_key", "G")]); + + let mut point_args = PointArgs::new(); + point_args.add("public_key", public_key); + + st.verify_proof(signature, &point_args, &message) +} + +#[cfg(test)] +mod tests { + #![allow(non_snake_case)] + + use super::*; + use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; + + #[test] + fn test_signature() { + let mut block64 = [0u8; 64]; + let mut block32 = [0u8; 32]; + let mut block100 = [0u8; 100]; + for i in 0..32 { + block32[i] = i as u8; + } + for i in 0..64 { + block64[i] = i as u8; + } + for i in 0..100 { + block100[i] = i as u8; + } + + let a = Scalar::from_bytes_mod_order_wide(&block64); + let A = a * RISTRETTO_BASEPOINT_POINT; + let randomness = block32; + let message = block100; + let signature = sign(a, A, &message, &randomness).unwrap(); + verify_signature(&signature, A, &message).unwrap(); + /* + for b in signature.iter() { + print!("0x{:02x}, ", b); + } + println!(""); + */ + assert!( + signature + == vec![ + 0xa0, 0x8f, 0x6b, 0x34, 0xa2, 0x82, 0xdd, 0x4c, 0x7c, 0xfc, 0x40, 0xb9, 0x18, + 0xf2, 0x24, 0xa6, 0xb6, 0x31, 0xca, 0x5f, 0x64, 0x80, 0xa1, 0x0b, 0x42, 0xbd, + 0x14, 0x08, 0x60, 0x2a, 0x7e, 0x00, 0x8a, 0x23, 0xa1, 0xe3, 0x24, 0x79, 0xbe, + 0xfb, 0x5e, 0x26, 0xb9, 0xf0, 0xf4, 0xfe, 0x0e, 0x9e, 0x9e, 0x9e, 0xc9, 0xaf, + 0xad, 0x26, 0x91, 0x43, 0xac, 0xb0, 0x3a, 0x22, 0xc6, 0x36, 0x4f, 0x03, + ] + ); + } +} diff --git a/net/gurk-rs/files/vendor/poksho/src/simple_types.rs b/net/gurk-rs/files/vendor/poksho/src/simple_types.rs new file mode 100644 index 0000000..b13b4d1 --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/src/simple_types.rs @@ -0,0 +1,12 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; + +pub type G1 = Vec; // Schnorr proves preimage of homomorphism from G1 -> G2 +pub type G2 = Vec; diff --git a/net/gurk-rs/files/vendor/poksho/src/statement.rs b/net/gurk-rs/files/vendor/poksho/src/statement.rs new file mode 100644 index 0000000..3b3b323 --- /dev/null +++ b/net/gurk-rs/files/vendor/poksho/src/statement.rs @@ -0,0 +1,600 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +use crate::args::*; +use crate::errors::*; +use crate::proof::*; +use crate::scalar::*; +use crate::shoapi::ShoApi; +use crate::shohmacsha256::ShoHmacSha256; +use crate::simple_types::*; +use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::traits::MultiscalarMul; +use std::collections::HashMap; + +// POKSHO implements the "Sigma protocol for arbitrary linear relations" described in section +// 19.5.3 of https://crypto.stanford.edu/~dabo/cryptobook/BonehShoup_0_4.pdf +// +// We adopt the view that we are proving knowledge of the preimage of a group homomorphism +// from groups G1 -> G2, where elements in G1 are vectors of scalars and elements in G2 are vectors of +// Ristretto "points". The homomomorphism can be viewed as a system of equations of the form: +// +// P = sP + sP + sP + ... +// P = sP + sP + sP + ... +// P = sP + sP + sP + ... +// ... +// +// Where s are any scalars and P are any points. The left-hand side of these equations describes +// the element in G2 which is the image of the homomorphism, and the scalars form an element in G1 +// which we are proving knowledge of (this preimage in G1 can be viewed as a vector if the system +// of equations is rewritten as matrix multiplication). +// +// We use the term "statement" for the above system of equations written with both points and +// scalars as variables. For example, the statement for signatures is the single equation: +// +// A = a*G +// +// where "A" is the public key, "a" is the private key, and "G" is the base point. The +// discrete-log equality statement used in VRFs could be written as: +// +// A = a*G +// B = a*H +// +// We use the term "witness" for a vector of scalars that satisfies a given statement and a given +// set of point assignments (equivalently: a witness is an element in G1 that is a preimage of the +// left-hand-side under the group homomorphism). In the above cases, "a" is the witness. +// +// The zero-knowledge proof is a standard Fiat-Shamir Sigma/Schnorr proof of knowledge. To +// immplement Fiat-Shamir hashing we use the SHO/HMAC-SHA256 construct, which provides a stateful object +// which we can use to Absorb data, and then Squeeze out arbitrary-length ouput. We use a SHO +// object not only to produce the Schnorr challenge, but also to produce the Schnorr nonce by +// hashing some caller-supplied random data, the witness, and the message. This "synthetic nonce" +// strategy is intended to ensure that the nonce appears random to any attacker and that different +// Schnorr challenges will never be used with the same nonce. +// +// Below we describe the hash inputs to SHO/HMAC-SHA256: +// +// L : bytes, label = "POKSHO_Ristretto_SHOHMACSHA256" +// D : bytes, description of statement - see below +// a : G1, witness scalars for statement +// A : G2, point values for statement = homomorphism(a) +// Z : bytes, random = 32 byes of randomness +// M : bytes, message to be signed, if any +// r : G1, Schnorr nonce +// R : G2, Schnorr commitment = homomorphism(r) +// h : integer, Schnorr challenge + +// sho = SHO(L) +// sho.AbsorbAndRatchet(D || A) +// sho2 = sho.Clone() +// sho2.AbsorbAndRatchet(Z || a) +// sho2.AbsorbAndRatchet(M) +// r = sho2.Squeeze(64 * num_scalars) +// sho.AbsorbAndRatchet(R || M) +// h = Squeeze(64) +// +// Description format (D) +// --- +// Ne : number of equations (1-255) +// for i=1..Ne: +// point_index : 0..255 (0 = base point) +// Nt : number of terms (1-255) +// for j=1..Nt: +// scalar_index: 0-255 +// point_index: 0-255 (0 = base point) +// +// Point values for statement (A) and commitment (R) +// --- +// for index=1..total number of points (excluding base point at index 0): +// RistrettoPoint +// +// Witness (a) +// --- +// for index=0..total number of scalars: +// RistrettoScalar + +use PokshoError::*; + +type ScalarIndex = u8; +type PointIndex = u8; + +struct Term { + scalar: ScalarIndex, + point: PointIndex, +} + +struct Equation { + lhs: PointIndex, + rhs: Vec, +} + +pub struct Statement { + // We store the Schnorr ZKP equations using scalar and point indices + // which are numbered from zero, and are assigned sequentially based + // on the order in which the point or scalar appears in the equations + // (except point index 0 is pre-assigned to "G", the Ristretto base point) + // + // We also store maps from string names -> indices, and vectors for + // the reverse map. The former map is used when adding new equations, + // and the latter is used when instantiating these indices with + // concrete values. + equations: Vec, + scalar_map: HashMap, + scalar_vec: Vec, + point_map: HashMap, + point_vec: Vec, +} + +impl Statement { + pub fn new() -> Self { + let mut point_map = HashMap::new(); + point_map.insert("G".to_string(), 0); // G is base point + let point_vec = vec!["G".to_string()]; + Statement { + equations: Vec::new(), + scalar_map: HashMap::new(), + scalar_vec: Vec::new(), + point_map, + point_vec, + } + } + + // panics on invalid input + pub fn add(&mut self, lhs_str: &str, rhs_pairs: &[(&str, &str)]) { + if (lhs_str.len() == 0) + || (rhs_pairs.len() == 0) + || (rhs_pairs.len() > 255) + || (self.equations.len() >= 255) + { + assert!(false); + } + let lhs = self.add_point(lhs_str.to_string()).unwrap(); + let mut rhs = Vec::::with_capacity(rhs_pairs.len()); + for pair in rhs_pairs { + if pair.0.len() == 0 || pair.1.len() == 0 { + assert!(false); + } + let scalar = self.add_scalar(pair.0.to_string()).unwrap(); + let point = self.add_point(pair.1.to_string()).unwrap(); + rhs.push(Term { scalar, point }); + } + self.equations.push(Equation { lhs, rhs }); + } + + pub fn prove( + &self, + scalar_args: &ScalarArgs, + point_args: &PointArgs, + message: &[u8], + randomness: &[u8], // must be 32 bytes + ) -> Result, PokshoError> { + if randomness.len() != 32 { + return Err(PokshoError::BadArgs); + } + let g1 = self.sort_scalars(scalar_args)?; + let all_points = self.sort_points(point_args)?; + + // Absorb the protocol label L, description of statement D, and point values A + let mut sho = ShoHmacSha256::new(b"POKSHO_Ristretto_SHOHMACSHA256"); // L + sho.absorb(&self.to_bytes()); // D + for point in &all_points { + // A + sho.absorb(&point.compress().to_bytes()); + } + + sho.ratchet(); // Ratchet + + // Random nonce + // "Synthetic" nonce based on hashing randomness, witness (private scalars) and message + let mut sho2 = sho.clone(); + sho2.absorb(randomness); // Z + for scalar in &g1 { + sho2.absorb(&scalar.to_bytes()); // a + } + sho2.ratchet(); // Ratchet + sho2.absorb_and_ratchet(message); // M + let blinding_scalar_bytes = sho2.squeeze_and_ratchet(g1.len() * 64); + + let mut nonce = self.g1_new(); + for i in 0..g1.len() { + nonce.push(scalar_from_slice_wide( + &blinding_scalar_bytes[i * 64..(i + 1) * 64], + )) + } + + // Commitment from nonce by applying homomorphism F: commitment = F(nonce) + let commitment = self.homomorphism_with_subtraction(&nonce, &all_points, None); + + // Challenge from commitment and message + for point in &commitment { + sho.absorb(&point.compress().to_bytes()); + } + sho.absorb_and_ratchet(message); + let challenge = scalar_from_slice_wide(&sho.squeeze_and_ratchet(64)); + + // Response + let mut response = self.g1_new(); + for i in 0..g1.len() { + response.push(nonce[i] + (g1[i] * challenge)); + } + + let proof = Proof { + challenge, + response, + }; + + // Verify before returning, since a bad proof could indicate + // a glitched/faulty response that leaks private keys, or incorrect inputs + let proof_bytes = proof.to_bytes(); + match self.verify_proof(&proof_bytes, point_args, message) { + Err(VerificationFailure) => Err(ProofCreationVerificationFailure), + Err(e) => Err(e), + Ok(_) => Ok(proof_bytes), + } + } + + pub fn verify_proof( + &self, + proof_bytes: &[u8], + point_args: &PointArgs, + message: &[u8], + ) -> Result<(), PokshoError> { + let proof = Proof::from_slice(proof_bytes).ok_or(VerificationFailure)?; + if proof.response.len() != self.scalar_vec.len() { + return Err(VerificationFailure); + } + let all_points = self.sort_points(point_args)?; + + // Absorb the protocol label L, statement description D, and point values A + let mut sho = ShoHmacSha256::new(b"POKSHO_Ristretto_SHOHMACSHA256"); // L + sho.absorb(&self.to_bytes()); // D + for point in &all_points { + // A + sho.absorb(&point.compress().to_bytes()); + } + sho.ratchet(); + + // Reconstruct commitment + // + // commitment R = F(s) - h*A + // + // F: homomorphism + // s: response element in G1 + // h: challenge scalar + // A: element in G2 whose preimage we are proving knowledge of (i.e. LHS of Schnorr eqns) + let commitment = + self.homomorphism_with_subtraction(&proof.response, &all_points, Some(proof.challenge)); + + // Reconstruct challenge from commitment and message + for point in &commitment { + // R + sho.absorb(&point.compress().to_bytes()); + } + sho.absorb_and_ratchet(message); // M + let challenge = scalar_from_slice_wide(&sho.squeeze_and_ratchet(64)); + + // Check challenge (const time) + if challenge == proof.challenge { + Ok(()) + } else { + Err(VerificationFailure) + } + } + + fn add_scalar(&mut self, scalar_name: String) -> Result { + match self.scalar_map.get(&scalar_name) { + Some(index) => Ok(*index), + None => { + assert!(self.scalar_map.len() == self.scalar_vec.len()); + let new_index = self.scalar_map.len(); + if new_index > 255 { + return Err(BadArgs); + } + let new_index = new_index as u8; + self.scalar_map.insert(scalar_name.clone(), new_index); + self.scalar_vec.push(scalar_name.clone()); + Ok(new_index) + } + } + } + + fn add_point(&mut self, point_name: String) -> Result { + match self.point_map.get(&point_name) { + Some(index) => Ok(*index), + None => { + assert!(self.point_map.len() == self.point_vec.len()); + let new_index = self.point_map.len(); + if new_index > 255 { + return Err(BadArgs); + } + let new_index = new_index as u8; + self.point_map.insert(point_name.clone(), new_index); + self.point_vec.push(point_name.clone()); + Ok(new_index) + } + } + } + + fn to_bytes(&self) -> Vec { + assert!( + self.equations.len() <= 255 + && self.scalar_map.len() <= 256 + && self.point_map.len() <= 256 + ); + let mut v = Vec::::new(); + v.push(self.equations.len() as u8); + for Equation { lhs, rhs } in &self.equations { + assert!(*lhs as usize <= self.point_map.len()); + assert!(rhs.len() <= 255); + v.push(*lhs); + v.push(rhs.len() as u8); + for Term { scalar, point } in rhs { + assert!((*scalar as usize) < self.scalar_map.len()); + assert!((*point as usize) < self.point_map.len()); + v.push(*scalar); + v.push(*point); + } + } + v + } + + fn g1_new(&self) -> G1 { + G1::with_capacity(self.scalar_vec.len()) + } + + fn g2_new(&self) -> G2 { + G2::with_capacity(self.equations.len()) + } + + // Applies the homomorphism from G1 -> G2 + // If given a challenge h, also subtracts h*A for efficient recovery of + // the Schnorr commitment + fn homomorphism_with_subtraction( + &self, + g1: &G1, + all_points: &Vec, + challenge: Option, + ) -> G2 { + let mut g2 = self.g2_new(); + for e in &self.equations { + let scalar_iter = e + .rhs + .iter() + .map(|Term { scalar, point: _ }| g1[*scalar as usize]); + let point_iter = e + .rhs + .iter() + .map(|Term { scalar: _, point }| all_points[*point as usize]); + + // Can this be done without a vector? + let mut v_scalar = Vec::::with_capacity(1); + let mut v_point = Vec::::with_capacity(1); + if let Some(h) = challenge { + v_scalar.push(-h); + v_point.push(all_points[e.lhs as usize]); + }; + + let scalar_iter = scalar_iter.chain(v_scalar); + let point_iter = point_iter.chain(v_point); + + // Could use vartime_multiscalar_mul in some cases, but in the + // general case points might be secret (not just scalars!) + g2.push(RistrettoPoint::multiscalar_mul(scalar_iter, point_iter)); + } + g2 + } + + fn sort_scalars(&self, scalar_args: &ScalarArgs) -> Result { + if scalar_args.0.len() != self.scalar_vec.len() { + return Err(BadArgsWrongNumberOfScalarArgs); + } + let mut g1 = self.g1_new(); + for scalar_name in &self.scalar_vec { + g1.push( + *scalar_args + .0 + .get(scalar_name) + .ok_or(BadArgsMissingScalarArg)?, + ); + } + Ok(g1) + } + + fn sort_points(&self, point_args: &PointArgs) -> Result, PokshoError> { + if point_args.0.len() != self.point_vec.len() - 1 { + return Err(BadArgsWrongNumberOfPointArgs); + } + let mut all_points = Vec::::new(); + all_points.push(RISTRETTO_BASEPOINT_POINT); + for point_name in &self.point_vec[1..] { + all_points.push(*point_args.0.get(point_name).ok_or(BadArgsMissingPointArg)?); + } + Ok(all_points) + } +} + +#[cfg(test)] +mod tests { + #![allow(non_snake_case)] + + use super::*; + + #[test] + fn test_statement_encoding() { + let mut s = Statement::new(); + s.add("A", &[("a", "G")]); + assert!(s.to_bytes() == vec![1, 1, 1, 0, 0]); + + let mut s = Statement::new(); + s.add("A", &[("a", "G")]); + s.add("B", &[("a", "H")]); + assert!(s.to_bytes() == vec![2, 1, 1, 0, 0, 2, 1, 0, 3]); + + let mut s = Statement::new(); + s.add("A", &[("a", "G"), ("b", "H")]); + assert!(s.to_bytes() == vec![1, 1, 2, 0, 0, 1, 2]); + } + + #[test] + fn test_complex_statement() { + let mut block32 = [0u8; 32]; + let mut block64a = [0u8; 64]; + let mut block64b = [0u8; 64]; + let mut block64c = [0u8; 64]; + let mut block64d = [0u8; 64]; + let mut block64h = [0u8; 64]; + let mut block64i = [0u8; 64]; + let block0 = [0u8; 0]; + for i in 0..32 { + block32[i] = i as u8; + } + for i in 0..64 { + block64a[i] = 10 + i as u8; + } + for i in 0..64 { + block64b[i] = 20 + i as u8; + } + for i in 0..64 { + block64c[i] = 30 + i as u8; + } + for i in 0..64 { + block64d[i] = 40 + i as u8; + } + for i in 0..64 { + block64h[i] = 50 + i as u8; + } + for i in 0..64 { + block64i[i] = 60 + i as u8; + } + + let randomness = block32; + let message = block0; + + let scalar_bytes_a = block64a; + let scalar_bytes_b = block64b; + let scalar_bytes_c = block64c; + let scalar_bytes_d = block64d; + + let scalar_bytes_h_point = block64h; + let scalar_bytes_i_point = block64i; + + let a = Scalar::from_bytes_mod_order_wide(&scalar_bytes_a); + let b = Scalar::from_bytes_mod_order_wide(&scalar_bytes_b); + let c = Scalar::from_bytes_mod_order_wide(&scalar_bytes_c); + let d = Scalar::from_bytes_mod_order_wide(&scalar_bytes_d); + let H = + Scalar::from_bytes_mod_order_wide(&scalar_bytes_h_point) * RISTRETTO_BASEPOINT_POINT; + let I = + Scalar::from_bytes_mod_order_wide(&scalar_bytes_i_point) * RISTRETTO_BASEPOINT_POINT; + + let A = a * RISTRETTO_BASEPOINT_POINT + b * H + c * I; + let B = c * H + d * I; + + let mut st = Statement::new(); + st.add("A", &[("a", "G"), ("b", "H"), ("c", "I")]); + st.add("B", &[("c", "H"), ("d", "I")]); + assert!(st.to_bytes() == vec![2, 1, 3, 0, 0, 1, 2, 2, 3, 4, 2, 2, 2, 3, 3]); + + let mut scalar_args = ScalarArgs::new(); + scalar_args.add("a", a); + scalar_args.add("b", b); + scalar_args.add("c", c); + scalar_args.add("d", d); + let mut point_args = PointArgs::new(); + point_args.add("A", A); + point_args.add("B", B); + point_args.add("H", H); + point_args.add("I", I); + + let mut scalar_args2 = scalar_args.clone(); + scalar_args2.add("abc", a); + + // Test bad args - extra scalar + match st.prove(&scalar_args2, &point_args, &message, &randomness) { + Err(PokshoError::BadArgsWrongNumberOfScalarArgs) => (), + _ => assert!(false), + } + + // Good proof + let mut proof = st + .prove(&scalar_args, &point_args, &message, &randomness) + .unwrap(); + st.verify_proof(&proof, &point_args, &message).unwrap(); + /* + for b in proof.iter() { + print!("0x{:02x}, ", b); + } + println!(""); + */ + assert!( + proof + == vec![ + 0x8e, 0xfc, 0x67, 0x6c, 0x33, 0xe6, 0xb2, 0xd0, 0x67, 0x0e, 0xd5, 0x46, 0x1a, + 0x50, 0x7f, 0x6a, 0x4b, 0xc9, 0x15, 0x3e, 0x26, 0x1d, 0xb8, 0x0f, 0xa4, 0x38, + 0xf3, 0xcd, 0x80, 0xa5, 0xc9, 0x09, 0xb1, 0x13, 0xcc, 0x0d, 0x79, 0x90, 0xad, + 0x61, 0x6d, 0x0a, 0x2f, 0xc4, 0xb8, 0x31, 0xd0, 0x63, 0x57, 0xa5, 0xee, 0x5d, + 0x36, 0xd4, 0x4b, 0x34, 0x27, 0xc7, 0x90, 0x10, 0x61, 0x18, 0x0c, 0x0f, 0xb1, + 0x79, 0x8c, 0x51, 0x68, 0x0f, 0xe2, 0x1b, 0x9f, 0x98, 0xe9, 0x79, 0x55, 0xb1, + 0x59, 0x7c, 0x49, 0x31, 0x47, 0x25, 0xc1, 0x54, 0x6a, 0x36, 0x93, 0x28, 0xcf, + 0x54, 0xda, 0xae, 0x71, 0x0b, 0xfc, 0x4a, 0x99, 0x11, 0x42, 0x2a, 0xa7, 0x7e, + 0xd6, 0xd7, 0x23, 0x1d, 0xe3, 0x00, 0x3b, 0xa5, 0xae, 0x9d, 0x9f, 0xd0, 0xc5, + 0x3c, 0xed, 0x7a, 0xd7, 0x82, 0xe2, 0x9b, 0x04, 0x68, 0x4a, 0x07, 0x22, 0x1a, + 0x6e, 0xf4, 0x7c, 0xe6, 0x1d, 0x81, 0x7f, 0x01, 0x11, 0x7c, 0xf5, 0x9d, 0xf6, + 0x9a, 0xc3, 0x5b, 0x5b, 0xb5, 0x90, 0xf1, 0xf7, 0xb6, 0xd0, 0x29, 0x71, 0x7b, + 0xc1, 0xa6, 0x25, 0x01, + ] + ); + + // Test bad args - extra point + let mut point_args2 = point_args.clone(); + point_args2.add("xyz", A); + match st.verify_proof(&proof, &point_args2, &message) { + Err(PokshoError::BadArgsWrongNumberOfPointArgs) => (), + _ => assert!(false), + } + + // Test bad message + match st.verify_proof(&proof, &point_args, &block32) { + Err(VerificationFailure) => (), + _ => assert!(false), + } + + // Test bad proof #1 - extra byte at end + let mut proof2 = proof.clone(); + proof2.push(0); + match st.verify_proof(&proof2, &point_args, &message) { + Err(VerificationFailure) => (), + _ => assert!(false), + } + + // Test bad proof #2 - last byte changed + let prooflen = proof.len(); + proof[prooflen - 1] += 1; + match st.verify_proof(&proof, &point_args, &message) { + Err(VerificationFailure) => (), + _ => assert!(false), + } + + // Test bad proof #3 - incorrect # of scalars (1 too few) + let mut proof2 = proof.clone(); + proof2.truncate(proof2.len() - 32); + match st.verify_proof(&proof2, &point_args, &message) { + Err(VerificationFailure) => (), + _ => assert!(false), + } + + // Test bad proof #3 - incorrect # of scalars (1 too few) + let mut proof2 = proof.clone(); + proof2.truncate(proof2.len() - 32); + match st.verify_proof(&proof2, &point_args, &message) { + Err(VerificationFailure) => (), + _ => assert!(false), + } + } +} diff --git a/net/gurk-rs/files/vendor/presage/.cargo-checksum.json b/net/gurk-rs/files/vendor/presage/.cargo-checksum.json new file mode 100644 index 0000000..17ce180 --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".github/workflows/ci.yaml":"c9c008a019fa138d791320a9bae47d08ffeb0647db710e86999f871e9bd2a053","Cargo.toml":"062ada4b20149d504ef21dccac55d817e0b9406c5326713d6037db365a6866c0","LICENSE.md":"0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0","README.md":"be9c578a483c733f418c04b061b56aec208a2adfc859f51f5ade752062cd4641","examples/cli.rs":"674e851b0c0ad9096feb88da209b6ea03fbd7db40c5b3faa4e798ab215f280d2","examples/link.rs":"7b56671e805bb1b1692c67c946d9faa6540b29e6f16c738442b8b03f4dbabf14","examples/register.rs":"f5bbba00fafbc8e3937781edd8d958fc0a54c41ffc02d2cfe40cf27409ec225f","rustfmt.toml":"e929ddb6e0351a2402ba754bbb7ef97cfa17a4ecd2d5fc06b5053ac376d44870","src/cache.rs":"e7db7bfab8935ce2bb993e2ef76f3ffbfd928c7956172da9305c4d9db8fb5791","src/config/mod.rs":"7823161971c85c1df783206c6adda7518981785ed20f54628dae61f949ec5b1f","src/config/sled.rs":"344607dc47043c2df85174721049111af3568102a7639adcad5e5b971a49adac","src/errors.rs":"501e810e41eefdf7498cb5a89a8b4822bc1aeb666a3db276e81ff3c38cdae775","src/lib.rs":"b56c700bde13d59dbf545f0083e3fd693aa1b6fd378acecaef011895bf3fd13f","src/manager.rs":"648ba61dd744d1542bc5cc3059b24455472ffd9613af34b15ec70d4969d9c4c5"},"package":null} \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/presage/.github/workflows/ci.yaml b/net/gurk-rs/files/vendor/presage/.github/workflows/ci.yaml new file mode 100644 index 0000000..b95c06a --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/.github/workflows/ci.yaml @@ -0,0 +1,54 @@ +on: [push, pull_request] + +name: CI + +env: + CARGO_INCREMENTAL: 0 + +jobs: + build_and_test: + name: build + runs-on: ubuntu-latest + env: + RUSTFLAGS: -D warnings + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - uses: actions-rs/cargo@v1 + with: + command: build + args: --all-targets + - uses: actions-rs/cargo@v1 + with: + command: test + + rustfmt: + name: rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + components: rustfmt + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: -- --check + + clippy: + name: clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + components: clippy + - uses: actions-rs/cargo@v1 + with: + command: clippy \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/presage/Cargo.toml b/net/gurk-rs/files/vendor/presage/Cargo.toml new file mode 100644 index 0000000..5274c08 --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/Cargo.toml @@ -0,0 +1,49 @@ +[package] +# be a sign or warning of (an imminent event, typically an unwelcome one). +name = "presage" +version = "0.2.0" +authors = ["Gabriel Féron "] +edition = "2018" + +[dependencies] +libsignal-service = { git = "https://github.com/boxdot/libsignal-service-rs", rev = "8be91da2" } +libsignal-service-hyper = { git = "https://github.com/boxdot/libsignal-service-rs", rev = "8be91da2" } + +async-trait = "0.1" +base64 = "0.12" +futures = "0.3" +hex = "0.4.2" +log = "0.4.8" +rand = "0.7" +serde = "1.0" +serde_json = "1.0" +thiserror = "1.0" +sled = { version = "0.34", optional = true } +qr2term = "0.2.2" + +[dev-dependencies] +# for tests +quickcheck = "1.0.3" +quickcheck_async = "0.1" + +# for examples +anyhow = "1.0" +directories = "3.0" +env_logger = "0.7" +futures = "0.3" +hex = "0.4" +log = "0.4" +rand = "0.7" +serde_json = "1.0" +structopt = "0.3" +tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } +url = "2.2.2" + +[features] +default = ["sled-store"] +quirks = [] +sled-store = ["sled"] + +#[patch."https://github.com/whisperfish/libsignal-service-rs.git"] +#libsignal-service = { path = "../libsignal-service-rs/libsignal-service" } +#libsignal-service-hyper = { path = "../libsignal-service-rs/libsignal-service-hyper" } diff --git a/net/gurk-rs/files/vendor/presage/LICENSE.md b/net/gurk-rs/files/vendor/presage/LICENSE.md new file mode 100644 index 0000000..be3f7b2 --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/LICENSE.md @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/net/gurk-rs/files/vendor/presage/README.md b/net/gurk-rs/files/vendor/presage/README.md new file mode 100644 index 0000000..e91648b --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/README.md @@ -0,0 +1,40 @@ +# Presage + +![CI](https://github.com/whisperfish/presage/workflows/CI/badge.svg) +![License](https://shields.io/github/license/whisperfish/presage.svg) + +A Rust library that helps building clients for the [Signal Messenger](https://signal.org/en/), using [libsignal-service-rs](https://github.com/whisperfish/libsignal-service-rs). It is designed to provide everything you need to get started. + +> :warning: **The API is considered unstable** - I am still experimenting here. + +Features: + +- [x] Configuration and secrets storage (using [sled](https://github.com/spacejam/sled)) + - [ ] Local encryption +- [x] Registration + - [x] SMS + - [x] Voice call +- [x] Link as secondary device from Android / iOS app (like Signal Desktop) +- [x] Synchronize contacts from primary device +- [x] Receive messages +- [x] Download + decrypt attachments +- [x] Send messages +- [x] Groups support + +## Instructions + +Included in this repository is a CLI very similar (on purpose) to the great [signal-cli](https://github.com/AsamK/signal-cli): + +``` +# print help section +cargo run --example=cli -- --help + +# link as secondary device, a PNG with a QR code to scan should open +cargo run --example=cli -- link-device --device-name presage + +# start receiving messages +cargo run --example=cli -- receive +``` + +For usage of the library, a few examples are included under the `examples/` directory, and most features are demonstrated +in [examples/cli.rs](./examples/cli.rs). diff --git a/net/gurk-rs/files/vendor/presage/examples/cli.rs b/net/gurk-rs/files/vendor/presage/examples/cli.rs new file mode 100644 index 0000000..d5ae9d1 --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/examples/cli.rs @@ -0,0 +1,349 @@ +use std::{convert::TryInto, path::PathBuf, time::UNIX_EPOCH}; + +use anyhow::{bail, Context as _}; +use directories::ProjectDirs; +use env_logger::Env; +use futures::{pin_mut, StreamExt}; +use libsignal_service::ServiceAddress; +use log::debug; +use presage::{ + prelude::{ + content::{ + Content, ContentBody, DataMessage, GroupContext, GroupContextV2, GroupType, SyncMessage, + }, + proto::sync_message::Sent, + Contact, GroupMasterKey, SignalServers, + }, + prelude::{phonenumber::PhoneNumber, Uuid}, + Manager, SledConfigStore, +}; +use structopt::StructOpt; +use url::Url; + +#[derive(StructOpt)] +#[structopt(about = "a basic signal CLI to try things out")] +struct Args { + #[structopt(long = "db-path", short = "d")] + db_path: Option, + + #[structopt(flatten)] + subcommand: Subcommand, +} + +#[derive(StructOpt)] +enum Subcommand { + #[structopt(about = "register a primary device using a phone number")] + Register { + #[structopt(long = "servers", short = "s", default_value = "staging")] + servers: SignalServers, + #[structopt(long, help = "Phone Number to register with in E.164 format")] + phone_number: PhoneNumber, + #[structopt(long)] + use_voice_call: bool, + #[structopt( + long = "captcha", + help = "Captcha obtained from https://signalcaptchas.org/registration/generate.html" + )] + captcha: Option, + #[structopt(long, help = "Force to register again if already registered")] + force: bool, + }, + #[structopt(about = "Unregister from Signal")] + Unregister, + #[structopt( + about = "generate a QR code to scan with Signal for iOS or Android to provision a secondary device on the same phone number" + )] + LinkDevice { + /// Possible values: staging, production + #[structopt(long, short = "s", default_value = "production")] + servers: SignalServers, + #[structopt( + long, + short = "n", + help = "Name of the device to register in the primary client" + )] + device_name: String, + }, + #[structopt(about = "verify the code you got from the SMS or voice-call when you registered")] + Verify { + #[structopt(long, short = "c", help = "SMS / Voice-call confirmation code")] + confirmation_code: u32, + }, + #[structopt(about = "Get information on the registered user")] + Whoami, + #[structopt(about = "Retrieve the user profile")] + RetrieveProfile, + #[structopt(about = "Sets a name, status and avatar")] + UpdateProfile, + #[structopt(about = "Check if a user is registered on Signal")] + GetUserStatus, + #[structopt(about = "Update the account attributes")] + UpdateAccount, + #[structopt(about = "Block the provided contacts or groups")] + Block, + #[structopt(about = "Unblock the provided contacts or groups")] + Unblock, + #[structopt(about = "Update the details of a contact")] + UpdateContact, + #[structopt(about = "Receives all pending messages and saves them to disk")] + Receive, + #[structopt(about = "List group memberships")] + ListGroups, + #[structopt(about = "list contacts")] + ListContacts, + #[structopt(about = "find a contact in the embedded DB")] + FindContact { + #[structopt(long, short = "u", help = "contact UUID")] + uuid: Option, + #[structopt(long, short = "name", help = "contact name")] + name: Option, + }, + #[structopt(about = "sends a message")] + Send { + #[structopt(long, short = "u", help = "uuid of the recipient")] + uuid: Uuid, + #[structopt(long, short = "m", help = "Contents of the message to send")] + message: String, + }, + #[structopt(about = "sends a message to group")] + SendToGroup { + #[structopt( + long = "phone-number", + short = "n", + min_values = 1, + required = true, + help = "Phone number of the recipient" + )] + recipients: Vec, + #[structopt(long, short = "m", help = "Contents of the message to send")] + message: String, + #[structopt(long, short = "g", help = "ID of the legacy group (hex string)")] + group_id: Option, + #[structopt(long, short = "k", help = "Master Key of the V2 group (hex string)")] + master_key: Option, + }, + #[cfg(feature = "quirks")] + RequestSyncContacts, + #[cfg(feature = "quirks")] + DumpConfig, +} + +#[tokio::main(flavor = "current_thread")] +async fn main() -> anyhow::Result<()> { + env_logger::from_env( + Env::default().default_filter_or(format!("{}=info", env!("CARGO_PKG_NAME"))), + ) + .init(); + + let args = Args::from_args(); + + let db_path = args.db_path.unwrap_or_else(|| { + ProjectDirs::from("org", "whisperfish", "presage") + .unwrap() + .config_dir() + .into() + }); + debug!("opening config database from {}", db_path.display()); + let config_store = SledConfigStore::new(db_path)?; + + let csprng = rand::thread_rng(); + let mut manager = Manager::new(config_store, csprng)?; + + match args.subcommand { + Subcommand::Register { + servers, + phone_number, + use_voice_call, + captcha, + force, + } => { + manager + .register( + servers, + phone_number, + use_voice_call, + captcha.as_ref().map(|u| u.host_str().unwrap()), + force, + ) + .await?; + } + Subcommand::LinkDevice { + servers, + device_name, + } => { + manager + .link_secondary_device(servers, device_name.clone()) + .await?; + } + Subcommand::Verify { confirmation_code } => { + manager.confirm_verification_code(confirmation_code).await?; + } + Subcommand::Receive => { + let messages = manager + .clone() + .receive_messages() + .await + .context("failed to initialize messages stream")?; + pin_mut!(messages); + while let Some(Content { metadata, body }) = messages.next().await { + match body { + ContentBody::DataMessage(message) + | ContentBody::SynchronizeMessage(SyncMessage { + sent: + Some(Sent { + message: Some(message), + .. + }), + .. + }) => { + if let Some(quote) = &message.quote { + println!( + "Quote from {:?}: > {:?} / {}", + metadata.sender, + quote, + message.body(), + ); + } else if let Some(reaction) = message.reaction { + println!( + "Reaction to message sent at {:?}: {:?}", + reaction.target_sent_timestamp, reaction.emoji, + ) + } else { + println!("Message from {:?}: {:?}", metadata, message); + // fetch the groups v2 info here, just for testing purposes + if let Some(group_v2) = message.group_v2 { + let _master_key = GroupMasterKey::new( + group_v2.master_key.unwrap().try_into().unwrap(), + ); + // let group = manager.get_group_v2(master_key).await; + // println!("Group v2: {:?}", group); + } + } + } + ContentBody::SynchronizeMessage(m) => { + eprintln!("Unhandled sync message: {:?}", m); + } + ContentBody::TypingMessage(_) => { + println!("{:?} is typing", metadata.sender); + } + ContentBody::CallMessage(_) => { + println!("{:?} is calling!", metadata.sender); + } + ContentBody::ReceiptMessage(_) => { + println!("Got read receipt from: {:?}", metadata.sender); + } + } + } + } + Subcommand::Send { uuid, message } => { + let timestamp = std::time::SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_millis() as u64; + + let message = ContentBody::DataMessage(DataMessage { + body: Some(message), + timestamp: Some(timestamp), + ..Default::default() + }); + + manager.send_message(uuid, message, timestamp).await?; + } + Subcommand::SendToGroup { + recipients, + message, + group_id, + master_key, + } => { + match (group_id.as_ref(), master_key.as_ref()) { + (Some(_), Some(_)) => bail!("Options --group-id and --master-key are exclusive"), + (None, None) => bail!("Either --group-id or --master-key is required"), + _ => (), + } + + let group_id = group_id.map(hex::decode).transpose()?; + let master_key = master_key.map(hex::decode).transpose()?; + + let timestamp = std::time::SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_millis() as u64; + + let data_message = DataMessage { + body: Some(message), + timestamp: Some(timestamp), + group: group_id.map(|id| GroupContext { + id: Some(id), + r#type: Some(GroupType::Deliver.into()), + ..Default::default() + }), + group_v2: master_key.map(|key| GroupContextV2 { + master_key: Some(key), + revision: Some(0), + ..Default::default() + }), + ..Default::default() + }; + + manager + .send_message_to_group( + recipients.into_iter().map(Into::into), + data_message, + timestamp, + ) + .await?; + } + Subcommand::Unregister => unimplemented!(), + Subcommand::RetrieveProfile => { + let profile = manager.retrieve_profile().await?; + println!("{:#?}", profile); + } + Subcommand::UpdateProfile => unimplemented!(), + Subcommand::GetUserStatus => unimplemented!(), + Subcommand::UpdateAccount => { + manager.set_account_attributes().await?; + } + Subcommand::Block => unimplemented!(), + Subcommand::Unblock => unimplemented!(), + Subcommand::UpdateContact => unimplemented!(), + Subcommand::ListGroups => unimplemented!(), + Subcommand::ListContacts => { + for contact in manager.get_contacts()? { + if let Contact { + name, + address: + ServiceAddress { + uuid: Some(uuid), + phonenumber: Some(phonenumber), + .. + }, + .. + } = contact + { + println!("{} / {} / {}", uuid, name, phonenumber); + } + } + } + Subcommand::Whoami => { + println!("{:?}", &manager.whoami().await?) + } + Subcommand::FindContact { uuid, ref name } => { + for contact in manager + .get_contacts()? + .filter(|c| c.address.uuid == uuid) + .filter(|c| name.as_ref().map_or(true, |n| c.name.contains(n))) + { + println!("{}: {}", contact.name, contact.address); + } + } + #[cfg(feature = "quirks")] + Subcommand::RequestSyncContacts => { + manager.request_contacts_sync().await?; + } + #[cfg(feature = "quirks")] + Subcommand::DumpConfig => { + manager.dump_config()?; + } + }; + Ok(()) +} diff --git a/net/gurk-rs/files/vendor/presage/examples/link.rs b/net/gurk-rs/files/vendor/presage/examples/link.rs new file mode 100644 index 0000000..9ddd804 --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/examples/link.rs @@ -0,0 +1,18 @@ +use presage::{prelude::SignalServers, Manager, SledConfigStore}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let config_store = SledConfigStore::new("/tmp/presage-example")?; + + let csprng = rand::thread_rng(); + let mut manager = Manager::new(config_store, csprng)?; + + manager + .link_secondary_device(SignalServers::Production, "my-linked-client".into()) + .await?; + + // scan the QR code that's being opened with your main device + // the store is now initialized, and you're ready to send/receive messages! + + Ok(()) +} diff --git a/net/gurk-rs/files/vendor/presage/examples/register.rs b/net/gurk-rs/files/vendor/presage/examples/register.rs new file mode 100644 index 0000000..9793b5b --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/examples/register.rs @@ -0,0 +1,53 @@ +use std::io::{self, BufRead}; + +use presage::{ + prelude::{phonenumber::PhoneNumber, SignalServers}, + Manager, SledConfigStore, +}; + +fn read_line() -> String { + io::stdin() + .lock() + .lines() + .next() + .expect("stdin should be available") + .expect("couldn't read from stdin") + .trim() + .to_string() +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let config_store = SledConfigStore::new("/tmp/presage-example")?; + + let csprng = rand::thread_rng(); + let mut manager = Manager::new(config_store, csprng)?; + + println!("phone number: "); + let phone_number: PhoneNumber = io::stdin() + .lock() + .lines() + .next() + .expect("stdin should be available") + .expect("couldn't read from stdin") + .trim() + .parse()?; + + manager + .register( + SignalServers::Production, + phone_number, + false, + None, // use a token obtained from https://signalcaptchas.org/registration/generate.html if registration fails + false, + ) + .await?; + + print!("confirmation code: "); + let confirmation_code: u32 = read_line().parse()?; + manager.confirm_verification_code(confirmation_code).await?; + + // the store is now initialized, and you're ready to send/receive messages! + + Ok(()) +} diff --git a/net/gurk-rs/files/vendor/presage/rustfmt.toml b/net/gurk-rs/files/vendor/presage/rustfmt.toml new file mode 100644 index 0000000..4e727a0 --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/rustfmt.toml @@ -0,0 +1 @@ +reorder_imports = true \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/presage/src/cache.rs b/net/gurk-rs/files/vendor/presage/src/cache.rs new file mode 100644 index 0000000..ed39baf --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/src/cache.rs @@ -0,0 +1,75 @@ +use std::cell::Cell; + +pub(crate) struct CacheCell { + cell: Cell>, +} + +impl Clone for CacheCell { + fn clone(&self) -> Self { + let value = self.cell.replace(None); + self.cell.set(value.clone()); + Self { + cell: Cell::new(value), + } + } +} + +impl Default for CacheCell { + fn default() -> Self { + Self { + cell: Cell::new(None), + } + } +} + +impl CacheCell { + pub fn get(&self, factory: impl FnOnce() -> Result) -> Result { + let value = match self.cell.replace(None) { + Some(value) => value, + None => factory()?, + }; + self.cell.set(Some(value.clone())); + Ok(value) + } + + pub fn clear(&self) { + self.cell.set(None) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::convert::Infallible; + + #[test] + fn test_cache_cell() { + let cache: CacheCell = Default::default(); + + let value = cache + .get(|| Ok::<_, Infallible>("Hello, World!".to_string())) + .unwrap(); + assert_eq!(value, "Hello, World!"); + let value = cache + .get(|| -> Result { panic!("I should not run") }) + .unwrap(); + assert_eq!(value, "Hello, World!"); + + let new_cache = cache.clone(); // clone should not touch the cache + let value = cache + .get(|| -> Result { panic!("I should not run") }) + .unwrap(); + assert_eq!(value, "Hello, World!"); + + cache.clear(); + let value = cache + .get(|| Ok::<_, Infallible>("Hi, Amigo!".to_string())) + .unwrap(); + assert_eq!(value, "Hi, Amigo!"); + let value = new_cache + .get(|| -> Result { panic!("I should not run") }) + .unwrap(); + assert_eq!(value, "Hello, World!"); + } +} diff --git a/net/gurk-rs/files/vendor/presage/src/config/mod.rs b/net/gurk-rs/files/vendor/presage/src/config/mod.rs new file mode 100644 index 0000000..231cb63 --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/src/config/mod.rs @@ -0,0 +1,32 @@ +use libsignal_service::{ + models::Contact, + prelude::{ + protocol::{IdentityKeyStore, PreKeyStore, SessionStoreExt, SignedPreKeyStore}, + Uuid, + }, +}; + +use crate::{manager::State, Error}; + +#[cfg(feature = "sled-store")] +pub mod sled; + +pub trait ConfigStore: + PreKeyStore + SignedPreKeyStore + SessionStoreExt + IdentityKeyStore + ContactsStore + Clone +{ + fn state(&self) -> Result; + + fn save(&self, state: &State) -> Result<(), Error>; + + fn pre_keys_offset_id(&self) -> Result; + fn set_pre_keys_offset_id(&self, id: u32) -> Result<(), Error>; + + fn next_signed_pre_key_id(&self) -> Result; + fn set_next_signed_pre_key_id(&self, id: u32) -> Result<(), Error>; +} + +pub trait ContactsStore { + fn save_contacts(&mut self, contacts: impl Iterator) -> Result<(), Error>; + fn contacts(&self) -> Result, Error>; + fn contact_by_id(&self, id: Uuid) -> Result, Error>; +} diff --git a/net/gurk-rs/files/vendor/presage/src/config/sled.rs b/net/gurk-rs/files/vendor/presage/src/config/sled.rs new file mode 100644 index 0000000..b1d908b --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/src/config/sled.rs @@ -0,0 +1,604 @@ +use std::{ + path::PathBuf, + sync::{Arc, RwLock}, +}; + +use async_trait::async_trait; +use libsignal_service::{ + models::Contact, + prelude::{ + protocol::{ + Context, Direction, IdentityKey, IdentityKeyPair, IdentityKeyStore, PreKeyRecord, + PreKeyStore, ProtocolAddress, SessionRecord, SessionStore, SessionStoreExt, + SignalProtocolError, SignedPreKeyRecord, SignedPreKeyStore, + }, + Uuid, + }, +}; +use log::{debug, trace, warn}; +use sled::IVec; + +use super::{ConfigStore, ContactsStore}; +use crate::{manager::State, Error}; + +const SLED_KEY_STATE: &str = "state"; +const SLED_KEY_CONTACTS: &str = "contacts"; + +const SLED_TREE_SESSIONS: &str = "sessions"; + +#[derive(Debug, Clone)] +pub struct SledConfigStore { + db: Arc>, +} + +impl SledConfigStore { + pub fn new(path: impl Into) -> Result { + Ok(SledConfigStore { + db: Arc::new(RwLock::new(sled::open(path.into())?)), + }) + } + + #[cfg(test)] + fn temporary() -> Result { + let db = sled::Config::new().temporary(true).open()?; + Ok(Self { + db: Arc::new(RwLock::new(db)), + }) + } + + pub fn get(&self, key: K) -> Result, Error> + where + K: AsRef, + { + trace!("get {}", key.as_ref()); + Ok(self.db.read().expect("poisoned mutex").get(key.as_ref())?) + } + + fn get_u32(&self, key: S) -> Result, Error> + where + S: AsRef, + { + trace!("getting u32 {}", key.as_ref()); + Ok(self.get(key.as_ref())?.map(|data| { + let mut a: [u8; 4] = Default::default(); + a.copy_from_slice(&data); + u32::from_le_bytes(a) + })) + } + + fn insert(&self, key: K, value: V) -> Result<(), Error> + where + K: AsRef, + IVec: From, + { + trace!("inserting {}", key.as_ref()); + let _ = self + .db + .try_write() + .expect("poisoned mutex") + .insert(key.as_ref(), value)?; + Ok(()) + } + + fn insert_u32(&self, key: S, value: u32) -> Result<(), Error> + where + S: AsRef, + { + trace!("inserting u32 {}", key.as_ref()); + self.db + .try_write() + .expect("poisoned mutex") + .insert(key.as_ref(), &value.to_le_bytes())?; + Ok(()) + } + + fn remove(&self, key: S) -> Result<(), Error> + where + S: AsRef, + { + trace!("removing {} from db", key.as_ref()); + self.db + .try_write() + .expect("poisoned mutex") + .remove(key.as_ref())?; + Ok(()) + } + + fn prekey_key(&self, id: u32) -> String { + format!("prekey-{:09}", id) + } + + fn signed_prekey_key(&self, id: u32) -> String { + format!("signed-prekey-{:09}", id) + } + + fn session_key(&self, addr: &ProtocolAddress) -> String { + format!("session-{}", addr) + } + + fn session_prefix(&self, name: &str) -> String { + format!("session-{}.", name) + } + + fn identity_key(&self, addr: &ProtocolAddress) -> String { + format!("identity-remote-{}", addr) + } + + pub fn keys(&self) -> Result<(Vec, Vec), SignalProtocolError> { + let db = self.db.read().expect("poisoned mutex"); + let global_keys = db + .iter() + .filter_map(|r| { + let (k, _) = r.ok()?; + Some(String::from_utf8_lossy(&k).to_string()) + }) + .collect(); + let session_keys = db + .open_tree(SLED_TREE_SESSIONS) + .map_err(|e| { + log::error!("failed to open sessions tree: {}", e); + SignalProtocolError::InternalError("sled error") + })? + .iter() + .filter_map(|r| { + let (k, _) = r.ok()?; + Some(String::from_utf8_lossy(&k).to_string()) + }) + .collect(); + Ok((global_keys, session_keys)) + } +} + +impl ConfigStore for SledConfigStore { + fn state(&self) -> Result { + let db = self.db.read().expect("poisoned mutex"); + db.get(SLED_KEY_STATE)?.map_or(Ok(State::New), |s| { + serde_json::from_slice(&s).map_err(Error::from) + }) + } + + fn save(&self, state: &State) -> Result<(), Error> { + let db = self.db.try_write().expect("poisoned mutex"); + db.clear()?; + db.insert(SLED_KEY_STATE, serde_json::to_vec(state)?)?; + Ok(()) + } + + fn pre_keys_offset_id(&self) -> Result { + Ok(self.get_u32("pre_keys_offset_id")?.unwrap_or(0)) + } + + fn set_pre_keys_offset_id(&self, id: u32) -> Result<(), Error> { + self.insert_u32("pre_keys_offset_id", id) + } + + fn next_signed_pre_key_id(&self) -> Result { + Ok(self.get_u32("next_signed_pre_key_id")?.unwrap_or(0)) + } + + fn set_next_signed_pre_key_id(&self, id: u32) -> Result<(), Error> { + self.insert_u32("next_signed_pre_key_id", id) + } +} + +impl ContactsStore for SledConfigStore { + fn save_contacts(&mut self, contacts: impl Iterator) -> Result<(), Error> { + let tree = self + .db + .write() + .expect("poisoned mutex") + .open_tree(SLED_KEY_CONTACTS)?; + for contact in contacts { + if let Some(uuid) = contact.address.uuid { + tree.insert(uuid.to_string(), serde_json::to_vec(&contact)?)?; + } else { + warn!("skipping contact {:?} without uuid", contact); + } + } + debug!("saved contacts"); + Ok(()) + } + + fn contacts(&self) -> Result, Error> { + Ok(self + .db + .read() + .expect("poisoned mutex") + .open_tree(SLED_KEY_CONTACTS)? + .iter() + .filter_map(Result::ok) + .filter_map(|(_key, buf)| serde_json::from_slice(&buf).ok()) + .collect()) + } + + fn contact_by_id(&self, id: Uuid) -> Result, Error> { + let db = self.db.read().expect("poisoned mutex"); + Ok( + if let Some(buf) = db.open_tree(SLED_KEY_CONTACTS)?.get(id.to_string())? { + let contact = serde_json::from_slice(&buf)?; + Some(contact) + } else { + None + }, + ) + } +} + +#[async_trait(?Send)] +impl PreKeyStore for SledConfigStore { + async fn get_pre_key( + &self, + prekey_id: u32, + _ctx: Context, + ) -> Result { + let buf = self + .get(self.prekey_key(prekey_id)) + .map_err(|e| { + log::error!("{}", e); + SignalProtocolError::InternalError("sled error") + })? + .ok_or(SignalProtocolError::InvalidPreKeyId)?; + PreKeyRecord::deserialize(&buf) + } + + async fn save_pre_key( + &mut self, + prekey_id: u32, + record: &PreKeyRecord, + _ctx: Context, + ) -> Result<(), SignalProtocolError> { + self.insert(self.prekey_key(prekey_id), record.serialize()?) + .expect("failed to store pre-key"); + Ok(()) + } + + async fn remove_pre_key( + &mut self, + prekey_id: u32, + _ctx: Context, + ) -> Result<(), SignalProtocolError> { + self.remove(self.prekey_key(prekey_id)) + .expect("failed to remove pre-key"); + Ok(()) + } +} + +#[async_trait(?Send)] +impl SignedPreKeyStore for SledConfigStore { + async fn get_signed_pre_key( + &self, + signed_prekey_id: u32, + _ctx: Context, + ) -> Result { + let buf = self + .get(self.signed_prekey_key(signed_prekey_id)) + .map_err(|e| { + log::error!("sled error: {}", e); + SignalProtocolError::InternalError("sled error") + })? + .ok_or(SignalProtocolError::InvalidSignedPreKeyId)?; + SignedPreKeyRecord::deserialize(&buf) + } + + async fn save_signed_pre_key( + &mut self, + signed_prekey_id: u32, + record: &SignedPreKeyRecord, + _ctx: Context, + ) -> Result<(), SignalProtocolError> { + self.insert( + self.signed_prekey_key(signed_prekey_id), + record.serialize()?, + ) + .map_err(|e| { + log::error!("sled error: {}", e); + SignalProtocolError::InternalError("sled error") + }) + } +} + +#[async_trait(?Send)] +impl SessionStore for SledConfigStore { + async fn load_session( + &self, + address: &ProtocolAddress, + _ctx: Context, + ) -> Result, SignalProtocolError> { + let key = self.session_key(address); + trace!("loading session from {}", key); + + let buf = self + .db + .try_read() + .expect("poisoned mutex") + .open_tree(SLED_TREE_SESSIONS) + .map_err(|e| { + log::error!("failed to open sessions tree: {}", e); + SignalProtocolError::InternalError("sled error") + })? + .get(key) + .map_err(|e| { + log::error!("sled error: {}", e); + SignalProtocolError::InternalError("sled error") + })?; + + buf.map(|buf| SessionRecord::deserialize(&buf)).transpose() + } + + async fn store_session( + &mut self, + address: &ProtocolAddress, + record: &SessionRecord, + _ctx: Context, + ) -> Result<(), SignalProtocolError> { + let key = self.session_key(address); + trace!("storing session for {:?} at {:?}", address, key); + self.db + .try_write() + .expect("poisoned mutex") + .open_tree(SLED_TREE_SESSIONS) + .map_err(|e| { + log::error!("failed to open sessions tree: {}", e); + SignalProtocolError::InternalError("sled error") + })? + .insert(key, record.serialize()?) + .map_err(|e| { + log::error!("failed to open sessions tree: {}", e); + SignalProtocolError::InternalError("sled error") + })?; + Ok(()) + } +} + +#[async_trait] +impl SessionStoreExt for SledConfigStore { + async fn get_sub_device_sessions(&self, name: &str) -> Result, SignalProtocolError> { + let session_prefix = self.session_prefix(name); + log::info!("get_sub_device_sessions: session_prefix={}", session_prefix); + let session_ids: Vec = self + .db + .read() + .expect("poisoned mutex") + .open_tree(SLED_TREE_SESSIONS) + .map_err(|e| { + log::error!("failed to open sessions tree: {}", e); + SignalProtocolError::InternalError("sled error") + })? + .scan_prefix(&session_prefix) + .filter_map(|r| { + let (key, _) = r.ok()?; + let key_str = String::from_utf8_lossy(&key); + let device_id = key_str.strip_prefix(&session_prefix)?; + device_id.parse().ok() + }) + .collect(); + Ok(session_ids) + } + + async fn delete_session(&self, address: &ProtocolAddress) -> Result<(), SignalProtocolError> { + let key = self.session_key(address); + trace!("deleting session with key: {}", key); + self.db + .try_write() + .expect("poisoned mutex") + .open_tree(SLED_TREE_SESSIONS) + .map_err(|e| { + log::error!("failed to open sessions tree: {}", e); + SignalProtocolError::InternalError("sled error") + })? + .remove(key) + .map_err(|_e| SignalProtocolError::InternalError("failed to delete session"))?; + Ok(()) + } + + async fn delete_all_sessions(&self, _name: &str) -> Result { + let tree = self + .db + .try_write() + .expect("poisoned mutex") + .open_tree(SLED_TREE_SESSIONS) + .map_err(|e| { + log::error!("failed to open sessions tree: {}", e); + SignalProtocolError::InternalError("sled error") + })?; + let len = tree.len(); + tree.clear() + .map_err(|_e| SignalProtocolError::InternalError("failed to delete all sessions"))?; + Ok(len) + } +} + +#[async_trait(?Send)] +impl IdentityKeyStore for SledConfigStore { + async fn get_identity_key_pair( + &self, + _ctx: Context, + ) -> Result { + trace!("getting identity_key_pair"); + match self.state() { + Ok(State::Registered { + private_key, + public_key, + .. + }) => Ok(IdentityKeyPair::new( + IdentityKey::new(public_key), + private_key, + )), + Ok(_) => Err(SignalProtocolError::InternalError( + "wrong state: no registration data yet", + )), + Err(e) => { + log::error!("identity key store error: {}", e); + Err(SignalProtocolError::InternalError("unhandled error")) + } + } + } + + async fn get_local_registration_id(&self, _ctx: Context) -> Result { + trace!("getting local_registration_id"); + match self.state() { + Ok(State::Registered { + registration_id, .. + }) => Ok(registration_id), + Ok(_) => Err(SignalProtocolError::InternalError( + "wrong state: no registration data yet", + )), + Err(e) => { + log::error!("identity key store error: {}", e); + Err(SignalProtocolError::InternalError("unhandled error")) + } + } + } + + async fn save_identity( + &mut self, + address: &ProtocolAddress, + identity_key: &IdentityKey, + _ctx: Context, + ) -> Result { + trace!("saving identity"); + self.insert(self.identity_key(address), identity_key.serialize()) + .map_err(|e| { + log::error!("error saving identity for {:?}: {}", address, e); + SignalProtocolError::InternalError("failed to save identity") + })?; + trace!("saved identity"); + Ok(false) + } + + async fn is_trusted_identity( + &self, + address: &ProtocolAddress, + identity_key: &IdentityKey, + _direction: Direction, + _ctx: Context, + ) -> Result { + match self.get(self.identity_key(address)).map_err(|_| { + SignalProtocolError::InternalError("failed to check if identity is trusted") + })? { + None => { + // when we encounter a new identity, we trust it by default + warn!("trusting new identity {:?}", address); + Ok(true) + } + Some(contents) => Ok(&IdentityKey::decode(&contents)? == identity_key), + } + } + + async fn get_identity( + &self, + address: &ProtocolAddress, + _ctx: Context, + ) -> Result, SignalProtocolError> { + let buf = self.get(self.identity_key(address)).map_err(|e| { + log::error!("error getting identity of {:?}: {}", address, e); + SignalProtocolError::InternalError("failed to read identity") + })?; + Ok(buf.map(|ref b| IdentityKey::decode(b).unwrap())) + } +} + +#[cfg(test)] +mod tests { + use core::fmt; + + use libsignal_service::prelude::protocol::{ + self, Direction, IdentityKeyStore, PreKeyRecord, PreKeyStore, SessionRecord, SessionStore, + SignedPreKeyRecord, SignedPreKeyStore, + }; + use quickcheck::{Arbitrary, Gen}; + + use super::SledConfigStore; + + #[derive(Debug, Clone)] + struct ProtocolAddress(protocol::ProtocolAddress); + + #[derive(Clone)] + struct KeyPair(protocol::KeyPair); + + impl fmt::Debug for KeyPair { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "{}", base64::encode(self.0.public_key.serialize())) + } + } + + impl Arbitrary for ProtocolAddress { + fn arbitrary(g: &mut Gen) -> Self { + let name: String = Arbitrary::arbitrary(g); + let device_id: u8 = Arbitrary::arbitrary(g); + ProtocolAddress(protocol::ProtocolAddress::new(name, device_id.into())) + } + } + + impl Arbitrary for KeyPair { + fn arbitrary(_g: &mut Gen) -> Self { + // Gen is not rand::CryptoRng here, see https://github.com/BurntSushi/quickcheck/issues/241 + KeyPair(protocol::KeyPair::generate(&mut rand::thread_rng())) + } + } + + #[quickcheck_async::tokio] + async fn test_save_get_trust_identity(addr: ProtocolAddress, key_pair: KeyPair) -> bool { + let mut db = SledConfigStore::temporary().unwrap(); + let identity_key = protocol::IdentityKey::new(key_pair.0.public_key); + db.save_identity(&addr.0, &identity_key, None) + .await + .unwrap(); + let id = db.get_identity(&addr.0, None).await.unwrap().unwrap(); + if id != identity_key { + return false; + } + db.is_trusted_identity(&addr.0, &id, Direction::Receiving, None) + .await + .unwrap() + } + + #[quickcheck_async::tokio] + async fn test_store_load_session(addr: ProtocolAddress) -> bool { + let session = SessionRecord::new_fresh(); + + let mut db = SledConfigStore::temporary().unwrap(); + db.store_session(&addr.0, &session, None).await.unwrap(); + if db.load_session(&addr.0, None).await.unwrap().is_none() { + return false; + } + let loaded_session = db.load_session(&addr.0, None).await.unwrap().unwrap(); + session.serialize().unwrap() == loaded_session.serialize().unwrap() + } + + #[quickcheck_async::tokio] + async fn test_prekey_store(id: u32, key_pair: KeyPair) -> bool { + let mut db = SledConfigStore::temporary().unwrap(); + let pre_key_record = PreKeyRecord::new(id, &key_pair.0); + db.save_pre_key(id, &pre_key_record, None).await.unwrap(); + if db.get_pre_key(id, None).await.unwrap().serialize().unwrap() + != pre_key_record.serialize().unwrap() + { + return false; + } + + db.remove_pre_key(id, None).await.unwrap(); + db.get_pre_key(id, None).await.is_err() + } + + #[quickcheck_async::tokio] + async fn test_signed_prekey_store( + id: u32, + timestamp: u64, + key_pair: KeyPair, + signature: Vec, + ) -> bool { + let mut db = SledConfigStore::temporary().unwrap(); + let signed_pre_key_record = SignedPreKeyRecord::new(id, timestamp, &key_pair.0, &signature); + db.save_signed_pre_key(id, &signed_pre_key_record, None) + .await + .unwrap(); + + db.get_signed_pre_key(id, None) + .await + .unwrap() + .serialize() + .unwrap() + == signed_pre_key_record.serialize().unwrap() + } +} diff --git a/net/gurk-rs/files/vendor/presage/src/errors.rs b/net/gurk-rs/files/vendor/presage/src/errors.rs new file mode 100644 index 0000000..8030663 --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/src/errors.rs @@ -0,0 +1,52 @@ +use std::borrow::Cow; + +use libsignal_service::{models::ParseContactError, prelude::protocol::SignalProtocolError}; + +#[derive(thiserror::Error, Debug)] +#[non_exhaustive] +pub enum Error { + #[error("captcha from https://signalcaptchas.org/registration/generate.html required")] + CaptchaRequired, + #[error("input/output error: {0}")] + IoError(#[from] std::io::Error), + #[error("JSON error: {0}")] + JsonError(#[from] serde_json::Error), + #[error("data store error: {0}")] + DbError(#[from] sled::Error), + #[error("error decoding base64 data: {0}")] + Base64Error(#[from] base64::DecodeError), + #[error("wrong slice size: {0}")] + TryFromSliceError(#[from] std::array::TryFromSliceError), + #[error("phone number parsing error: {0}")] + PhoneNumberError(#[from] libsignal_service::prelude::phonenumber::ParseError), + #[error("UUID decoding error: {0}")] + UuidError(#[from] libsignal_service::prelude::UuidError), + #[error("libsignal-protocol error: {0}")] + ProtocolError(#[from] SignalProtocolError), + #[error("libsignal-service error: {0}")] + ServiceError(#[from] libsignal_service::prelude::ServiceError), + #[error("libsignal-service error: {0}")] + ProfileManagerError(#[from] libsignal_service::ProfileManagerError), + #[error("libsignal-service sending error: {0}")] + MessageSenderError(#[from] libsignal_service::prelude::MessageSenderError), + #[error("libsignal-service error: {0}")] + MessageReceiverError(#[from] libsignal_service::receiver::MessageReceiverError), + #[error("this client is already registered with Signal")] + AlreadyRegisteredError, + #[error("this client is not yet registered, please register or link as a secondary device")] + NotYetRegisteredError, + #[error("failed to provision device: {0}")] + ProvisioningError(#[from] libsignal_service::provisioning::ProvisioningError), + #[error("no provisioning message received")] + NoProvisioningMessageReceived, + #[error("qr code error: {0}")] + QrCodeError(qr2term::QrError), + #[error("missing key {0} in config DB")] + MissingKeyError(Cow<'static, str>), + #[error("receiving pipe was interrupted")] + MessagePipeInterruptedError, + #[error("failed to parse contact information: {0}")] + ParseContactError(#[from] ParseContactError), + #[error("failed to decrypt attachment: {0}")] + AttachmentCipherError(#[from] libsignal_service::attachment_cipher::AttachmentCipherError), +} diff --git a/net/gurk-rs/files/vendor/presage/src/lib.rs b/net/gurk-rs/files/vendor/presage/src/lib.rs new file mode 100644 index 0000000..faad192 --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/src/lib.rs @@ -0,0 +1,34 @@ +mod cache; +mod config; +mod errors; +mod manager; + +#[cfg(feature = "sled-store")] +pub use config::sled::SledConfigStore; + +pub use config::ConfigStore; +pub use errors::Error; +pub use manager::{Manager, State}; + +#[deprecated(note = "Please help use improve the prelude module instead")] +pub use libsignal_service; + +pub mod prelude { + pub use libsignal_service::{ + configuration::SignalServers, + content::{ + self, Content, ContentBody, DataMessage, GroupContext, GroupContextV2, GroupType, + Metadata, SyncMessage, + }, + models::Contact, + prelude::{ + phonenumber::{self, PhoneNumber}, + GroupMasterKey, GroupSecretParams, Uuid, + }, + proto, + sender::AttachmentSpec, + ServiceAddress, + }; +} + +const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "-rs-", env!("CARGO_PKG_VERSION")); diff --git a/net/gurk-rs/files/vendor/presage/src/manager.rs b/net/gurk-rs/files/vendor/presage/src/manager.rs new file mode 100644 index 0000000..b56ef9c --- /dev/null +++ b/net/gurk-rs/files/vendor/presage/src/manager.rs @@ -0,0 +1,807 @@ +use std::{convert::TryInto, time::UNIX_EPOCH}; + +use futures::{channel::mpsc, future, AsyncReadExt, Stream, StreamExt}; +use log::{error, trace, warn}; +use rand::{distributions::Alphanumeric, CryptoRng, Rng, RngCore}; +use serde::{Deserialize, Serialize}; + +use libsignal_service::{ + attachment_cipher::decrypt_in_place, + cipher, + configuration::{ServiceConfiguration, SignalServers, SignalingKey}, + content::{ContentBody, DataMessage, SyncMessage}, + groups_v2::{GroupsManager, InMemoryCredentialsCache}, + messagepipe::ServiceCredentials, + models::Contact, + prelude::{ + phonenumber::PhoneNumber, + protocol::{KeyPair, PrivateKey, PublicKey}, + Content, Envelope, GroupMasterKey, GroupSecretParams, PushService, Uuid, + }, + proto::{sync_message, AttachmentPointer}, + provisioning::{ + generate_registration_id, LinkingManager, ProvisioningManager, SecondaryDeviceProvisioning, + VerificationCodeResponse, + }, + push_service::{ + AccountAttributes, DeviceCapabilities, ProfileKey, ServiceError, WhoAmIResponse, + DEFAULT_DEVICE_ID, + }, + receiver::MessageReceiver, + sender::{AttachmentSpec, AttachmentUploadError}, + utils::{serde_private_key, serde_public_key, serde_signaling_key}, + AccountManager, Profile, ServiceAddress, +}; + +use libsignal_service_hyper::push_service::HyperPushService; + +use crate::cache::CacheCell; +use crate::{config::ConfigStore, Error}; + +type ServiceCipher = cipher::ServiceCipher; +type MessageSender = + libsignal_service::prelude::MessageSender; + +#[derive(Clone)] +pub struct Manager { + /// Persistent store + config_store: C, + /// Random generator + csprng: R, + /// Part of the manager which is persisted in the store. + state: State, + /// Part of the manager which is cached. + /// + /// The cache should be cleared when state changes. + cache: Cache, +} + +#[derive(Clone, Default)] +struct Cache { + push_service: CacheCell, +} + +impl Cache { + fn clear(&self) { + self.push_service.clear(); + } +} + +#[derive(Clone, Serialize, Deserialize)] +pub enum State { + New, + Registration { + signal_servers: SignalServers, + phone_number: PhoneNumber, + use_voice_call: bool, + }, + Linking { + signal_servers: SignalServers, + #[serde(with = "serde_signaling_key")] + signaling_key: SignalingKey, + password: String, + }, + Confirmation { + signal_servers: SignalServers, + phone_number: PhoneNumber, + password: String, + }, + Registered { + signal_servers: SignalServers, + device_name: Option, + phone_number: PhoneNumber, + uuid: Uuid, + password: String, + #[serde(with = "serde_signaling_key")] + signaling_key: SignalingKey, + device_id: Option, + registration_id: u32, + #[serde(with = "serde_private_key")] + private_key: PrivateKey, + #[serde(with = "serde_public_key")] + public_key: PublicKey, + profile_key: ProfileKey, + }, +} + +impl Manager +where + C: ConfigStore + Sync, +{ + /// Creates a new manager from a store with a default random generator. + pub fn with_store(store: C) -> Result { + Self::new(store, rand::thread_rng()) + } +} + +impl Manager +where + C: ConfigStore + Sync, + R: Rng + CryptoRng + Clone, +{ + pub fn new(config_store: C, csprng: R) -> Result { + let state = config_store.state()?; + Ok(Manager { + config_store, + csprng, + state, + cache: Default::default(), + }) + } + + /// Sets the state and saves it into the store. + /// + /// The cache is also cleared. + fn set_state(&mut self, state: State) -> Result<(), Error> { + self.state = state; + self.cache.clear(); + self.config_store.save(&self.state) + } + + fn credentials(&self) -> Result, Error> { + match &self.state { + State::New { .. } => Err(Error::NotYetRegisteredError), + State::Registration { .. } => Ok(None), + State::Linking { .. } => Ok(None), + State::Confirmation { + phone_number, + password, + .. + } => Ok(Some(ServiceCredentials { + uuid: None, + phonenumber: phone_number.clone(), + password: Some(password.clone()), + signaling_key: None, + device_id: None, + })), + State::Registered { + phone_number, + uuid, + device_id, + password, + signaling_key, + .. + } => Ok(Some(ServiceCredentials { + uuid: Some(*uuid), + phonenumber: phone_number.clone(), + password: Some(password.clone()), + signaling_key: Some(*signaling_key), + device_id: *device_id, + })), + } + } + + /// Checks if the manager has a registered device. + pub fn is_registered(&self) -> bool { + matches!(&self.state, State::Registered { .. }) + } + + pub fn config_store(&self) -> &C { + &self.config_store + } + + pub fn uuid(&self) -> Uuid { + match &self.state { + State::Registered { uuid, .. } => *uuid, + _ => Default::default(), + } + } + + pub fn phone_number(&self) -> Option<&PhoneNumber> { + match &self.state { + State::Registered { phone_number, .. } => Some(phone_number), + _ => None, + } + } + + #[cfg(feature = "quirks")] + pub fn dump_config(&mut self) -> Result<(), Error> { + serde_json::to_writer_pretty(std::io::stderr(), &self.state)?; + + Ok(()) + } + + pub async fn register( + &mut self, + signal_servers: SignalServers, + phone_number: PhoneNumber, + use_voice_call: bool, + captcha: Option<&str>, + force: bool, + ) -> Result<(), Error> { + // generate a random 24 bytes password + let rng = rand::rngs::OsRng::default(); + let password: String = rng.sample_iter(&Alphanumeric).take(24).collect(); + + if !force + && matches!( + self.state, + State::Registration { .. } | State::Registered { .. } + ) + { + return Err(Error::AlreadyRegisteredError); + } + + // re-initialize the state to new with specified servers & phone number + self.set_state(State::Registration { + signal_servers, + phone_number: phone_number.clone(), + use_voice_call, + })?; + + let mut push_service = self.push_service()?; + let mut provisioning_manager: ProvisioningManager = + ProvisioningManager::new(&mut push_service, phone_number.clone(), password.clone()); + + let verification_code_response = if use_voice_call { + provisioning_manager + .request_voice_verification_code(captcha, None) + .await? + } else { + provisioning_manager + .request_sms_verification_code(captcha, None) + .await? + }; + + if let VerificationCodeResponse::CaptchaRequired = verification_code_response { + return Err(Error::CaptchaRequired); + } + + self.set_state(State::Confirmation { + signal_servers, + phone_number, + password, + }) + } + + pub async fn confirm_verification_code(&mut self, confirm_code: u32) -> Result<(), Error> { + trace!("confirming verification code"); + let (signal_servers, phone_number, password) = match &self.state { + State::Confirmation { + signal_servers, + phone_number, + password, + } => (*signal_servers, phone_number, password), + State::Registered { .. } => return Err(Error::AlreadyRegisteredError), + _ => return Err(Error::NotYetRegisteredError), + }; + + // see libsignal-protocol-c / signal_protocol_key_helper_generate_registration_id + let registration_id = generate_registration_id(&mut self.csprng); + trace!("registration_id: {}", registration_id); + + let mut push_service = self.push_service()?; + let mut provisioning_manager: ProvisioningManager = + ProvisioningManager::new( + &mut push_service, + phone_number.clone(), + password.to_string(), + ); + + let mut rng = rand::thread_rng(); + + // generate a 52 bytes signaling key + let mut signaling_key = [0u8; 52]; + rng.fill_bytes(&mut signaling_key); + + let mut profile_key = [0u8; 32]; + rng.fill_bytes(&mut profile_key); + let profile_key = ProfileKey(profile_key); + + let registered = provisioning_manager + .confirm_verification_code( + confirm_code, + AccountAttributes { + signaling_key: Some(signaling_key.to_vec()), + registration_id, + voice: false, + video: false, + fetches_messages: true, + pin: None, + registration_lock: None, + unidentified_access_key: Some(profile_key.derive_access_key()), + unrestricted_unidentified_access: false, // TODO: make this configurable? + discoverable_by_phone_number: true, + capabilities: DeviceCapabilities { + uuid: true, + gv2: true, + storage: false, + gv1_migration: true, + }, + }, + ) + .await?; + + let identity_key_pair = KeyPair::generate(&mut self.csprng); + + let phone_number = phone_number.clone(); + let password = password.clone(); + self.set_state(State::Registered { + signal_servers, + device_name: None, + phone_number, + uuid: registered.uuid, + password, + signaling_key, + device_id: None, + registration_id, + private_key: identity_key_pair.private_key, + public_key: identity_key_pair.public_key, + profile_key, + })?; + + trace!("confirmed! (and registered)"); + + self.register_pre_keys().await?; + + Ok(()) + } + + pub async fn link_secondary_device( + &mut self, + signal_servers: SignalServers, + device_name: String, + ) -> Result<(), Error> { + // generate a random 24 bytes password + let mut rng = rand::rngs::OsRng::default(); + let password: String = rng.sample_iter(&Alphanumeric).take(24).collect(); + + // generate a 52 bytes signaling key + let mut signaling_key = [0u8; 52]; + rng.fill_bytes(&mut signaling_key); + + self.set_state(State::Linking { + signal_servers, + password: password.clone(), + signaling_key, + })?; + + let push_service = self.push_service()?; + let mut linking_manager: LinkingManager = + LinkingManager::new(push_service, password.clone()); + + let (tx, mut rx) = mpsc::channel(1); + + let (fut1, fut2) = future::join( + linking_manager.provision_secondary_device(&mut self.csprng, signaling_key, tx), + async move { + while let Some(provisioning_step) = rx.next().await { + match provisioning_step { + SecondaryDeviceProvisioning::Url(url) => { + log::info!("generating qrcode from provisioning link: {}", &url); + qr2term::print_qr(url.to_string()).map_err(|e| { + log::error!("failed to open qr code: {}", e); + Error::QrCodeError(e) + })?; + } + SecondaryDeviceProvisioning::NewDeviceRegistration { + phone_number, + device_id, + registration_id, + uuid, + private_key, + public_key, + profile_key, + } => { + log::info!("successfully registered device {}", &uuid); + return Ok(( + phone_number, + device_id.device_id, + registration_id, + uuid, + private_key, + public_key, + profile_key, + )); + } + } + } + Err(Error::NoProvisioningMessageReceived) + }, + ) + .await; + + let _ = fut1?; + let (phone_number, device_id, registration_id, uuid, private_key, public_key, profile_key) = + fut2?; + + self.set_state(State::Registered { + signal_servers, + device_name: Some(device_name), + phone_number, + uuid, + signaling_key, + password, + device_id: Some(device_id), + registration_id, + public_key, + private_key, + profile_key: ProfileKey(profile_key.try_into().expect("32 bytes for profile key")), + })?; + + self.register_pre_keys().await?; + self.set_account_attributes().await?; + self.request_contacts_sync().await?; + + Ok(()) + } + + pub async fn whoami(&self) -> Result { + Ok(self.push_service()?.whoami().await?) + } + + pub async fn retrieve_profile(&self) -> Result { + match &self.state { + State::Registered { + uuid, profile_key, .. + } => self.retrieve_profile_by_uuid(*uuid, **profile_key).await, + _ => Err(Error::NotYetRegisteredError), + } + } + + pub async fn retrieve_profile_by_uuid( + &self, + uuid: Uuid, + profile_key: [u8; 32], + ) -> Result { + let mut account_manager = AccountManager::new(self.push_service()?, Some(profile_key)); + Ok(account_manager.retrieve_profile(uuid).await?) + } + + async fn register_pre_keys(&mut self) -> Result<(), Error> { + let profile_key = match &self.state { + State::Registered { profile_key, .. } => profile_key, + _ => return Err(Error::NotYetRegisteredError), + }; + + let mut account_manager = AccountManager::new(self.push_service()?, Some(**profile_key)); + + let (pre_keys_offset_id, next_signed_pre_key_id) = account_manager + .update_pre_key_bundle( + &self.config_store.clone(), + &mut self.config_store.clone(), + &mut self.config_store.clone(), + &mut self.csprng, + self.config_store.pre_keys_offset_id()?, + self.config_store.next_signed_pre_key_id()?, + true, + ) + .await?; + + self.config_store + .set_pre_keys_offset_id(pre_keys_offset_id)?; + self.config_store + .set_next_signed_pre_key_id(next_signed_pre_key_id)?; + + Ok(()) + } + + pub async fn set_account_attributes(&mut self) -> Result<(), Error> { + let (profile_key, registration_id) = match &self.state { + State::Registered { + profile_key, + registration_id, + .. + } => (profile_key, registration_id), + _ => return Err(Error::NotYetRegisteredError), + }; + dbg!(profile_key.derive_access_key().len()); + + let mut account_manager = AccountManager::new(self.push_service()?, Some(**profile_key)); + account_manager + .set_account_attributes(AccountAttributes { + registration_id: *registration_id, + signaling_key: None, + voice: false, + video: false, + fetches_messages: true, + pin: None, + registration_lock: None, + unidentified_access_key: Some(profile_key.derive_access_key()), + unrestricted_unidentified_access: false, + discoverable_by_phone_number: true, + capabilities: DeviceCapabilities { + uuid: true, + storage: false, + gv2: true, + gv1_migration: true, + }, + }) + .await?; + Ok(()) + } + + /// Request that the primary device to encrypt & send all of its contacts as a message to ourselves + /// which can be then received, decrypted and stored in the message receiving loop. + /// + /// Note: if this is successful, the contacts are not yet received & stored, and will only be + /// processed when they're received using the `MessageReceiver`. + pub async fn request_contacts_sync(&self) -> Result<(), Error> { + let uuid = match &self.state { + State::Registered { uuid, .. } => uuid, + _ => return Err(Error::NotYetRegisteredError), + }; + + let sync_message = SyncMessage { + request: Some(sync_message::Request { + r#type: Some(sync_message::request::Type::Contacts as i32), + }), + ..Default::default() + }; + + let timestamp = std::time::SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_millis() as u64; + + self.send_message(*uuid, sync_message, timestamp).await?; + + Ok(()) + } + + pub fn get_contacts(&self) -> Result, Error> { + Ok(self.config_store.contacts()?.into_iter()) + } + + pub fn get_contact_by_id(&self, id: Uuid) -> Result, Error> { + self.config_store.contact_by_id(id) + } + + async fn receive_messages_encrypted( + &self, + ) -> Result>, Error> { + // TODO: error if we're primary registered device, as this is only for secondary devices + + let credentials = self.credentials()?.ok_or(Error::NotYetRegisteredError)?; + let pipe = MessageReceiver::new(self.push_service()?) + .create_message_pipe(credentials) + .await?; + Ok(pipe.stream()) + } + + pub async fn receive_messages(&self) -> Result, Error> { + struct StreamState { + encrypted_messages: S, + service_cipher: ServiceCipher, + push_service: HyperPushService, + config_store: C, + } + + let init = StreamState { + encrypted_messages: Box::pin(self.receive_messages_encrypted().await?), + service_cipher: self.new_service_cipher()?, + push_service: self.push_service()?, + config_store: self.config_store.clone(), + }; + + Ok(futures::stream::unfold(init, |mut state| async move { + loop { + match state.encrypted_messages.next().await { + Some(Ok(envelope)) => { + match state.service_cipher.open_envelope(envelope).await { + Ok(Some(Content { + body: + ContentBody::SynchronizeMessage(SyncMessage { + contacts: Some(contacts), + .. + }), + .. + })) => { + let mut message_receiver = + MessageReceiver::new(state.push_service.clone()); + match message_receiver.retrieve_contacts(&contacts).await { + Ok(contacts_iter) => { + if let Err(e) = state + .config_store + .save_contacts(contacts_iter.filter_map(Result::ok)) + { + error!("failed to save contacts: {}", e) + } + } + Err(e) => error!("failed to retrieve contacts: {}", e), + } + } + Ok(Some(content)) => return Some((content, state)), + Ok(None) => warn!("Empty envelope..., message will be skipped!"), + Err(e) => { + error!("Error opening envelope: {:?}, message will be skipped!", e); + } + } + } + Some(Err(e)) => error!("Error: {}", e), + None => return None, + } + } + })) + } + + pub async fn send_message( + &self, + recipient_addr: impl Into, + message: impl Into, + timestamp: u64, + ) -> Result<(), Error> { + let mut sender = self.new_message_sender()?; + + let online_only = false; + sender + .send_message( + &recipient_addr.into(), + None, + message, + timestamp, + online_only, + ) + .await?; + + Ok(()) + } + + pub async fn upload_attachments( + &self, + attachments: Vec<(AttachmentSpec, Vec)>, + ) -> Result>, Error> { + let sender = self.new_message_sender()?; + let upload = future::join_all(attachments.into_iter().map(move |(spec, contents)| { + let mut sender = sender.clone(); + async move { sender.upload_attachment(spec, contents).await } + })); + Ok(upload.await) + } + + pub async fn send_message_to_group( + &self, + recipients: impl IntoIterator, + message: DataMessage, + timestamp: u64, + ) -> Result<(), Error> { + let mut sender = self.new_message_sender()?; + + let recipients: Vec<_> = recipients.into_iter().collect(); + + let online_only = false; + let results = sender + .send_message_to_group(recipients, None, message, timestamp, online_only) + .await; + + // return first error if any + results.into_iter().find(|res| res.is_err()).transpose()?; + + Ok(()) + } + + pub async fn clear_sessions(&self, recipient: &ServiceAddress) -> Result<(), Error> { + self.config_store + .delete_all_sessions(&recipient.identifier()) + .await?; + Ok(()) + } + + pub async fn get_group_v2( + &mut self, + group_master_key: GroupMasterKey, + ) -> Result { + let (signal_servers, _phone_number, uuid, _device_id) = match &self.state { + State::Registered { + signal_servers, + phone_number, + uuid, + device_id, + .. + } => (signal_servers, phone_number, uuid, device_id), + _ => return Err(Error::NotYetRegisteredError), + }; + + let service_configuration: ServiceConfiguration = (*signal_servers).into(); + let server_public_params = service_configuration.zkgroup_server_public_params; + + let mut groups_v2_credentials_cache = InMemoryCredentialsCache::default(); + let mut groups_v2_api = GroupsManager::new( + self.push_service()?, + &mut groups_v2_credentials_cache, + server_public_params, + ); + + let group_secret_params = GroupSecretParams::derive_from_master_key(group_master_key); + let authorization = groups_v2_api + .get_authorization_for_today(*uuid, group_secret_params) + .await?; + + Ok(groups_v2_api + .get_group(group_secret_params, authorization) + .await?) + } + + pub async fn get_attachment( + &self, + attachment_pointer: &AttachmentPointer, + ) -> Result, Error> { + let mut service = self.push_service()?; + let mut attachment_stream = service.get_attachment(attachment_pointer).await?; + + // We need the whole file for the crypto to check out + let mut ciphertext = Vec::new(); + let len = attachment_stream.read_to_end(&mut ciphertext).await?; + + trace!("downloaded encrypted attachment of {} bytes", len); + + let key: [u8; 64] = attachment_pointer.key().try_into()?; + decrypt_in_place(key, &mut ciphertext)?; + + Ok(ciphertext) + } + + /// Returns a clone of a cached push service. + /// + /// If no service is yet cached, it will create and cache one. + fn push_service(&self) -> Result { + self.cache.push_service.get(|| { + let signal_servers = match &self.state { + State::Registration { signal_servers, .. } + | State::Linking { signal_servers, .. } + | State::Confirmation { signal_servers, .. } + | State::Registered { signal_servers, .. } => signal_servers, + _ => return Err(Error::NotYetRegisteredError), + }; + + let credentials = self.credentials()?; + let service_configuration: ServiceConfiguration = (*signal_servers).into(); + + Ok(HyperPushService::new( + service_configuration, + credentials, + crate::USER_AGENT.to_string(), + )) + }) + } + + /// Creates a new message sender. + fn new_message_sender(&self) -> Result, Error> { + let (phone_number, uuid, device_id) = match &self.state { + State::Registered { + phone_number, + uuid, + device_id, + .. + } => (phone_number, uuid, device_id), + _ => return Err(Error::NotYetRegisteredError), + }; + + let local_addr = ServiceAddress { + uuid: Some(*uuid), + phonenumber: Some(phone_number.clone()), + relay: None, + }; + + Ok(MessageSender::new( + self.push_service()?, + self.new_service_cipher()?, + self.csprng.clone(), + self.config_store.clone(), + self.config_store.clone(), + local_addr, + device_id.unwrap_or(DEFAULT_DEVICE_ID), + )) + } + + /// Creates a new service cipher. + fn new_service_cipher(&self) -> Result, Error> { + let signal_servers = match &self.state { + State::Registered { signal_servers, .. } => signal_servers, + _ => return Err(Error::NotYetRegisteredError), + }; + + let service_configuration: ServiceConfiguration = (*signal_servers).into(); + let certificate_validator = service_configuration.credentials_validator()?; + let service_cipher = ServiceCipher::new( + self.config_store.clone(), + self.config_store.clone(), + self.config_store.clone(), + self.config_store.clone(), + self.csprng.clone(), + certificate_validator, + ); + + Ok(service_cipher) + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/.cargo-checksum.json b/net/gurk-rs/files/vendor/zkgroup/.cargo-checksum.json new file mode 100644 index 0000000..30e2271 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"cb7ca5fecaa564cae74864f55e2d46ebd7582a3e8d782533e545aaa016478745","benches/zkgroup_benchmarks.rs":"79c33b5b2b2da0e9d99f472002dad8af4505ef7db77c15c2065306d9538a8ca9","rustfmt.license-template":"6c0aa49b09640fe7bc67479f301f9f0303e97d57cbc1f8e2460caa4d7bb168a0","rustfmt.toml":"94c610400bd30d5afe9cc8b0a2ec887e2aa2429b90ec0c156562e23ad4046df9","scripts/format-code":"74a8db574cd2bd70eb5dda671749fddef7c90ae5a30595cccd9e316da68a0daa","src/api/auth/auth_credential.rs":"0fae28381c284ccd125e7a19e40f46a61bae61e3d0f7c74ab07c9dbe2290ff92","src/api/auth/auth_credential_presentation.rs":"cb9353ef068236574ba909faad0a614f3f09360505307f0d45892d632aaa62c7","src/api/auth/auth_credential_response.rs":"663ef06a9dbc5feceb276d87afd71083dbd4be17ba20fcbe5ab7d7bc1146eb77","src/api/auth/mod.rs":"2f14f5532dd059497adc313a2e044dc1a92797cd855a4e4b848e63262bef3f55","src/api/groups/group_params.rs":"7b9622724054d15d0cb78685b562465e07f24829ee09efebe4e639e7e93f7bee","src/api/groups/mod.rs":"2a86d9a4d1f9fedfbf1867d00a610f8650f3b0310d5de2a24aef5329063acb5a","src/api/groups/profile_key_ciphertext.rs":"538d99d186d8331e0b34659efb7ceb27bc43aebf24a48b4441e26f21402499be","src/api/groups/uuid_ciphertext.rs":"0630f14f49aa508700b3e7d781770ee60b0e34bdadc832f59ab693447e7705c3","src/api/mod.rs":"cddb1b813022ad6474157867b13328d0023fd5b940786da33d3bf4b9848bc1aa","src/api/profiles/mod.rs":"d7bc78ec76124dea7c6df90e391ae1544dbe7f10ba987c0338971b35e202e0bb","src/api/profiles/profile_key.rs":"d2d2f31db60fc981b25b9da87076f1cc3473cc9136501f2e8384dd3151375280","src/api/profiles/profile_key_commitment.rs":"a4760d56a536d31a64316b566e283fe2fc61977976c71fa0ae4b869d08d1044c","src/api/profiles/profile_key_credential.rs":"15a2884bdbe8023e61046a1a16a4f386254bb4e951d7bede2c052f1eeb4928b4","src/api/profiles/profile_key_credential_presentation.rs":"5523f68a175e4ddf5a21af176c8856ea3e6c6d64df5b4afbb5912aa7c651a7a3","src/api/profiles/profile_key_credential_request.rs":"425ef24c34992347f1870f132439d5b2c1be103dfc5b4bffe2d137aa1bd74c9e","src/api/profiles/profile_key_credential_request_context.rs":"19183a6eff15e9b68340b848e4acf2ad2ef69689ec1906494781d495d1cc8f3e","src/api/profiles/profile_key_credential_response.rs":"adda434fe28f42d2102a9f9b8da2b55ff6ef70d84992702e696f19c5b3cdc012","src/api/profiles/profile_key_version.rs":"7368c1936660ecf82211e040725008c30107440c15dd28185ae0f37dc4d96f9e","src/api/server_params.rs":"5447b5c75a678ce45c010b1d2d74b0ca5e948ffcf0bcf70c79c76bc703c65e98","src/common/constants.rs":"2444cf6bdd893dc4dbde6a3e80c965c3533ae61e54e0ee8d15e2edf7d869d94b","src/common/errors.rs":"9c31438f75c6c147b1e4f66b3155faf9c45b6d9f8d68bc6cd3276519df3a29d7","src/common/mod.rs":"6ebf7405863030fe9bc7ef4a3de7308d5ab3110ea4bbc21465359f7ca049a788","src/common/sho.rs":"3b14b9810c85c2b07857054fa12dc00e401a3b308c50b245009302271451e6d1","src/common/simple_types.rs":"b33af57622f3e9a95978afc291365732ef001a8fedcb44b9da69c07fe8da6005","src/crypto/credentials.rs":"284a1c5c0fa3869a70033deb0247aebb990a5d1ed2348399253cd183d0fe388d","src/crypto/mod.rs":"858b765777f4c152d69c73359d3803d6c490d719efdc71957ceb8753dafbeaa4","src/crypto/profile_key_commitment.rs":"5cdc107bfd47824535c2ab3db1b1b1d46f80a80297ab03f30f5628df8a4acd69","src/crypto/profile_key_credential_request.rs":"2773d27af83dcfa277d1b538fab8fe6b833611bb0d7ec05dbf87958e005a3012","src/crypto/profile_key_encryption.rs":"48bf4d5b0ebfe3cf454ee66758a64e7247948bf40ee945e9233fe6a8a53f156e","src/crypto/profile_key_struct.rs":"3d00f44c3cbf6be84b5973d7fc660aac3560bf5a989b17d8c0daaf9564b6c2dc","src/crypto/proofs.rs":"b32a368481734112837a839cd545fe5026945de608457d3462f6cbb5b11814a9","src/crypto/signature.rs":"f58b7265ac6218cd1a0d65f57e6d4fcf6b3aa56edc84263dacaf1ed19ab9db02","src/crypto/uid_encryption.rs":"fe21c49e75f960bac6a587159635d6dfd4bfcb0b0519fd5c90c8992ac8ee35f9","src/crypto/uid_struct.rs":"6a0752e293455ea3b4a23f210ce0e154ae252cc1cd51b0a158b5ab828516c231","src/ffi/constants.rs":"67e4c083467ebcc68bcc8f49f000328e5a293ea340c385d8647267f6502ec8f4","src/ffi/ffiapi.rs":"8f8d8fee4c5968800982bd1a6b8a3e56a28f1a14f5e83970e84e59e187839ef6","src/ffi/ffiapijava.rs":"bd845088122df2f909cd29c95c656a0870349593e92a42c9f47b781dd110075d","src/ffi/mod.rs":"241eefb61cdfa635f697466bd822a3f6b504cc21b118a83cb6b80f1d08a0c516","src/ffi/simpleapi.rs":"7b87022a3186162f8e0b13f3f0f210240bbdebe7acc20368c74012de5b3c0466","src/lib.rs":"9d26663d4f4080059a63faac6da97e0e300b92b21bf9ce7e47ae7fa7e49e0fe8","tests/integration_tests.rs":"90ac9ac9cc9376a0dc7dcb05c2a2ef997bb58e5dde13fe2bbed0fea1e4c90cf8"},"package":null} \ No newline at end of file diff --git a/net/gurk-rs/files/vendor/zkgroup/Cargo.toml b/net/gurk-rs/files/vendor/zkgroup/Cargo.toml new file mode 100644 index 0000000..01f208d --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/Cargo.toml @@ -0,0 +1,53 @@ +# +# Copyright (C) 2020 Signal Messenger, LLC. +# All rights reserved. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +[package] +name = "zkgroup" +version = "0.7.3" +authors = ["Trevor Perrin "] +edition = "2018" +description = "A zero-knowledge group library" +license = "GPL-3.0-only" + +[lib] +name = "zkgroup" +crate-type = [ "staticlib", "cdylib", "rlib"] + +[dependencies] +bincode = "1.2.1" +serde = { version = "1.0.106", features = ["derive"] } +sha2 = "0.8.0" +jni = { version = "0.16.0", default-features = false } +hex = "0.4.0" +aead = "0.4.0" +aes-gcm-siv = "0.10.0" + +[dependencies.curve25519-dalek] +features = ["std", "serde", "alloc"] +version = "2.0.0" +git = "https://github.com/signalapp/curve25519-dalek.git" +branch = "lizard2" + +[dependencies.poksho] +git = "https://github.com/signalapp/poksho.git" +tag = "v0.7.0" + +[features] +default = ["u64_backend"] +u32_backend = ["curve25519-dalek/u32_backend"] +u64_backend = ["curve25519-dalek/u64_backend"] +simd_backend = ["curve25519-dalek/simd_backend"] +nightly = ["curve25519-dalek/nightly"] + +# Below is for benchmarking: + +[dev-dependencies] +criterion = "0.3.1" + +[[bench]] +name = "zkgroup_benchmarks" +harness = false diff --git a/net/gurk-rs/files/vendor/zkgroup/benches/zkgroup_benchmarks.rs b/net/gurk-rs/files/vendor/zkgroup/benches/zkgroup_benchmarks.rs new file mode 100644 index 0000000..26c7de6 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/benches/zkgroup_benchmarks.rs @@ -0,0 +1,219 @@ +use criterion::{criterion_group, criterion_main, Criterion}; + +extern crate zkgroup; + +fn benchmark_integration_auth(c: &mut Criterion) { + let server_secret_params = zkgroup::ServerSecretParams::generate(zkgroup::TEST_ARRAY_32); + let server_public_params = server_secret_params.get_public_params(); + + let master_key = zkgroup::groups::GroupMasterKey::new(zkgroup::TEST_ARRAY_32_1); + let group_secret_params = + zkgroup::groups::GroupSecretParams::derive_from_master_key(master_key); + let group_public_params = group_secret_params.get_public_params(); + + // Random UID and issueTime + let uid = zkgroup::TEST_ARRAY_16; + let redemption_time = 123456u32; + + // SERVER + // Issue credential + let randomness = zkgroup::TEST_ARRAY_32_2; + let auth_credential_response = + server_secret_params.issue_auth_credential(randomness, uid, redemption_time); + + c.bench_function("issue_auth_credential", |b| { + b.iter(|| server_secret_params.issue_auth_credential(randomness, uid, redemption_time)) + }); + + // CLIENT + let auth_credential = server_public_params + .receive_auth_credential(uid, redemption_time, &auth_credential_response) + .unwrap(); + + c.bench_function("receive_auth_credential", |b| { + b.iter(|| { + server_public_params + .receive_auth_credential(uid, redemption_time, &auth_credential_response) + .unwrap() + }) + }); + + // Create and decrypt user entry + let uuid_ciphertext = group_secret_params.encrypt_uuid(uid); + let plaintext = group_secret_params.decrypt_uuid(uuid_ciphertext).unwrap(); + assert!(plaintext == uid); + + // Create and receive presentation + let randomness = zkgroup::TEST_ARRAY_32_5; + + let presentation = server_public_params.create_auth_credential_presentation( + randomness, + group_secret_params, + auth_credential, + ); + + c.bench_function("create_auth_credential_presentation", |b| { + b.iter(|| { + server_public_params.create_auth_credential_presentation( + randomness, + group_secret_params, + auth_credential, + ) + }) + }); + + let _presentation_bytes = &bincode::serialize(&presentation).unwrap(); + + //for b in presentation_bytes.iter() { + // print!("0x{:02x}, ", b); + //} + //assert!(AUTH_CREDENTIAL_PRESENTATION_RESULT[..] == presentation_bytes[..]); + + c.bench_function("verify_auth_credential_presentation", |b| { + b.iter(|| { + server_secret_params + .verify_auth_credential_presentation(group_public_params, &presentation) + .unwrap(); + }) + }); +} + +// Copied and modified from tests/integration_tests.rs +pub fn benchmark_integration_profile(c: &mut Criterion) { + // Random UID and issueTime + let _uid = zkgroup::TEST_ARRAY_16; + + // SERVER + let server_secret_params = zkgroup::ServerSecretParams::generate(zkgroup::TEST_ARRAY_32); + let server_public_params = server_secret_params.get_public_params(); + + // CLIENT + let master_key = zkgroup::groups::GroupMasterKey::new(zkgroup::TEST_ARRAY_32_1); + let group_secret_params = + zkgroup::groups::GroupSecretParams::derive_from_master_key(master_key); + let group_public_params = group_secret_params.get_public_params(); + + let uid = zkgroup::TEST_ARRAY_16; + let profile_key = + zkgroup::profiles::ProfileKey::create(zkgroup::common::constants::TEST_ARRAY_32_1); + let profile_key_commitment = profile_key.get_commitment(uid); + + // Create context and request + let randomness = zkgroup::TEST_ARRAY_32_3; + + let context = server_public_params.create_profile_key_credential_request_context( + randomness, + uid, + profile_key, + ); + + c.bench_function("create_profile_key_credential_request_context", |b| { + b.iter(|| { + server_public_params.create_profile_key_credential_request_context( + randomness, + uid, + profile_key, + ) + }) + }); + + let request = context.get_request(); + + // SERVER + + let randomness = zkgroup::TEST_ARRAY_32_4; + let response = server_secret_params + .issue_profile_key_credential(randomness, &request, uid, profile_key_commitment) + .unwrap(); + + c.bench_function("issue_profile_key_credential", |b| { + b.iter(|| { + server_secret_params + .issue_profile_key_credential(randomness, &request, uid, profile_key_commitment) + .unwrap() + }) + }); + + // CLIENT + // Gets stored profile credential + let profile_key_credential = server_public_params + .receive_profile_key_credential(&context, &response) + .unwrap(); + + c.bench_function("receive_profile_key_credential", |b| { + b.iter(|| { + server_public_params + .receive_profile_key_credential(&context, &response) + .unwrap() + }) + }); + + // Create encrypted UID and profile key + let uuid_ciphertext = group_secret_params.encrypt_uuid(uid); + + c.bench_function("encrypt_uuid", |b| { + b.iter(|| group_secret_params.encrypt_uuid(uid)) + }); + + let plaintext = group_secret_params.decrypt_uuid(uuid_ciphertext).unwrap(); + + c.bench_function("decrypt_uuid", |b| { + b.iter(|| group_secret_params.decrypt_uuid(uuid_ciphertext)) + }); + + assert!(plaintext == uid); + + let profile_key_ciphertext = group_secret_params.encrypt_profile_key(profile_key, uid); + + c.bench_function("encrypt_profile_key", |b| { + b.iter(|| group_secret_params.encrypt_profile_key(profile_key, uid)) + }); + + let decrypted_profile_key = group_secret_params + .decrypt_profile_key(profile_key_ciphertext, uid) + .unwrap(); + + c.bench_function("decrypt_profile_key", |b| { + b.iter(|| group_secret_params.decrypt_profile_key(profile_key_ciphertext, uid)) + }); + + assert!(decrypted_profile_key.get_bytes() == profile_key.get_bytes()); + + // Create presentation + let randomness = zkgroup::TEST_ARRAY_32_5; + + let presentation = server_public_params.create_profile_key_credential_presentation( + randomness, + group_secret_params, + profile_key_credential, + ); + + c.bench_function("create_profile_key_credential_presentation", |b| { + b.iter(|| { + server_public_params.create_profile_key_credential_presentation( + randomness, + group_secret_params, + profile_key_credential, + ) + }) + }); + + // SERVER + server_secret_params + .verify_profile_key_credential_presentation(group_public_params, &presentation) + .unwrap(); + + c.bench_function("verify_profile_key_credential_presentation", |b| { + b.iter(|| { + server_secret_params + .verify_profile_key_credential_presentation(group_public_params, &presentation) + }) + }); +} + +criterion_group!( + benches, + benchmark_integration_profile, + benchmark_integration_auth +); +criterion_main!(benches); diff --git a/net/gurk-rs/files/vendor/zkgroup/rustfmt.license-template b/net/gurk-rs/files/vendor/zkgroup/rustfmt.license-template new file mode 100644 index 0000000..ae7596e --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/rustfmt.license-template @@ -0,0 +1,6 @@ +// +// Copyright (C) {\d+} Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// diff --git a/net/gurk-rs/files/vendor/zkgroup/rustfmt.toml b/net/gurk-rs/files/vendor/zkgroup/rustfmt.toml new file mode 100644 index 0000000..e34f0d5 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/rustfmt.toml @@ -0,0 +1,12 @@ +# +# Copyright (C) 2020 Signal Messenger, LLC. +# All rights reserved. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +unstable_features = true +license_template_path = "rustfmt.license-template" + +ignore = [ +] diff --git a/net/gurk-rs/files/vendor/zkgroup/scripts/format-code b/net/gurk-rs/files/vendor/zkgroup/scripts/format-code new file mode 100755 index 0000000..18bcc7c --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/scripts/format-code @@ -0,0 +1,7 @@ +#!/bin/sh + +# To run, install the nightly toolchain: +# $ rustup toolchain install nightly + +cargo +nightly fmt "$@" +cargo +nightly clippy diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/auth/auth_credential.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/auth/auth_credential.rs new file mode 100644 index 0000000..04d6de1 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/auth/auth_credential.rs @@ -0,0 +1,22 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::api; +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Serialize, Deserialize)] +pub struct AuthCredential { + pub(crate) reserved: ReservedBytes, + pub(crate) credential: crypto::credentials::AuthCredential, + pub(crate) server_public_params: api::ServerPublicParams, + pub(crate) uid: crypto::uid_struct::UidStruct, + pub(crate) redemption_time: RedemptionTime, +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/auth/auth_credential_presentation.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/auth/auth_credential_presentation.rs new file mode 100644 index 0000000..2b79968 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/auth/auth_credential_presentation.rs @@ -0,0 +1,34 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::api; +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct AuthCredentialPresentation { + pub(crate) reserved: ReservedBytes, + pub(crate) proof: crypto::proofs::AuthCredentialPresentationProof, + pub(crate) ciphertext: crypto::uid_encryption::Ciphertext, + pub(crate) redemption_time: RedemptionTime, +} + +impl AuthCredentialPresentation { + pub fn get_uuid_ciphertext(&self) -> api::groups::UuidCiphertext { + api::groups::UuidCiphertext { + reserved: Default::default(), + ciphertext: self.ciphertext, + } + } + + pub fn get_redemption_time(&self) -> RedemptionTime { + self.redemption_time + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/auth/auth_credential_response.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/auth/auth_credential_response.rs new file mode 100644 index 0000000..70ba84e --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/auth/auth_credential_response.rs @@ -0,0 +1,19 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct AuthCredentialResponse { + pub(crate) reserved: ReservedBytes, + pub(crate) credential: crypto::credentials::AuthCredential, + pub(crate) proof: crypto::proofs::AuthCredentialIssuanceProof, +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/auth/mod.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/auth/mod.rs new file mode 100644 index 0000000..8ed6e64 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/auth/mod.rs @@ -0,0 +1,14 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +pub mod auth_credential; +pub mod auth_credential_presentation; +pub mod auth_credential_response; + +pub use auth_credential::AuthCredential; +pub use auth_credential_presentation::AuthCredentialPresentation; +pub use auth_credential_response::AuthCredentialResponse; diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/groups/group_params.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/groups/group_params.rs new file mode 100644 index 0000000..c0cd2e9 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/groups/group_params.rs @@ -0,0 +1,318 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::api; +use crate::common::constants::*; +use crate::common::errors::*; +use crate::common::sho::*; +use crate::common::simple_types::*; +use crate::crypto; +use aead::{generic_array::GenericArray, Aead, NewAead}; +use aes_gcm_siv::Aes256GcmSiv; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Serialize, Deserialize, Default)] +pub struct GroupMasterKey { + pub(crate) bytes: [u8; GROUP_MASTER_KEY_LEN], +} + +#[derive(Copy, Clone, Serialize, Deserialize)] +pub struct GroupSecretParams { + reserved: ReservedBytes, + master_key: GroupMasterKey, + group_id: GroupIdentifierBytes, + blob_key: AesKeyBytes, + pub(crate) uid_enc_key_pair: crypto::uid_encryption::KeyPair, + pub(crate) profile_key_enc_key_pair: crypto::profile_key_encryption::KeyPair, +} + +#[derive(Copy, Clone, Serialize, Deserialize)] +pub struct GroupPublicParams { + reserved: ReservedBytes, + group_id: GroupIdentifierBytes, + pub(crate) uid_enc_public_key: crypto::uid_encryption::PublicKey, + pub(crate) profile_key_enc_public_key: crypto::profile_key_encryption::PublicKey, +} + +impl GroupMasterKey { + pub fn new(bytes: [u8; GROUP_MASTER_KEY_LEN]) -> Self { + GroupMasterKey { bytes } + } +} + +impl GroupSecretParams { + pub fn generate(randomness: RandomnessBytes) -> Self { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Random_GroupSecretParams_Generate", + &randomness, + ); + let mut master_key: GroupMasterKey = Default::default(); + master_key + .bytes + .copy_from_slice(&sho.squeeze(GROUP_MASTER_KEY_LEN)[..]); + GroupSecretParams::derive_from_master_key(master_key) + } + + pub fn derive_from_master_key(master_key: GroupMasterKey) -> Self { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_GroupMasterKey_GroupSecretParams_DeriveFromMasterKey", + &master_key.bytes, + ); + let mut group_id: GroupIdentifierBytes = Default::default(); + let mut blob_key: AesKeyBytes = Default::default(); + group_id.copy_from_slice(&sho.squeeze(GROUP_IDENTIFIER_LEN)[..]); + blob_key.copy_from_slice(&sho.squeeze(AES_KEY_LEN)[..]); + let uid_enc_key_pair = crypto::uid_encryption::KeyPair::derive_from(&mut sho); + let profile_key_enc_key_pair = + crypto::profile_key_encryption::KeyPair::derive_from(&mut sho); + + Self { + reserved: Default::default(), + master_key, + group_id, + blob_key, + uid_enc_key_pair, + profile_key_enc_key_pair, + } + } + + pub fn get_master_key(&self) -> GroupMasterKey { + self.master_key + } + + pub fn get_group_identifier(&self) -> GroupIdentifierBytes { + self.group_id + } + + pub fn get_public_params(&self) -> GroupPublicParams { + GroupPublicParams { + reserved: Default::default(), + uid_enc_public_key: self.uid_enc_key_pair.get_public_key(), + profile_key_enc_public_key: self.profile_key_enc_key_pair.get_public_key(), + group_id: self.group_id, + } + } + + pub fn encrypt_uuid(&self, uid_bytes: UidBytes) -> api::groups::UuidCiphertext { + let uid = crypto::uid_struct::UidStruct::new(uid_bytes); + self.encrypt_uid_struct(uid) + } + + pub fn encrypt_uid_struct( + &self, + uid: crypto::uid_struct::UidStruct, + ) -> api::groups::UuidCiphertext { + let ciphertext = self.uid_enc_key_pair.encrypt(uid); + api::groups::UuidCiphertext { + reserved: Default::default(), + ciphertext, + } + } + + pub fn decrypt_uuid( + &self, + ciphertext: api::groups::UuidCiphertext, + ) -> Result { + let uid = self.uid_enc_key_pair.decrypt(ciphertext.ciphertext)?; + Ok(uid.to_bytes()) + } + + pub fn encrypt_profile_key( + &self, + profile_key: api::profiles::ProfileKey, + uid_bytes: UidBytes, + ) -> api::groups::ProfileKeyCiphertext { + self.encrypt_profile_key_bytes(profile_key.bytes, uid_bytes) + } + + pub fn encrypt_profile_key_bytes( + &self, + profile_key_bytes: ProfileKeyBytes, + uid_bytes: UidBytes, + ) -> api::groups::ProfileKeyCiphertext { + let profile_key = + crypto::profile_key_struct::ProfileKeyStruct::new(profile_key_bytes, uid_bytes); + let ciphertext = self.profile_key_enc_key_pair.encrypt(profile_key); + api::groups::ProfileKeyCiphertext { + reserved: Default::default(), + ciphertext, + } + } + + pub fn decrypt_profile_key( + &self, + ciphertext: api::groups::ProfileKeyCiphertext, + uid_bytes: UidBytes, + ) -> Result { + let profile_key_struct = self + .profile_key_enc_key_pair + .decrypt(ciphertext.ciphertext, uid_bytes)?; + Ok(api::profiles::ProfileKey { + bytes: profile_key_struct.bytes, + }) + } + + pub fn encrypt_blob( + &self, + randomness: RandomnessBytes, + plaintext: &[u8], + ) -> Result, ZkGroupError> { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Random_GroupSecretParams_EncryptBlob", + &randomness, + ); + let nonce_vec = sho.squeeze(AESGCM_NONCE_LEN); + match self.encrypt_blob_aesgcmsiv(&self.blob_key, &nonce_vec[..], plaintext) { + Ok(mut ciphertext_vec) => { + ciphertext_vec.extend(nonce_vec); + ciphertext_vec.extend(&[0u8]); // reserved byte + Ok(ciphertext_vec) + } + Err(e) => Err(e), + } + } + + pub fn decrypt_blob(self, ciphertext: &[u8]) -> Result, ZkGroupError> { + if ciphertext.len() < AESGCM_NONCE_LEN + 1 { + // AESGCM_NONCE_LEN = 12 bytes for IV + return Err(ZkGroupError::DecryptionFailure); + } + let unreserved_len = ciphertext.len() - 1; + let nonce = &ciphertext[unreserved_len - AESGCM_NONCE_LEN..unreserved_len]; + let ciphertext = &ciphertext[..unreserved_len - AESGCM_NONCE_LEN]; + self.decrypt_blob_aesgcmsiv(&self.blob_key, nonce, ciphertext) + } + + fn encrypt_blob_aesgcmsiv( + &self, + key: &[u8], + nonce: &[u8], + plaintext: &[u8], + ) -> Result, ZkGroupError> { + let key = GenericArray::from_slice(key); + let aead_cipher = Aes256GcmSiv::new(&*key); + let nonce = GenericArray::from_slice(nonce); + match aead_cipher.encrypt(nonce, plaintext) { + Ok(ciphertext_vec) => Ok(ciphertext_vec), + Err(_) => Err(ZkGroupError::BadArgs), + } + } + + fn decrypt_blob_aesgcmsiv( + self, + key: &[u8], + nonce: &[u8], + ciphertext: &[u8], + ) -> Result, ZkGroupError> { + if ciphertext.len() < AESGCM_TAG_LEN { + // AESGCM_TAG_LEN = 16 bytes for tag + return Err(ZkGroupError::DecryptionFailure); + } + let key = GenericArray::from_slice(key); + let aead_cipher = Aes256GcmSiv::new(&*key); + let nonce = GenericArray::from_slice(nonce); + match aead_cipher.decrypt(nonce, ciphertext) { + Ok(plaintext_vec) => Ok(plaintext_vec), + Err(_) => Err(ZkGroupError::DecryptionFailure), + } + } +} + +impl GroupPublicParams { + pub fn get_group_identifier(&self) -> GroupIdentifierBytes { + self.group_id + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_aesgcmsiv_vec1() { + // https://tools.ietf.org/html/rfc8452#appendix-C + + let group_secret_params = GroupSecretParams::generate([0u8; RANDOMNESS_LEN]); + + let plaintext_vec = vec![ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ]; + + let key_vec = vec![ + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ]; + + let nonce_vec = vec![ + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + + let ciphertext_vec = vec![ + 0x4a, 0x6a, 0x9d, 0xb4, 0xc8, 0xc6, 0x54, 0x92, 0x01, 0xb9, 0xed, 0xb5, 0x30, 0x06, + 0xcb, 0xa8, 0x21, 0xec, 0x9c, 0xf8, 0x50, 0x94, 0x8a, 0x7c, 0x86, 0xc6, 0x8a, 0xc7, + 0x53, 0x9d, 0x02, 0x7f, 0xe8, 0x19, 0xe6, 0x3a, 0xbc, 0xd0, 0x20, 0xb0, 0x06, 0xa9, + 0x76, 0x39, 0x76, 0x32, 0xeb, 0x5d, + ]; + + let calc_ciphertext = group_secret_params + .encrypt_blob_aesgcmsiv(&key_vec, &nonce_vec, &plaintext_vec) + .unwrap(); + + assert!(calc_ciphertext[..ciphertext_vec.len()] == ciphertext_vec[..]); + + let calc_plaintext = group_secret_params + .decrypt_blob_aesgcmsiv(&key_vec, &nonce_vec, &calc_ciphertext) + .unwrap(); + assert!(calc_plaintext[..] == plaintext_vec[..]); + } + + #[test] + fn test_aesgcmsiv_vec2() { + // https://tools.ietf.org/html/rfc8452#appendix-C + + let group_secret_params = GroupSecretParams::generate([0u8; RANDOMNESS_LEN]); + + let plaintext_vec = vec![ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4d, 0xb9, 0x23, 0xdc, 0x79, 0x3e, 0xe6, 0x49, 0x7c, 0x76, 0xdc, 0xc0, + 0x3a, 0x98, 0xe1, 0x08, + ]; + + let key_vec = vec![ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ]; + + let nonce_vec = vec![ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + + let ciphertext_vec = vec![ + 0xf3, 0xf8, 0x0f, 0x2c, 0xf0, 0xcb, 0x2d, 0xd9, 0xc5, 0x98, 0x4f, 0xcd, 0xa9, 0x08, + 0x45, 0x6c, 0xc5, 0x37, 0x70, 0x3b, 0x5b, 0xa7, 0x03, 0x24, 0xa6, 0x79, 0x3a, 0x7b, + 0xf2, 0x18, 0xd3, 0xea, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + + let calc_ciphertext = group_secret_params + .encrypt_blob_aesgcmsiv(&key_vec, &nonce_vec, &plaintext_vec) + .unwrap(); + + assert!(calc_ciphertext[..ciphertext_vec.len()] == ciphertext_vec[..]); + + let calc_plaintext = group_secret_params + .decrypt_blob_aesgcmsiv(&key_vec, &nonce_vec, &calc_ciphertext) + .unwrap(); + assert!(calc_plaintext[..] == plaintext_vec[..]); + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/groups/mod.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/groups/mod.rs new file mode 100644 index 0000000..473116d --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/groups/mod.rs @@ -0,0 +1,16 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +pub mod group_params; +pub mod profile_key_ciphertext; +pub mod uuid_ciphertext; + +pub use group_params::GroupMasterKey; +pub use group_params::GroupPublicParams; +pub use group_params::GroupSecretParams; +pub use profile_key_ciphertext::ProfileKeyCiphertext; +pub use uuid_ciphertext::UuidCiphertext; diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/groups/profile_key_ciphertext.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/groups/profile_key_ciphertext.rs new file mode 100644 index 0000000..44128b7 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/groups/profile_key_ciphertext.rs @@ -0,0 +1,18 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Default, Serialize, Deserialize, PartialEq)] +pub struct ProfileKeyCiphertext { + pub(crate) reserved: ReservedBytes, + pub(crate) ciphertext: crypto::profile_key_encryption::Ciphertext, +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/groups/uuid_ciphertext.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/groups/uuid_ciphertext.rs new file mode 100644 index 0000000..f04c93c --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/groups/uuid_ciphertext.rs @@ -0,0 +1,18 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Default, Serialize, Deserialize, PartialEq)] +pub struct UuidCiphertext { + pub(crate) reserved: ReservedBytes, + pub(crate) ciphertext: crypto::uid_encryption::Ciphertext, +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/mod.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/mod.rs new file mode 100644 index 0000000..24f71f5 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/mod.rs @@ -0,0 +1,15 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +pub mod auth; +pub mod groups; +pub mod profiles; + +pub mod server_params; + +pub use server_params::ServerPublicParams; +pub use server_params::ServerSecretParams; diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/mod.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/mod.rs new file mode 100644 index 0000000..36137dd --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/mod.rs @@ -0,0 +1,24 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +pub mod profile_key; +pub mod profile_key_commitment; +pub mod profile_key_credential; +pub mod profile_key_credential_presentation; +pub mod profile_key_credential_request; +pub mod profile_key_credential_request_context; +pub mod profile_key_credential_response; +pub mod profile_key_version; + +pub use profile_key::ProfileKey; +pub use profile_key_commitment::ProfileKeyCommitment; +pub use profile_key_credential::ProfileKeyCredential; +pub use profile_key_credential_presentation::ProfileKeyCredentialPresentation; +pub use profile_key_credential_request::ProfileKeyCredentialRequest; +pub use profile_key_credential_request_context::ProfileKeyCredentialRequestContext; +pub use profile_key_credential_response::ProfileKeyCredentialResponse; +pub use profile_key_version::ProfileKeyVersion; diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key.rs new file mode 100644 index 0000000..f5b82c7 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key.rs @@ -0,0 +1,68 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::api; +use crate::common::constants::*; +use crate::common::sho::*; +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Serialize, Deserialize)] +pub struct ProfileKey { + pub bytes: ProfileKeyBytes, +} + +impl ProfileKey { + pub fn generate(randomness: RandomnessBytes) -> Self { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Random_ProfileKey_Generate", + &randomness, + ); + let mut bytes = [0u8; PROFILE_KEY_LEN]; + bytes.copy_from_slice(&sho.squeeze(PROFILE_KEY_LEN)[..]); + Self { bytes } + } + + pub fn create(bytes: ProfileKeyBytes) -> Self { + Self { bytes } + } + + pub fn get_bytes(&self) -> ProfileKeyBytes { + self.bytes + } + + pub fn get_commitment(&self, uid_bytes: UidBytes) -> api::profiles::ProfileKeyCommitment { + let profile_key = crypto::profile_key_struct::ProfileKeyStruct::new(self.bytes, uid_bytes); + let commitment = + crypto::profile_key_commitment::CommitmentWithSecretNonce::new(profile_key, uid_bytes); + api::profiles::ProfileKeyCommitment { + reserved: Default::default(), + commitment: commitment.get_profile_key_commitment(), + } + } + + pub fn get_profile_key_version(&self, uid_bytes: UidBytes) -> api::profiles::ProfileKeyVersion { + let mut combined_array = [0u8; PROFILE_KEY_LEN + UUID_LEN]; + combined_array[..PROFILE_KEY_LEN].copy_from_slice(&self.bytes); + combined_array[PROFILE_KEY_LEN..].copy_from_slice(&uid_bytes); + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_ProfileKeyAndUid_ProfileKey_GetProfileKeyVersion", + &combined_array, + ); + + let pkv_hex_string = hex::encode(&sho.squeeze(PROFILE_KEY_VERSION_LEN)[..]); + let mut pkv_hex_array: [u8; PROFILE_KEY_VERSION_ENCODED_LEN] = + [0u8; PROFILE_KEY_VERSION_ENCODED_LEN]; + pkv_hex_array.copy_from_slice(pkv_hex_string.as_bytes()); + api::profiles::ProfileKeyVersion { + bytes: pkv_hex_array, + } + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_commitment.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_commitment.rs new file mode 100644 index 0000000..7eea1cf --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_commitment.rs @@ -0,0 +1,18 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Serialize, Deserialize)] +pub struct ProfileKeyCommitment { + pub(crate) reserved: ReservedBytes, + pub(crate) commitment: crypto::profile_key_commitment::Commitment, +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential.rs new file mode 100644 index 0000000..cb5921b --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential.rs @@ -0,0 +1,20 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Serialize, Deserialize)] +pub struct ProfileKeyCredential { + pub(crate) reserved: ReservedBytes, + pub(crate) credential: crypto::credentials::ProfileKeyCredential, + pub(crate) uid_bytes: UidBytes, + pub(crate) profile_key_bytes: ProfileKeyBytes, +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_presentation.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_presentation.rs new file mode 100644 index 0000000..1122dc2 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_presentation.rs @@ -0,0 +1,37 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::api; +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct ProfileKeyCredentialPresentation { + pub(crate) reserved: ReservedBytes, + pub(crate) proof: crypto::proofs::ProfileKeyCredentialPresentationProof, + pub(crate) uid_enc_ciphertext: crypto::uid_encryption::Ciphertext, + pub(crate) profile_key_enc_ciphertext: crypto::profile_key_encryption::Ciphertext, +} + +impl ProfileKeyCredentialPresentation { + pub fn get_uuid_ciphertext(&self) -> api::groups::UuidCiphertext { + api::groups::UuidCiphertext { + reserved: Default::default(), + ciphertext: self.uid_enc_ciphertext, + } + } + + pub fn get_profile_key_ciphertext(&self) -> api::groups::ProfileKeyCiphertext { + api::groups::ProfileKeyCiphertext { + reserved: Default::default(), + ciphertext: self.profile_key_enc_ciphertext, + } + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_request.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_request.rs new file mode 100644 index 0000000..a52ecff --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_request.rs @@ -0,0 +1,20 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct ProfileKeyCredentialRequest { + pub(crate) reserved: ReservedBytes, + pub(crate) public_key: crypto::profile_key_credential_request::PublicKey, + pub(crate) ciphertext: crypto::profile_key_credential_request::Ciphertext, + pub(crate) proof: crypto::proofs::ProfileKeyCredentialRequestProof, +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_request_context.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_request_context.rs new file mode 100644 index 0000000..8c3d659 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_request_context.rs @@ -0,0 +1,37 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::api; +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct ProfileKeyCredentialRequestContext { + pub(crate) reserved: ReservedBytes, + pub(crate) uid_bytes: UidBytes, + pub(crate) profile_key_bytes: ProfileKeyBytes, + pub(crate) key_pair: crypto::profile_key_credential_request::KeyPair, + pub(crate) ciphertext_with_secret_nonce: + crypto::profile_key_credential_request::CiphertextWithSecretNonce, + pub(crate) proof: crypto::proofs::ProfileKeyCredentialRequestProof, +} + +impl ProfileKeyCredentialRequestContext { + pub fn get_request(&self) -> api::profiles::ProfileKeyCredentialRequest { + let ciphertext = self.ciphertext_with_secret_nonce.get_ciphertext(); + let public_key = self.key_pair.get_public_key(); + api::profiles::ProfileKeyCredentialRequest { + reserved: Default::default(), + public_key, + ciphertext, + proof: self.proof.clone(), + } + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_response.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_response.rs new file mode 100644 index 0000000..9e7a080 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_credential_response.rs @@ -0,0 +1,19 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct ProfileKeyCredentialResponse { + pub(crate) reserved: ReservedBytes, + pub(crate) blinded_credential: crypto::credentials::BlindedProfileKeyCredential, + pub(crate) proof: crypto::proofs::ProfileKeyCredentialIssuanceProof, +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_version.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_version.rs new file mode 100644 index 0000000..9b5fc2f --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/profiles/profile_key_version.rs @@ -0,0 +1,30 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::simple_types::*; +use serde::ser::SerializeTuple; +use serde::{Serialize, Serializer}; + +#[derive(Copy, Clone)] +pub struct ProfileKeyVersion { + pub(crate) bytes: ProfileKeyVersionEncodedBytes, +} + +impl Serialize for ProfileKeyVersion { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_tuple(self.bytes.len()).unwrap(); + for b in self.bytes.iter() { + seq.serialize_element(b)?; + } + seq.end() + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/api/server_params.rs b/net/gurk-rs/files/vendor/zkgroup/src/api/server_params.rs new file mode 100644 index 0000000..047aca6 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/api/server_params.rs @@ -0,0 +1,351 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::api; +use crate::common::constants::*; +use crate::common::errors::*; +use crate::common::sho::*; +use crate::common::simple_types::*; +use crate::crypto; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Serialize, Deserialize)] +pub struct ServerSecretParams { + pub(crate) reserved: ReservedBytes, + pub(crate) auth_credentials_key_pair: crypto::credentials::KeyPair, + pub(crate) profile_key_credentials_key_pair: crypto::credentials::KeyPair, + sig_key_pair: crypto::signature::KeyPair, +} + +#[derive(Copy, Clone, Serialize, Deserialize)] +pub struct ServerPublicParams { + pub(crate) reserved: ReservedBytes, + pub(crate) auth_credentials_public_key: crypto::credentials::PublicKey, + pub(crate) profile_key_credentials_public_key: crypto::credentials::PublicKey, + sig_public_key: crypto::signature::PublicKey, +} + +impl ServerSecretParams { + pub fn generate(randomness: RandomnessBytes) -> Self { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Random_ServerSecretParams_Generate", + &randomness, + ); + + let auth_credentials_key_pair = + crypto::credentials::KeyPair::generate(&mut sho, NUM_AUTH_CRED_ATTRIBUTES); + let profile_key_credentials_key_pair = + crypto::credentials::KeyPair::generate(&mut sho, NUM_PROFILE_KEY_CRED_ATTRIBUTES); + let sig_key_pair = crypto::signature::KeyPair::generate(&mut sho); + + Self { + reserved: Default::default(), + auth_credentials_key_pair, + profile_key_credentials_key_pair, + sig_key_pair, + } + } + + pub fn get_public_params(&self) -> ServerPublicParams { + ServerPublicParams { + reserved: Default::default(), + auth_credentials_public_key: self.auth_credentials_key_pair.get_public_key(), + profile_key_credentials_public_key: self + .profile_key_credentials_key_pair + .get_public_key(), + sig_public_key: self.sig_key_pair.get_public_key(), + } + } + + pub fn sign( + &self, + randomness: RandomnessBytes, + message: &[u8], + ) -> Result { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Random_ServerSecretParams_Sign", + &randomness, + ); + self.sig_key_pair.sign(message, &mut sho) + } + + pub fn issue_auth_credential( + &self, + randomness: RandomnessBytes, + uid_bytes: UidBytes, + redemption_time: RedemptionTime, + ) -> api::auth::AuthCredentialResponse { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Random_ServerSecretParams_IssueAuthCredential", + &randomness, + ); + + let uid = crypto::uid_struct::UidStruct::new(uid_bytes); + let credential = + self.auth_credentials_key_pair + .create_auth_credential(uid, redemption_time, &mut sho); + let proof = crypto::proofs::AuthCredentialIssuanceProof::new( + self.auth_credentials_key_pair, + credential, + uid, + redemption_time, + &mut sho, + ); + api::auth::AuthCredentialResponse { + reserved: Default::default(), + credential, + proof, + } + } + + pub fn verify_auth_credential_presentation( + &self, + group_public_params: api::groups::GroupPublicParams, + presentation: &api::auth::AuthCredentialPresentation, + ) -> Result<(), ZkGroupError> { + presentation.proof.verify( + self.auth_credentials_key_pair, + group_public_params.uid_enc_public_key, + presentation.ciphertext, + presentation.redemption_time, + ) + } + + pub fn verify_profile_key_credential_presentation( + &self, + group_public_params: api::groups::GroupPublicParams, + presentation: &api::profiles::ProfileKeyCredentialPresentation, + ) -> Result<(), ZkGroupError> { + let credentials_key_pair = self.profile_key_credentials_key_pair; + let uid_enc_public_key = group_public_params.uid_enc_public_key; + let profile_key_enc_public_key = group_public_params.profile_key_enc_public_key; + + presentation.proof.verify( + credentials_key_pair, + presentation.uid_enc_ciphertext, + uid_enc_public_key, + presentation.profile_key_enc_ciphertext, + profile_key_enc_public_key, + ) + } + + pub fn issue_profile_key_credential( + &self, + randomness: RandomnessBytes, + request: &api::profiles::ProfileKeyCredentialRequest, + uid_bytes: UidBytes, + commitment: api::profiles::ProfileKeyCommitment, + ) -> Result { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Random_ServerSecretParams_IssueProfileKeyCredential", + &randomness, + ); + + request.proof.verify( + request.public_key, + request.ciphertext, + commitment.commitment, + )?; + + let uid = crypto::uid_struct::UidStruct::new(uid_bytes); + let blinded_credential_with_secret_nonce = self + .profile_key_credentials_key_pair + .create_blinded_profile_key_credential( + uid, + request.public_key, + request.ciphertext, + &mut sho, + ); + + let proof = crypto::proofs::ProfileKeyCredentialIssuanceProof::new( + self.profile_key_credentials_key_pair, + request.public_key, + request.ciphertext, + blinded_credential_with_secret_nonce, + uid, + &mut sho, + ); + + Ok(api::profiles::ProfileKeyCredentialResponse { + reserved: Default::default(), + blinded_credential: blinded_credential_with_secret_nonce + .get_blinded_profile_key_credential(), + proof, + }) + } +} + +impl ServerPublicParams { + pub fn verify_signature( + &self, + message: &[u8], + signature: NotarySignatureBytes, + ) -> Result<(), ZkGroupError> { + self.sig_public_key.verify(message, signature) + } + + pub fn receive_auth_credential( + &self, + uid_bytes: UidBytes, + redemption_time: RedemptionTime, + response: &api::auth::AuthCredentialResponse, + ) -> Result { + let uid = crypto::uid_struct::UidStruct::new(uid_bytes); + response.proof.verify( + self.auth_credentials_public_key, + response.credential, + uid, + redemption_time, + )?; + + Ok(api::auth::AuthCredential { + reserved: Default::default(), + credential: response.credential, + server_public_params: *self, + uid, + redemption_time, + }) + } + + pub fn create_auth_credential_presentation( + &self, + randomness: RandomnessBytes, + group_secret_params: api::groups::GroupSecretParams, + auth_credential: api::auth::AuthCredential, + ) -> api::auth::AuthCredentialPresentation { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Random_ServerPublicParams_CreateAuthCredentialPresentation", + &randomness, + ); + + let uuid_ciphertext = group_secret_params.encrypt_uid_struct(auth_credential.uid); + + let proof = crypto::proofs::AuthCredentialPresentationProof::new( + self.auth_credentials_public_key, + group_secret_params.uid_enc_key_pair, + auth_credential.credential, + auth_credential.uid, + uuid_ciphertext.ciphertext, + auth_credential.redemption_time, + &mut sho, + ); + + api::auth::AuthCredentialPresentation { + reserved: Default::default(), + proof, + ciphertext: uuid_ciphertext.ciphertext, + redemption_time: auth_credential.redemption_time, + } + } + + pub fn create_profile_key_credential_request_context( + &self, + randomness: RandomnessBytes, + uid_bytes: UidBytes, + profile_key: api::profiles::ProfileKey, + ) -> api::profiles::ProfileKeyCredentialRequestContext { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Random_ServerPublicParams_CreateProfileKeyCredentialRequestContext", + &randomness, + ); + let profile_key_struct = + crypto::profile_key_struct::ProfileKeyStruct::new(profile_key.bytes, uid_bytes); + + let commitment_with_secret_nonce = + crypto::profile_key_commitment::CommitmentWithSecretNonce::new( + profile_key_struct, + uid_bytes, + ); + + let key_pair = crypto::profile_key_credential_request::KeyPair::generate(&mut sho); + let ciphertext_with_secret_nonce = key_pair.encrypt(profile_key_struct, &mut sho); + + let proof = crypto::proofs::ProfileKeyCredentialRequestProof::new( + key_pair, + ciphertext_with_secret_nonce, + commitment_with_secret_nonce, + &mut sho, + ); + + api::profiles::ProfileKeyCredentialRequestContext { + reserved: Default::default(), + uid_bytes, + profile_key_bytes: profile_key_struct.bytes, + key_pair, + ciphertext_with_secret_nonce, + proof, + } + } + + pub fn receive_profile_key_credential( + &self, + context: &api::profiles::ProfileKeyCredentialRequestContext, + response: &api::profiles::ProfileKeyCredentialResponse, + ) -> Result { + response.proof.verify( + self.profile_key_credentials_public_key, + context.key_pair.get_public_key(), + context.uid_bytes, + context.ciphertext_with_secret_nonce.get_ciphertext(), + response.blinded_credential, + )?; + + let credential = context + .key_pair + .decrypt_blinded_profile_key_credential(response.blinded_credential); + + Ok(api::profiles::ProfileKeyCredential { + reserved: Default::default(), + credential, + uid_bytes: context.uid_bytes, + profile_key_bytes: context.profile_key_bytes, + }) + } + + pub fn create_profile_key_credential_presentation( + &self, + randomness: RandomnessBytes, + group_secret_params: api::groups::GroupSecretParams, + profile_key_credential: api::profiles::ProfileKeyCredential, + ) -> api::profiles::ProfileKeyCredentialPresentation { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Random_ServerPublicParams_CreateProfileKeyCredentialPresentation", + &randomness, + ); + + let uid_enc_key_pair = group_secret_params.uid_enc_key_pair; + let profile_key_enc_key_pair = group_secret_params.profile_key_enc_key_pair; + let credentials_public_key = self.profile_key_credentials_public_key; + + let uuid_ciphertext = group_secret_params.encrypt_uuid(profile_key_credential.uid_bytes); + let profile_key_ciphertext = group_secret_params.encrypt_profile_key_bytes( + profile_key_credential.profile_key_bytes, + profile_key_credential.uid_bytes, + ); + + let proof = crypto::proofs::ProfileKeyCredentialPresentationProof::new( + uid_enc_key_pair, + profile_key_enc_key_pair, + credentials_public_key, + profile_key_credential.credential, + uuid_ciphertext.ciphertext, + profile_key_ciphertext.ciphertext, + profile_key_credential.uid_bytes, + profile_key_credential.profile_key_bytes, + &mut sho, + ); + + api::profiles::ProfileKeyCredentialPresentation { + reserved: Default::default(), + proof, + uid_enc_ciphertext: uuid_ciphertext.ciphertext, + profile_key_enc_ciphertext: profile_key_ciphertext.ciphertext, + } + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/common/constants.rs b/net/gurk-rs/files/vendor/zkgroup/src/common/constants.rs new file mode 100644 index 0000000..cc2990c --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/common/constants.rs @@ -0,0 +1,75 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +pub const NUM_AUTH_CRED_ATTRIBUTES: usize = 3; +pub const NUM_PROFILE_KEY_CRED_ATTRIBUTES: usize = 4; + +pub const AES_KEY_LEN: usize = 32; +pub const AESGCM_NONCE_LEN: usize = 12; +pub const AESGCM_TAG_LEN: usize = 16; +pub const GROUP_MASTER_KEY_LEN: usize = 32; +pub const GROUP_SECRET_PARAMS_LEN: usize = 289; +pub const GROUP_PUBLIC_PARAMS_LEN: usize = 97; +pub const GROUP_IDENTIFIER_LEN: usize = 32; +pub const AUTH_CREDENTIAL_LEN: usize = 342; +pub const AUTH_CREDENTIAL_PRESENTATION_LEN: usize = 493; +pub const AUTH_CREDENTIAL_RESPONSE_LEN: usize = 361; +pub const PROFILE_KEY_LEN: usize = 32; +pub const PROFILE_KEY_CIPHERTEXT_LEN: usize = 65; +pub const PROFILE_KEY_COMMITMENT_LEN: usize = 97; +pub const PROFILE_KEY_CREDENTIAL_LEN: usize = 145; +pub const PROFILE_KEY_CREDENTIAL_PRESENTATION_LEN: usize = 713; +pub const PROFILE_KEY_CREDENTIAL_REQUEST_LEN: usize = 329; +pub const PROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN: usize = 473; +pub const PROFILE_KEY_CREDENTIAL_RESPONSE_LEN: usize = 457; +pub const PROFILE_KEY_VERSION_LEN: usize = 32; +pub const PROFILE_KEY_VERSION_ENCODED_LEN: usize = 64; +pub const RESERVED_LEN: usize = 1; +pub const SERVER_SECRET_PARAMS_LEN: usize = 769; +pub const SERVER_PUBLIC_PARAMS_LEN: usize = 161; +pub const UUID_CIPHERTEXT_LEN: usize = 65; +pub const RANDOMNESS_LEN: usize = 32; +pub const SIGNATURE_LEN: usize = 64; +pub const UUID_LEN: usize = 16; + +pub const TEST_ARRAY_16: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + +pub const TEST_ARRAY_16_1: [u8; 16] = [ + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, +]; + +pub const TEST_ARRAY_32: [u8; 32] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, +]; + +pub const TEST_ARRAY_32_1: [u8; 32] = [ + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, +]; + +pub const TEST_ARRAY_32_2: [u8; 32] = [ + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, +]; + +pub const TEST_ARRAY_32_3: [u8; 32] = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, +]; + +pub const TEST_ARRAY_32_4: [u8; 32] = [ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, +]; + +pub const TEST_ARRAY_32_5: [u8; 32] = [ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, +]; diff --git a/net/gurk-rs/files/vendor/zkgroup/src/common/errors.rs b/net/gurk-rs/files/vendor/zkgroup/src/common/errors.rs new file mode 100644 index 0000000..86bdc1c --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/common/errors.rs @@ -0,0 +1,16 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#[derive(Debug)] +pub enum ZkGroupError { + BadArgs, // Bad arguments were passed to the function + DecryptionFailure, // Decryption failed + MacVerificationFailure, // MAC verification failed + ProofVerificationFailure, // Proof verification failed + SignatureVerificationFailure, // Signature verification failed + PointDecodeFailure, // Lizard failed to decode; CAN HAPPEN +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/common/mod.rs b/net/gurk-rs/files/vendor/zkgroup/src/common/mod.rs new file mode 100644 index 0000000..7d2e1dc --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/common/mod.rs @@ -0,0 +1,11 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +pub mod constants; +pub mod errors; +pub mod sho; +pub mod simple_types; diff --git a/net/gurk-rs/files/vendor/zkgroup/src/common/sho.rs b/net/gurk-rs/files/vendor/zkgroup/src/common/sho.rs new file mode 100644 index 0000000..6f352c0 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/common/sho.rs @@ -0,0 +1,44 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; +use poksho::ShoApi; + +pub struct Sho { + internal_sho: poksho::ShoHmacSha256, +} + +impl Sho { + pub fn new(label: &[u8], data: &[u8]) -> Self { + let mut sho = poksho::ShoHmacSha256::new(label); + sho.absorb_and_ratchet(data); + Sho { internal_sho: sho } + } + + pub fn squeeze(&mut self, outlen: usize) -> Vec { + self.internal_sho.squeeze_and_ratchet(outlen) + } + + pub fn get_point(&mut self) -> RistrettoPoint { + let mut point_bytes = [0u8; 64]; + point_bytes.copy_from_slice(&self.internal_sho.squeeze_and_ratchet(64)[..]); + RistrettoPoint::from_uniform_bytes(&point_bytes) + } + + pub fn get_point_single_elligator(&mut self) -> RistrettoPoint { + let mut point_bytes = [0u8; 32]; + point_bytes.copy_from_slice(&self.internal_sho.squeeze_and_ratchet(32)[..]); + RistrettoPoint::from_uniform_bytes_single_elligator(&point_bytes) + } + + pub fn get_scalar(&mut self) -> Scalar { + let mut scalar_bytes = [0u8; 64]; + scalar_bytes.copy_from_slice(&self.internal_sho.squeeze_and_ratchet(64)[..]); + Scalar::from_bytes_mod_order_wide(&scalar_bytes) + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/common/simple_types.rs b/net/gurk-rs/files/vendor/zkgroup/src/common/simple_types.rs new file mode 100644 index 0000000..a2af34d --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/common/simple_types.rs @@ -0,0 +1,37 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +use crate::common::constants::*; +use curve25519_dalek::scalar::Scalar; + +pub type AesKeyBytes = [u8; AES_KEY_LEN]; +pub type GroupMasterKeyBytes = [u8; GROUP_MASTER_KEY_LEN]; +pub type UidBytes = [u8; UUID_LEN]; +pub type ProfileKeyBytes = [u8; PROFILE_KEY_LEN]; +pub type RandomnessBytes = [u8; RANDOMNESS_LEN]; +pub type ReservedBytes = [u8; RESERVED_LEN]; +pub type SignatureBytes = [u8; SIGNATURE_LEN]; +pub type NotarySignatureBytes = [u8; SIGNATURE_LEN]; +pub type GroupIdentifierBytes = [u8; GROUP_IDENTIFIER_LEN]; +pub type ProfileKeyVersionBytes = [u8; PROFILE_KEY_VERSION_LEN]; +pub type ProfileKeyVersionEncodedBytes = [u8; PROFILE_KEY_VERSION_ENCODED_LEN]; +pub type RedemptionTime = u32; + +pub fn encode_redemption_time(redemption_time: u32) -> Scalar { + let mut scalar_bytes: [u8; 32] = Default::default(); + scalar_bytes[0..4].copy_from_slice(&redemption_time.to_be_bytes()); + Scalar::from_bytes_mod_order(scalar_bytes) +} + +#[test] +fn test_encode_scalar() { + let s_bytes = [0xFF; 32]; + match bincode::deserialize::(&s_bytes) { + Err(_) => (), + Ok(_) => unreachable!(), + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/crypto/credentials.rs b/net/gurk-rs/files/vendor/zkgroup/src/crypto/credentials.rs new file mode 100644 index 0000000..0469c9b --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/crypto/credentials.rs @@ -0,0 +1,363 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::sho::*; +use crate::common::simple_types::*; +use crate::crypto::profile_key_credential_request; +use crate::crypto::uid_struct; +use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)] +pub struct SystemParams { + pub(crate) G_w: RistrettoPoint, + pub(crate) G_wprime: RistrettoPoint, + pub(crate) G_x0: RistrettoPoint, + pub(crate) G_x1: RistrettoPoint, + pub(crate) G_y1: RistrettoPoint, + pub(crate) G_y2: RistrettoPoint, + pub(crate) G_y3: RistrettoPoint, + pub(crate) G_y4: RistrettoPoint, + pub(crate) G_m1: RistrettoPoint, + pub(crate) G_m2: RistrettoPoint, + pub(crate) G_m3: RistrettoPoint, + pub(crate) G_m4: RistrettoPoint, + pub(crate) G_V: RistrettoPoint, + pub(crate) G_z: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct KeyPair { + // private + pub(crate) w: Scalar, + pub(crate) wprime: Scalar, + pub(crate) W: RistrettoPoint, + pub(crate) x0: Scalar, + pub(crate) x1: Scalar, + pub(crate) y1: Scalar, + pub(crate) y2: Scalar, + pub(crate) y3: Scalar, + pub(crate) y4: Scalar, + + // public + pub(crate) C_W: RistrettoPoint, + pub(crate) I: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct PublicKey { + pub(crate) C_W: RistrettoPoint, + pub(crate) I: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct AuthCredential { + pub(crate) t: Scalar, + pub(crate) U: RistrettoPoint, + pub(crate) V: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct ProfileKeyCredential { + pub(crate) t: Scalar, + pub(crate) U: RistrettoPoint, + pub(crate) V: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct BlindedProfileKeyCredentialWithSecretNonce { + pub(crate) rprime: Scalar, + pub(crate) t: Scalar, + pub(crate) U: RistrettoPoint, + pub(crate) S1: RistrettoPoint, + pub(crate) S2: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct BlindedProfileKeyCredential { + pub(crate) t: Scalar, + pub(crate) U: RistrettoPoint, + pub(crate) S1: RistrettoPoint, + pub(crate) S2: RistrettoPoint, +} + +pub(crate) fn convert_to_points_uid_struct( + uid: uid_struct::UidStruct, + redemption_time: RedemptionTime, +) -> Vec { + let system = SystemParams::get_hardcoded(); + let redemption_time_scalar = encode_redemption_time(redemption_time); + vec![uid.M1, uid.M2, redemption_time_scalar * system.G_m3] +} + +impl SystemParams { + pub fn generate() -> Self { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Constant_Credentials_SystemParams_Generate", + b"", + ); + let G_w = sho.get_point(); + let G_wprime = sho.get_point(); + + let G_x0 = sho.get_point(); + let G_x1 = sho.get_point(); + + let G_y1 = sho.get_point(); + let G_y2 = sho.get_point(); + let G_y3 = sho.get_point(); + let G_y4 = sho.get_point(); + + let G_m1 = sho.get_point(); + let G_m2 = sho.get_point(); + let G_m3 = sho.get_point(); + let G_m4 = sho.get_point(); + + let G_V = sho.get_point(); + let G_z = sho.get_point(); + + SystemParams { + G_w, + G_wprime, + G_x0, + G_x1, + G_y1, + G_y2, + G_y3, + G_y4, + G_m1, + G_m2, + G_m3, + G_m4, + G_V, + G_z, + } + } + + pub fn get_hardcoded() -> SystemParams { + bincode::deserialize::(&SystemParams::SYSTEM_HARDCODED).unwrap() + } + + const SYSTEM_HARDCODED: [u8; 448] = [ + 0x9a, 0xe7, 0xc8, 0xe5, 0xed, 0x77, 0x9b, 0x11, 0x4a, 0xe7, 0x70, 0x8a, 0xa2, 0xf7, 0x94, + 0x67, 0xa, 0xdd, 0xa3, 0x24, 0x98, 0x7b, 0x65, 0x99, 0x13, 0x12, 0x2c, 0x35, 0x50, 0x5b, + 0x10, 0x5e, 0x6c, 0xa3, 0x10, 0x25, 0xd2, 0xd7, 0x6b, 0xe7, 0xfd, 0x34, 0x94, 0x4f, 0x98, + 0xf7, 0xfa, 0xe, 0x37, 0xba, 0xbb, 0x2c, 0x8b, 0x98, 0xbb, 0xbd, 0xbd, 0x3d, 0xd1, 0xbf, + 0x13, 0xc, 0xca, 0x2c, 0x8a, 0x9a, 0x3b, 0xdf, 0xaa, 0xa2, 0xb6, 0xb3, 0x22, 0xd4, 0x6b, + 0x93, 0xec, 0xa7, 0xb0, 0xd5, 0x1c, 0x86, 0xa3, 0xc8, 0x39, 0xe1, 0x14, 0x66, 0x35, 0x82, + 0x58, 0xa6, 0xc1, 0xc, 0x57, 0x7f, 0xc2, 0xbf, 0xfd, 0x34, 0xcd, 0x99, 0x16, 0x4c, 0x9a, + 0x6c, 0xd2, 0x9f, 0xab, 0x55, 0xd9, 0x1f, 0xf9, 0x26, 0x93, 0x22, 0xec, 0x34, 0x58, 0x60, + 0x3c, 0xc9, 0x6a, 0xd, 0x47, 0xf7, 0x4, 0x5, 0x82, 0x88, 0xf6, 0x2e, 0xe0, 0xac, 0xed, + 0xb8, 0xaa, 0x23, 0x24, 0x21, 0x21, 0xd9, 0x89, 0x65, 0xa9, 0xbb, 0x29, 0x91, 0x25, 0xc, + 0x11, 0x75, 0x80, 0x95, 0xec, 0xe0, 0xfd, 0x2b, 0x33, 0x28, 0x52, 0x86, 0xfe, 0x1f, 0xcb, + 0x5, 0x61, 0x3, 0xb6, 0x8, 0x17, 0x44, 0xb9, 0x75, 0xf5, 0x50, 0xd0, 0x85, 0x21, 0x56, + 0x8d, 0xd3, 0xd8, 0x61, 0x8f, 0x25, 0xc1, 0x40, 0x37, 0x5a, 0xf, 0x40, 0x24, 0xc3, 0xaa, + 0x23, 0xbd, 0xff, 0xfb, 0x27, 0xfb, 0xd9, 0x82, 0x20, 0x8d, 0x3e, 0xcd, 0x1f, 0xd3, 0xbc, + 0xb7, 0xac, 0xc, 0x3a, 0x14, 0xb1, 0x9, 0x80, 0x4f, 0xc7, 0x48, 0xd7, 0xfa, 0x45, 0x6c, + 0xff, 0xb4, 0x93, 0x4f, 0x98, 0xb, 0x6e, 0x9, 0xa2, 0x48, 0xa6, 0xf, 0x44, 0xa6, 0x15, 0xa, + 0xe6, 0xc1, 0x3d, 0x7e, 0x3c, 0x6, 0x26, 0x1d, 0x7e, 0x4e, 0xed, 0x37, 0xf3, 0x9f, 0x60, + 0xcc, 0x60, 0x37, 0xdc, 0x31, 0xc2, 0xe8, 0xd4, 0x47, 0x4f, 0xb5, 0x19, 0x58, 0x7a, 0x44, + 0x86, 0x93, 0x18, 0x2a, 0xd9, 0xd6, 0xd8, 0x6b, 0x53, 0x59, 0x57, 0x85, 0x8f, 0x54, 0x7b, + 0x93, 0x40, 0x12, 0x7d, 0xa7, 0x5f, 0x80, 0x74, 0xca, 0xee, 0x94, 0x4a, 0xc3, 0x6c, 0xa, + 0xc6, 0x62, 0xd3, 0x8c, 0x9b, 0x3c, 0xcc, 0xe0, 0x3a, 0x9, 0x3f, 0xcd, 0x96, 0x44, 0x4, + 0x73, 0x98, 0xb8, 0x6b, 0x6e, 0x83, 0x37, 0x2f, 0xf1, 0x4f, 0xb8, 0xbb, 0xd, 0xea, 0x65, + 0x53, 0x12, 0x52, 0xac, 0x70, 0xd5, 0x8a, 0x4a, 0x8, 0x10, 0xd6, 0x82, 0xa0, 0xe7, 0x9, + 0xc9, 0x22, 0x7b, 0x30, 0xef, 0x6c, 0x8e, 0x17, 0xc5, 0x91, 0x5d, 0x52, 0x72, 0x21, 0xbb, + 0x0, 0xda, 0x81, 0x75, 0xcd, 0x64, 0x89, 0xaa, 0x8a, 0xa4, 0x92, 0xa5, 0x0, 0xf9, 0xab, + 0xee, 0x56, 0x90, 0xb9, 0xdf, 0xca, 0x88, 0x55, 0x4, 0xb6, 0x16, 0xc7, 0x6, 0xc8, 0xc, + 0x75, 0x6c, 0x11, 0xa3, 0x1, 0x6b, 0xbf, 0xb6, 0x9, 0x77, 0xf4, 0x64, 0x8b, 0x5f, 0x23, + 0x95, 0xa4, 0xb4, 0x28, 0xb7, 0x21, 0x19, 0x40, 0x81, 0x3e, 0x3a, 0xfd, 0xe2, 0xb8, 0x7a, + 0xa9, 0xc2, 0xc3, 0x7b, 0xf7, 0x16, 0xe2, 0x57, 0x8f, 0x95, 0x65, 0x6d, 0xf1, 0x2c, 0x2f, + 0xb6, 0xf5, 0xd0, 0x63, 0x1f, 0x6f, 0x71, 0xe2, 0xc3, 0x19, 0x3f, 0x6d, + ]; +} + +impl KeyPair { + pub fn generate(sho: &mut Sho, num_attributes: usize) -> Self { + if !(3..=4).contains(&num_attributes) { + panic!(); + } + + let system = SystemParams::get_hardcoded(); + let w = sho.get_scalar(); + let W = w * system.G_w; + let wprime = sho.get_scalar(); + let x0 = sho.get_scalar(); + let x1 = sho.get_scalar(); + let y1 = sho.get_scalar(); + let y2 = sho.get_scalar(); + let y3 = sho.get_scalar(); + let y4 = sho.get_scalar(); + + let C_W = (w * system.G_w) + (wprime * system.G_wprime); + let mut I = system.G_V + - (x0 * system.G_x0) + - (x1 * system.G_x1) + - (y1 * system.G_y1) + - (y2 * system.G_y2) + - (y3 * system.G_y3); + + if num_attributes > 3 { + I -= y4 * system.G_y4; + } + + KeyPair { + w, + wprime, + W, + x0, + x1, + y1, + y2, + y3, + y4, + C_W, + I, + } + } + + pub fn get_public_key(&self) -> PublicKey { + PublicKey { + C_W: self.C_W, + I: self.I, + } + } + + pub fn create_auth_credential( + &self, + uid: uid_struct::UidStruct, + redemption_time: RedemptionTime, + sho: &mut Sho, + ) -> AuthCredential { + let M = convert_to_points_uid_struct(uid, redemption_time); + let (t, U, V) = self.credential_core(M, sho); + AuthCredential { t, U, V } + } + + fn credential_core( + &self, + M: Vec, + sho: &mut Sho, + ) -> (Scalar, RistrettoPoint, RistrettoPoint) { + if M.len() > 4 { + panic!(); + } + let t = sho.get_scalar(); + let U = sho.get_point(); + + let mut V = self.W + (self.x0 + self.x1 * t) * U; + V += self.y1 * M[0]; + V += self.y2 * M[1]; + if M.len() > 2 { + V += self.y3 * M[2]; + } + if M.len() > 3 { + V += self.y4 * M[3]; + } + (t, U, V) + } + + pub fn create_blinded_profile_key_credential( + &self, + uid: uid_struct::UidStruct, + public_key: profile_key_credential_request::PublicKey, + ciphertext: profile_key_credential_request::Ciphertext, + sho: &mut Sho, + ) -> BlindedProfileKeyCredentialWithSecretNonce { + let M = vec![uid.M1, uid.M2]; + + let (t, U, Vprime) = self.credential_core(M, sho); + let rprime = sho.get_scalar(); + let R1 = rprime * RISTRETTO_BASEPOINT_POINT; + let R2 = rprime * public_key.Y + Vprime; + let S1 = R1 + (self.y3 * ciphertext.D1) + (self.y4 * ciphertext.E1); + let S2 = R2 + (self.y3 * ciphertext.D2) + (self.y4 * ciphertext.E2); + BlindedProfileKeyCredentialWithSecretNonce { + rprime, + t, + U, + S1, + S2, + } + } +} + +impl BlindedProfileKeyCredentialWithSecretNonce { + pub fn get_blinded_profile_key_credential(&self) -> BlindedProfileKeyCredential { + BlindedProfileKeyCredential { + t: self.t, + U: self.U, + S1: self.S1, + S2: self.S2, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::constants::*; + use crate::crypto::proofs; + + #[test] + fn test_system() { + let params = SystemParams::generate(); + println!("PARAMS = {:#x?}", bincode::serialize(¶ms)); + assert!(SystemParams::generate() == SystemParams::get_hardcoded()); + } + + #[test] + fn test_mac() { + let mut sho = Sho::new(b"Test_Credentials", b""); + let keypair = KeyPair::generate(&mut sho, NUM_AUTH_CRED_ATTRIBUTES); + + let uid_bytes = TEST_ARRAY_16; + let redemption_time = 37; + let uid = uid_struct::UidStruct::new(uid_bytes); + let credential = keypair.create_auth_credential(uid, redemption_time, &mut sho); + let proof = proofs::AuthCredentialIssuanceProof::new( + keypair, + credential, + uid, + redemption_time, + &mut sho, + ); + + let public_key = keypair.get_public_key(); + proof + .verify(public_key, credential, uid, redemption_time) + .unwrap(); + + let keypair_bytes = bincode::serialize(&keypair).unwrap(); + let keypair2 = bincode::deserialize(&keypair_bytes).unwrap(); + assert!(keypair == keypair2); + + let public_key_bytes = bincode::serialize(&public_key).unwrap(); + let public_key2 = bincode::deserialize(&public_key_bytes).unwrap(); + assert!(public_key == public_key2); + + let mac_bytes = bincode::serialize(&credential).unwrap(); + + println!("mac_bytes = {:#x?}", mac_bytes); + assert!( + mac_bytes + == vec![ + 0xe0, 0xce, 0x21, 0xfe, 0xb7, 0xc3, 0xb8, 0x62, 0x3a, 0xe6, 0x20, 0xab, 0x3e, + 0xe6, 0x5d, 0x94, 0xa3, 0xf3, 0x40, 0x53, 0x31, 0x63, 0xd2, 0x4c, 0x5d, 0x41, + 0xa0, 0xd6, 0x7a, 0x40, 0xb3, 0x2, 0x8e, 0x50, 0xa2, 0x7b, 0xd4, 0xda, 0xe9, + 0x9d, 0x60, 0x0, 0xdb, 0x97, 0x3d, 0xbc, 0xc5, 0xad, 0xe1, 0x32, 0xbc, 0x56, + 0xb0, 0xe1, 0xac, 0x16, 0x7b, 0xb, 0x2c, 0x9, 0xe2, 0xb6, 0xc8, 0x5b, 0x68, + 0xc8, 0x8e, 0x7d, 0xfd, 0x58, 0x97, 0x51, 0xe9, 0x8, 0x1f, 0x81, 0xb0, 0x24, + 0xea, 0xa0, 0xaf, 0x29, 0x6, 0xed, 0xb3, 0x9, 0x32, 0xed, 0x65, 0x28, 0x2f, + 0xa1, 0x79, 0x9e, 0x1, 0x24, + ] + ); + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/crypto/mod.rs b/net/gurk-rs/files/vendor/zkgroup/src/crypto/mod.rs new file mode 100644 index 0000000..2154c18 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/crypto/mod.rs @@ -0,0 +1,16 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +pub mod credentials; +pub mod profile_key_commitment; +pub mod profile_key_credential_request; +pub mod profile_key_encryption; +pub mod profile_key_struct; +pub mod proofs; +pub mod signature; +pub mod uid_encryption; +pub mod uid_struct; diff --git a/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_commitment.rs b/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_commitment.rs new file mode 100644 index 0000000..1340c0c --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_commitment.rs @@ -0,0 +1,120 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::constants::*; +use crate::common::sho::*; +use crate::common::simple_types::*; +use crate::crypto::profile_key_struct; +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct SystemParams { + pub(crate) G_j1: RistrettoPoint, + pub(crate) G_j2: RistrettoPoint, + pub(crate) G_j3: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct CommitmentWithSecretNonce { + pub(crate) J1: RistrettoPoint, + pub(crate) J2: RistrettoPoint, + pub(crate) J3: RistrettoPoint, + pub(crate) j3: Scalar, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct Commitment { + pub(crate) J1: RistrettoPoint, + pub(crate) J2: RistrettoPoint, + pub(crate) J3: RistrettoPoint, +} + +impl SystemParams { + pub fn generate() -> Self { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Constant_ProfileKeyCommitment_SystemParams_Generate", + b"", + ); + let G_j1 = sho.get_point(); + let G_j2 = sho.get_point(); + let G_j3 = sho.get_point(); + SystemParams { G_j1, G_j2, G_j3 } + } + + pub fn get_hardcoded() -> SystemParams { + bincode::deserialize::(&SystemParams::SYSTEM_HARDCODED).unwrap() + } + + const SYSTEM_HARDCODED: [u8; 96] = [ + 0xa8, 0xca, 0xb, 0xbd, 0x11, 0x48, 0xc4, 0x66, 0x72, 0x58, 0x60, 0x64, 0xa, 0xc5, 0x3d, + 0x27, 0x72, 0xb1, 0x4e, 0xea, 0xe0, 0x17, 0xa, 0x38, 0xc6, 0x2c, 0x7b, 0x3d, 0xd2, 0x9c, + 0x3e, 0x4a, 0x14, 0xb9, 0x46, 0x2d, 0x94, 0x8f, 0x5, 0x94, 0x50, 0x79, 0x9f, 0x4c, 0xc2, + 0xa0, 0x6e, 0x55, 0xde, 0xc8, 0x7, 0x73, 0x56, 0x70, 0xb9, 0x4a, 0x5c, 0xe8, 0xf, 0x59, + 0xf1, 0x95, 0x8, 0x61, 0xb0, 0xc0, 0xf7, 0xb9, 0x1f, 0x6e, 0xf9, 0xc7, 0x55, 0x60, 0x93, + 0xd8, 0x93, 0xa, 0x86, 0xbd, 0x36, 0x18, 0x8c, 0xec, 0x74, 0x5, 0x54, 0x65, 0x7d, 0x92, + 0xdc, 0xd8, 0x6a, 0xad, 0x25, 0x1c, + ]; +} + +impl CommitmentWithSecretNonce { + pub fn new( + profile_key: profile_key_struct::ProfileKeyStruct, + uid_bytes: UidBytes, + ) -> CommitmentWithSecretNonce { + let commitment_system = SystemParams::get_hardcoded(); + + let profile_key_struct::ProfileKeyStruct { M3, M4, .. } = profile_key; + let j3 = Self::calc_j3(profile_key.bytes, uid_bytes); + let J1 = (j3 * commitment_system.G_j1) + M3; + let J2 = (j3 * commitment_system.G_j2) + M4; + let J3 = j3 * commitment_system.G_j3; + CommitmentWithSecretNonce { J1, J2, J3, j3 } + } + + pub fn get_profile_key_commitment(&self) -> Commitment { + Commitment { + J1: self.J1, + J2: self.J2, + J3: self.J3, + } + } + + pub fn calc_j3(profile_key_bytes: ProfileKeyBytes, uid_bytes: UidBytes) -> Scalar { + let mut combined_array = [0u8; PROFILE_KEY_LEN + UUID_LEN]; + combined_array[..PROFILE_KEY_LEN].copy_from_slice(&profile_key_bytes); + combined_array[PROFILE_KEY_LEN..].copy_from_slice(&uid_bytes); + Sho::new( + b"Signal_ZKGroup_20200424_ProfileKeyAndUid_ProfileKeyCommitment_Calcj3", + &combined_array, + ) + .get_scalar() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_system() { + let params = SystemParams::generate(); + println!("PARAMS = {:#x?}", bincode::serialize(¶ms)); + assert!(SystemParams::generate() == SystemParams::get_hardcoded()); + } + + #[test] + fn test_commitment() { + let profile_key = profile_key_struct::ProfileKeyStruct::new(TEST_ARRAY_32, TEST_ARRAY_16); + let c1 = CommitmentWithSecretNonce::new(profile_key, TEST_ARRAY_16); + let c2 = CommitmentWithSecretNonce::new(profile_key, TEST_ARRAY_16); + assert!(c1 == c2); + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_credential_request.rs b/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_credential_request.rs new file mode 100644 index 0000000..8a402dd --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_credential_request.rs @@ -0,0 +1,190 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::sho::*; +use crate::crypto::credentials::{BlindedProfileKeyCredential, ProfileKeyCredential}; +use crate::crypto::profile_key_struct; +use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; +use serde::{Deserialize, Serialize}; + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct KeyPair { + // private + pub(crate) y: Scalar, + + // public + pub(crate) Y: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct PublicKey { + pub(crate) Y: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct CiphertextWithSecretNonce { + pub(crate) r1: Scalar, + pub(crate) r2: Scalar, + pub(crate) D1: RistrettoPoint, + pub(crate) D2: RistrettoPoint, + pub(crate) E1: RistrettoPoint, + pub(crate) E2: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct Ciphertext { + pub(crate) D1: RistrettoPoint, + pub(crate) D2: RistrettoPoint, + pub(crate) E1: RistrettoPoint, + pub(crate) E2: RistrettoPoint, +} + +impl KeyPair { + pub fn generate(sho: &mut Sho) -> Self { + let y = sho.get_scalar(); + let Y = y * RISTRETTO_BASEPOINT_POINT; + KeyPair { y, Y } + } + + pub fn get_public_key(&self) -> PublicKey { + PublicKey { Y: self.Y } + } + + pub fn encrypt( + &self, + profile_key_struct: profile_key_struct::ProfileKeyStruct, + sho: &mut Sho, + ) -> CiphertextWithSecretNonce { + let r1 = sho.get_scalar(); + let r2 = sho.get_scalar(); + let D1 = r1 * RISTRETTO_BASEPOINT_POINT; + let E1 = r2 * RISTRETTO_BASEPOINT_POINT; + + let D2 = r1 * (self.Y) + profile_key_struct.M3; + let E2 = r2 * (self.Y) + profile_key_struct.M4; + + CiphertextWithSecretNonce { + r1, + r2, + D1, + D2, + E1, + E2, + } + } + + pub fn decrypt_blinded_profile_key_credential( + &self, + blinded_profile_key_credential: BlindedProfileKeyCredential, + ) -> ProfileKeyCredential { + let V = blinded_profile_key_credential.S2 - self.y * blinded_profile_key_credential.S1; + ProfileKeyCredential { + t: blinded_profile_key_credential.t, + U: blinded_profile_key_credential.U, + V, + } + } +} + +impl CiphertextWithSecretNonce { + pub fn get_ciphertext(&self) -> Ciphertext { + Ciphertext { + D1: self.D1, + D2: self.D2, + E1: self.E1, + E2: self.E2, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::constants::*; + use crate::crypto::profile_key_commitment; + + #[test] + fn test_request_response() { + let mut sho = Sho::new(b"Test_Profile_Key_Credential_Request", b""); + + // client + let blind_key_pair = KeyPair::generate(&mut sho); + + // server and client + let profile_key_struct = + profile_key_struct::ProfileKeyStruct::new(TEST_ARRAY_32, TEST_ARRAY_16); + let _ = profile_key_commitment::CommitmentWithSecretNonce::new( + profile_key_struct, + TEST_ARRAY_16, + ); + + // client + let _ = blind_key_pair.encrypt(profile_key_struct, &mut sho); + + // server + /*TODO request_ciphertext.verify(c).unwrap(); + + let credential_key_pair = credentials::KeyPair::generate(TEST_ARRAY_32_2); + let uid_bytes = TEST_ARRAY_16; + let redemption_time = 37; + let randomness = TEST_ARRAY_32_3; + let response = + query.create_response(credential_key_pair, uid_bytes, redemption_time, randomness); + + response + .verify( + blind_key_pair, + credential_key_pair.get_public_key(), + query.E_D1, + query.E_D2, + uid_bytes, + redemption_time, + ) + .unwrap(); + + let mac = response.get_mac(blind_key_pair); + + let master_key = GroupMasterKey::new(TEST_ARRAY_32_4); + let uid_enc_key_pair = uid_encryption::KeyPair::derive_from(master_key); + let profile_enc_key_pair = KeyPair::generate(TEST_ARRAY_32_4); + let profile_ciphertext = profile_enc_key_pair + .get_public_key() + .encrypt(profile_key, TEST_ARRAY_32_4); + + let ppp = profile_presentation_proof::PresentationProof::new( + mac, + uid_enc_key_pair, + credential_key_pair.get_public_key(), + uid_bytes, + profile_ciphertext.E_B1, + profile_ciphertext.E_B2, + profile_key, + profile_enc_key_pair.B, + profile_enc_key_pair.b, + redemption_time, + TEST_ARRAY_32_5, + ); + + let uid = uid_encryption::UidStruct::new(uid_bytes); + let uid_ciphertext = uid_enc_key_pair.encrypt(uid); + + ppp.verify( + uid_ciphertext, + uid_enc_key_pair.get_public_key(), + credential_key_pair, + redemption_time, + profile_ciphertext.E_B1, + profile_ciphertext.E_B2, + profile_enc_key_pair.B, + ).unwrap(); + */ + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_encryption.rs b/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_encryption.rs new file mode 100644 index 0000000..d1f6f9a --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_encryption.rs @@ -0,0 +1,228 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::errors::*; +use crate::common::sho::*; +use crate::common::simple_types::*; +use crate::crypto::profile_key_struct; +use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; +use serde::{Deserialize, Serialize}; + +use curve25519_dalek::subtle::Choice; +use curve25519_dalek::subtle::ConditionallySelectable; +use curve25519_dalek::subtle::ConstantTimeEq; + +use ZkGroupError::*; + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct SystemParams { + pub(crate) G_b1: RistrettoPoint, + pub(crate) G_b2: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct KeyPair { + pub(crate) b1: Scalar, + pub(crate) b2: Scalar, + pub(crate) B: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct PublicKey { + pub(crate) B: RistrettoPoint, +} + +#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)] +pub struct Ciphertext { + pub(crate) E_B1: RistrettoPoint, + pub(crate) E_B2: RistrettoPoint, +} + +impl SystemParams { + pub fn generate() -> Self { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Constant_ProfileKeyEncryption_SystemParams_Generate", + b"", + ); + let G_b1 = sho.get_point(); + let G_b2 = sho.get_point(); + SystemParams { G_b1, G_b2 } + } + + pub fn get_hardcoded() -> SystemParams { + bincode::deserialize::(&SystemParams::SYSTEM_HARDCODED).unwrap() + } + + const SYSTEM_HARDCODED: [u8; 64] = [ + 0xf6, 0xba, 0xa3, 0x17, 0xce, 0x18, 0x39, 0xc9, 0x3d, 0x61, 0x7e, 0xc, 0xd8, 0x37, 0xd1, + 0x9d, 0xa9, 0xc8, 0xa4, 0xc5, 0x20, 0xbf, 0x7c, 0x51, 0xb1, 0xe6, 0xc2, 0xcb, 0x2a, 0x4, + 0x9c, 0x61, 0x2e, 0x1, 0x75, 0x89, 0x4c, 0x87, 0x30, 0xb2, 0x3, 0xab, 0x3b, 0xd9, 0x8e, + 0xcb, 0x2d, 0x81, 0xab, 0xac, 0xb6, 0x5f, 0x8a, 0x61, 0x24, 0xf4, 0x97, 0x71, 0xd1, 0x4a, + 0x98, 0x52, 0x12, 0xc, + ]; +} + +impl KeyPair { + pub fn derive_from(sho: &mut Sho) -> Self { + let system = SystemParams::get_hardcoded(); + + let b1 = sho.get_scalar(); + let b2 = sho.get_scalar(); + + let B = b1 * system.G_b1 + b2 * system.G_b2; + KeyPair { b1, b2, B } + } + + pub fn encrypt(&self, profile_key: profile_key_struct::ProfileKeyStruct) -> Ciphertext { + let E_B1 = self.calc_E_B1(profile_key); + let E_B2 = (self.b2 * E_B1) + profile_key.M4; + Ciphertext { E_B1, E_B2 } + } + + // Might return DecryptionFailure + #[allow(clippy::needless_range_loop)] + pub fn decrypt( + &self, + ciphertext: Ciphertext, + uid_bytes: UidBytes, + ) -> Result { + if ciphertext.E_B1 == RISTRETTO_BASEPOINT_POINT { + return Err(DecryptionFailure); + } + let M4 = ciphertext.E_B2 - (self.b2 * ciphertext.E_B1); + let (mask, candidates) = M4.decode_253_bits(); + + let target_M3 = self.b1.invert() * ciphertext.E_B1; + + let mut retval: profile_key_struct::ProfileKeyStruct = Default::default(); + let mut n_found = 0; + for i in 0..8 { + let is_valid_fe = Choice::from((mask >> i) & 1); + let profile_key_bytes: ProfileKeyBytes = candidates[i]; + for j in 0..8 { + let mut pk = profile_key_bytes; + if ((j >> 2) & 1) == 1 { + pk[0] |= 0x01; + } + if ((j >> 1) & 1) == 1 { + pk[31] |= 0x80; + } + if (j & 1) == 1 { + pk[31] |= 0x40; + } + let M3 = profile_key_struct::ProfileKeyStruct::calc_M3(pk, uid_bytes); + let candidate_retval = profile_key_struct::ProfileKeyStruct { bytes: pk, M3, M4 }; + let found = M3.ct_eq(&target_M3) & is_valid_fe; + retval.conditional_assign(&candidate_retval, found); + n_found += found.unwrap_u8(); + } + } + if n_found == 1 { + Ok(retval) + } else { + Err(DecryptionFailure) + } + } + + fn calc_E_B1(&self, profile_key: profile_key_struct::ProfileKeyStruct) -> RistrettoPoint { + self.b1 * profile_key.M3 + } + + pub fn get_public_key(&self) -> PublicKey { + PublicKey { B: self.B } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::constants::*; + + #[test] + fn test_profile_key_encryption() { + let master_key = TEST_ARRAY_32_1; + let mut sho = Sho::new(b"Test_Profile_Key_Encryption", &master_key); + + //let system = SystemParams::generate(); + //println!("PARAMS = {:#x?}", bincode::serialize(&system)); + assert!(SystemParams::generate() == SystemParams::get_hardcoded()); + + let key_pair = KeyPair::derive_from(&mut sho); + + // Test serialize of key_pair + let key_pair_bytes = bincode::serialize(&key_pair).unwrap(); + match bincode::deserialize::(&key_pair_bytes[0..key_pair_bytes.len() - 1]) { + Err(_) => (), + _ => unreachable!(), + }; + let key_pair2: KeyPair = bincode::deserialize(&key_pair_bytes).unwrap(); + assert!(key_pair == key_pair2); + + let profile_key_bytes = TEST_ARRAY_32_1; + let uid_bytes = TEST_ARRAY_16_1; + let profile_key = profile_key_struct::ProfileKeyStruct::new(profile_key_bytes, uid_bytes); + let ciphertext = key_pair.encrypt(profile_key); + + // Test serialize / deserialize of Ciphertext + let ciphertext_bytes = bincode::serialize(&ciphertext).unwrap(); + assert!(ciphertext_bytes.len() == 64); + let ciphertext2: Ciphertext = bincode::deserialize(&ciphertext_bytes).unwrap(); + assert!(ciphertext == ciphertext2); + println!("ciphertext_bytes = {:#x?}", ciphertext_bytes); + assert!( + ciphertext_bytes + == vec![ + 0x56, 0x18, 0xcb, 0x4c, 0x7d, 0x72, 0x1e, 0x1, 0x2b, 0x22, 0xf0, 0x77, 0xef, + 0x12, 0x64, 0xf6, 0xb1, 0x43, 0xbb, 0x59, 0x7a, 0x1d, 0x66, 0x5a, 0x70, 0xaa, + 0x84, 0x24, 0x5f, 0x24, 0x6d, 0x20, 0xba, 0xdb, 0x97, 0x47, 0x4a, 0x56, 0xf4, + 0xb5, 0x36, 0x1a, 0xec, 0xa9, 0xd1, 0x18, 0xb7, 0x0, 0x4e, 0x14, 0x9, 0x71, + 0x99, 0xa, 0xab, 0x2a, 0xf2, 0x43, 0x2d, 0x3f, 0x8f, 0x7d, 0x21, 0x3a, + ] + ); + + let plaintext = key_pair.decrypt(ciphertext2, uid_bytes).unwrap(); + assert!(plaintext == profile_key); + + let mut sho = Sho::new(b"Test_Repeated_ProfileKeyEnc/Dec", b"seed"); + for _ in 0..100 { + let mut uid_bytes: UidBytes = Default::default(); + let mut profile_key_bytes: ProfileKeyBytes = Default::default(); + + uid_bytes.copy_from_slice(&sho.squeeze(UUID_LEN)[..]); + profile_key_bytes.copy_from_slice(&sho.squeeze(PROFILE_KEY_LEN)[..]); + + let profile_key = + profile_key_struct::ProfileKeyStruct::new(profile_key_bytes, uid_bytes); + let ciphertext = key_pair.encrypt(profile_key); + assert!(key_pair.decrypt(ciphertext, uid_bytes).unwrap() == profile_key); + } + + let uid_bytes = TEST_ARRAY_16; + let profile_key = profile_key_struct::ProfileKeyStruct::new(TEST_ARRAY_32, TEST_ARRAY_16); + let ciphertext = key_pair.encrypt(profile_key); + assert!(key_pair.decrypt(ciphertext, uid_bytes).unwrap() == profile_key); + + let uid_bytes = TEST_ARRAY_16; + let profile_key = profile_key_struct::ProfileKeyStruct::new(TEST_ARRAY_32_2, TEST_ARRAY_16); + let ciphertext = key_pair.encrypt(profile_key); + assert!(key_pair.decrypt(ciphertext, uid_bytes).unwrap() == profile_key); + + let uid_bytes = TEST_ARRAY_16; + let profile_key = profile_key_struct::ProfileKeyStruct::new(TEST_ARRAY_32_3, TEST_ARRAY_16); + let ciphertext = key_pair.encrypt(profile_key); + assert!(key_pair.decrypt(ciphertext, uid_bytes).unwrap() == profile_key); + + let uid_bytes = TEST_ARRAY_16; + let profile_key = profile_key_struct::ProfileKeyStruct::new(TEST_ARRAY_32_4, TEST_ARRAY_16); + let ciphertext = key_pair.encrypt(profile_key); + assert!(key_pair.decrypt(ciphertext, uid_bytes).unwrap() == profile_key); + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_struct.rs b/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_struct.rs new file mode 100644 index 0000000..ad93263 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/crypto/profile_key_struct.rs @@ -0,0 +1,75 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::constants::*; +use crate::common::sho::*; +use crate::common::simple_types::*; +use curve25519_dalek::ristretto::RistrettoPoint; +use serde::{Deserialize, Serialize}; + +use curve25519_dalek::subtle::Choice; +use curve25519_dalek::subtle::ConditionallySelectable; + +#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)] +pub struct ProfileKeyStruct { + pub(crate) bytes: ProfileKeyBytes, + pub(crate) M3: RistrettoPoint, + pub(crate) M4: RistrettoPoint, +} + +impl ProfileKeyStruct { + pub fn new(profile_key_bytes: ProfileKeyBytes, uid_bytes: UidBytes) -> Self { + let mut encoded_profile_key = profile_key_bytes; + encoded_profile_key[0] &= 254; + encoded_profile_key[31] &= 63; + let M3 = Self::calc_M3(profile_key_bytes, uid_bytes); + let M4 = RistrettoPoint::from_uniform_bytes_single_elligator(&encoded_profile_key); + + ProfileKeyStruct { + bytes: profile_key_bytes, + M3, + M4, + } + } + + pub fn calc_M3(profile_key_bytes: ProfileKeyBytes, uid_bytes: UidBytes) -> RistrettoPoint { + let mut combined_array = [0u8; PROFILE_KEY_LEN + UUID_LEN]; + combined_array[..PROFILE_KEY_LEN].copy_from_slice(&profile_key_bytes); + combined_array[PROFILE_KEY_LEN..].copy_from_slice(&uid_bytes); + Sho::new( + b"Signal_ZKGroup_20200424_ProfileKeyAndUid_ProfileKey_CalcM3", + &combined_array, + ) + .get_point_single_elligator() + } + + pub fn to_bytes(&self) -> ProfileKeyBytes { + self.bytes + } +} + +impl ConditionallySelectable for ProfileKeyStruct { + #[allow(clippy::needless_range_loop)] + fn conditional_select( + a: &ProfileKeyStruct, + b: &ProfileKeyStruct, + choice: Choice, + ) -> ProfileKeyStruct { + let mut bytes: ProfileKeyBytes = [0u8; PROFILE_KEY_LEN]; + for i in 0..PROFILE_KEY_LEN { + bytes[i] = u8::conditional_select(&a.bytes[i], &b.bytes[i], choice); + } + + ProfileKeyStruct { + bytes, + M3: RistrettoPoint::conditional_select(&a.M3, &b.M3, choice), + M4: RistrettoPoint::conditional_select(&a.M4, &b.M4, choice), + } + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/crypto/proofs.rs b/net/gurk-rs/files/vendor/zkgroup/src/crypto/proofs.rs new file mode 100644 index 0000000..2a9ba6f --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/crypto/proofs.rs @@ -0,0 +1,731 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] +use crate::common::constants::*; +use crate::common::errors::ZkGroupError::*; +use crate::common::errors::*; +use crate::common::sho::*; +use crate::common::simple_types::*; +use crate::crypto::credentials; +use crate::crypto::profile_key_commitment; +use crate::crypto::profile_key_credential_request; +use crate::crypto::profile_key_encryption; +use crate::crypto::profile_key_struct; +use crate::crypto::uid_encryption; +use crate::crypto::uid_struct; +use curve25519_dalek::ristretto::RistrettoPoint; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone)] +pub struct AuthCredentialIssuanceProof { + poksho_proof: Vec, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct ProfileKeyCredentialRequestProof { + poksho_proof: Vec, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct ProfileKeyCredentialIssuanceProof { + poksho_proof: Vec, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct AuthCredentialPresentationProof { + C_x0: RistrettoPoint, + C_x1: RistrettoPoint, + C_y1: RistrettoPoint, + C_y2: RistrettoPoint, + C_y3: RistrettoPoint, + C_V: RistrettoPoint, + poksho_proof: Vec, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct ProfileKeyCredentialPresentationProof { + C_x0: RistrettoPoint, + C_x1: RistrettoPoint, + C_y1: RistrettoPoint, + C_y2: RistrettoPoint, + C_y3: RistrettoPoint, + C_y4: RistrettoPoint, + C_V: RistrettoPoint, + C_z: RistrettoPoint, + poksho_proof: Vec, +} + +impl AuthCredentialIssuanceProof { + pub fn get_poksho_statement() -> poksho::Statement { + let mut st = poksho::Statement::new(); + st.add("C_W", &[("w", "G_w"), ("wprime", "G_wprime")]); + st.add( + "G_V-I", + &[ + ("x0", "G_x0"), + ("x1", "G_x1"), + ("y1", "G_y1"), + ("y2", "G_y2"), + ("y3", "G_y3"), + ], + ); + st.add( + "V", + &[ + ("w", "G_w"), + ("x0", "U"), + ("x1", "tU"), + ("y1", "M1"), + ("y2", "M2"), + ("y3", "M3"), + ], + ); + st + } + + pub fn new( + key_pair: credentials::KeyPair, + credential: credentials::AuthCredential, + uid: uid_struct::UidStruct, + redemption_time: RedemptionTime, + sho: &mut Sho, + ) -> Self { + let system = credentials::SystemParams::get_hardcoded(); + + let M = credentials::convert_to_points_uid_struct(uid, redemption_time); + + let mut scalar_args = poksho::ScalarArgs::new(); + scalar_args.add("w", key_pair.w); + scalar_args.add("wprime", key_pair.wprime); + scalar_args.add("x0", key_pair.x0); + scalar_args.add("x1", key_pair.x1); + scalar_args.add("y1", key_pair.y1); + scalar_args.add("y2", key_pair.y2); + scalar_args.add("y3", key_pair.y3); + + let mut point_args = poksho::PointArgs::new(); + point_args.add("C_W", key_pair.C_W); + point_args.add("G_w", system.G_w); + point_args.add("G_wprime", system.G_wprime); + point_args.add("G_V-I", system.G_V - key_pair.I); + point_args.add("G_x0", system.G_x0); + point_args.add("G_x1", system.G_x1); + point_args.add("G_y1", system.G_y1); + point_args.add("G_y2", system.G_y2); + point_args.add("G_y3", system.G_y3); + point_args.add("V", credential.V); + point_args.add("U", credential.U); + point_args.add("tU", credential.t * credential.U); + point_args.add("M1", M[0]); + point_args.add("M2", M[1]); + point_args.add("M3", M[2]); + + let poksho_proof = Self::get_poksho_statement() + .prove( + &scalar_args, + &point_args, + &[], + &sho.squeeze(RANDOMNESS_LEN)[..], + ) + .unwrap(); + Self { poksho_proof } + } + + pub fn verify( + &self, + public_key: credentials::PublicKey, + credential: credentials::AuthCredential, + uid_struct: uid_struct::UidStruct, + redemption_time: RedemptionTime, + ) -> Result<(), ZkGroupError> { + let system = credentials::SystemParams::get_hardcoded(); + + let M = credentials::convert_to_points_uid_struct(uid_struct, redemption_time); + + let mut point_args = poksho::PointArgs::new(); + point_args.add("C_W", public_key.C_W); + point_args.add("G_w", system.G_w); + point_args.add("G_wprime", system.G_wprime); + point_args.add("G_V-I", system.G_V - public_key.I); + point_args.add("G_x0", system.G_x0); + point_args.add("G_x1", system.G_x1); + point_args.add("G_y1", system.G_y1); + point_args.add("G_y2", system.G_y2); + point_args.add("G_y3", system.G_y3); + point_args.add("V", credential.V); + point_args.add("U", credential.U); + point_args.add("tU", credential.t * credential.U); + point_args.add("M1", M[0]); + point_args.add("M2", M[1]); + point_args.add("M3", M[2]); + + match Self::get_poksho_statement().verify_proof(&self.poksho_proof, &point_args, &[]) { + Err(_) => Err(ProofVerificationFailure), + Ok(_) => Ok(()), + } + } +} + +impl ProfileKeyCredentialRequestProof { + pub fn get_poksho_statement() -> poksho::Statement { + let mut st = poksho::Statement::new(); + st.add("Y", &[("y", "G")]); + st.add("D1", &[("r1", "G")]); + st.add("E1", &[("r2", "G")]); + st.add("J3", &[("j3", "G_j3")]); + st.add("D2-J1", &[("r1", "Y"), ("j3", "-G_j1")]); + st.add("E2-J2", &[("r2", "Y"), ("j3", "-G_j2")]); + st + } + + pub fn new( + key_pair: profile_key_credential_request::KeyPair, + ciphertext: profile_key_credential_request::CiphertextWithSecretNonce, + commitment: profile_key_commitment::CommitmentWithSecretNonce, + sho: &mut Sho, + ) -> ProfileKeyCredentialRequestProof { + let commitment_system = profile_key_commitment::SystemParams::get_hardcoded(); + + let mut scalar_args = poksho::ScalarArgs::new(); + scalar_args.add("y", key_pair.y); + scalar_args.add("r1", ciphertext.r1); + scalar_args.add("r2", ciphertext.r2); + scalar_args.add("j3", commitment.j3); + + let mut point_args = poksho::PointArgs::new(); + point_args.add("Y", key_pair.Y); + point_args.add("D1", ciphertext.D1); + point_args.add("E1", ciphertext.E1); + point_args.add("J3", commitment.J3); + point_args.add("G_j3", commitment_system.G_j3); + point_args.add("D2-J1", ciphertext.D2 - commitment.J1); + point_args.add("-G_j1", -commitment_system.G_j1); + point_args.add("E2-J2", ciphertext.E2 - commitment.J2); + point_args.add("-G_j2", -commitment_system.G_j2); + + let poksho_proof = Self::get_poksho_statement() + .prove( + &scalar_args, + &point_args, + &[], + &sho.squeeze(RANDOMNESS_LEN)[..], + ) + .unwrap(); + ProfileKeyCredentialRequestProof { poksho_proof } + } + + pub fn verify( + &self, + public_key: profile_key_credential_request::PublicKey, + ciphertext: profile_key_credential_request::Ciphertext, + commitment: profile_key_commitment::Commitment, + ) -> Result<(), ZkGroupError> { + let commitment_system = profile_key_commitment::SystemParams::get_hardcoded(); + + let mut point_args = poksho::PointArgs::new(); + point_args.add("Y", public_key.Y); + point_args.add("D1", ciphertext.D1); + point_args.add("E1", ciphertext.E1); + point_args.add("J3", commitment.J3); + point_args.add("G_j3", commitment_system.G_j3); + point_args.add("D2-J1", ciphertext.D2 - commitment.J1); + point_args.add("-G_j1", -commitment_system.G_j1); + point_args.add("E2-J2", ciphertext.E2 - commitment.J2); + point_args.add("-G_j2", -commitment_system.G_j2); + + match Self::get_poksho_statement().verify_proof(&self.poksho_proof, &point_args, &[]) { + Err(_) => Err(ProofVerificationFailure), + Ok(_) => Ok(()), + } + } +} + +impl ProfileKeyCredentialIssuanceProof { + pub fn get_poksho_statement() -> poksho::Statement { + let mut st = poksho::Statement::new(); + st.add("C_W", &[("w", "G_w"), ("wprime", "G_wprime")]); + st.add( + "G_V-I", + &[ + ("x0", "G_x0"), + ("x1", "G_x1"), + ("y1", "G_y1"), + ("y2", "G_y2"), + ("y3", "G_y3"), + ("y4", "G_y4"), + ], + ); + st.add("S1", &[("y3", "D1"), ("y4", "E1"), ("rprime", "G")]); + st.add( + "S2", + &[ + ("y3", "D2"), + ("y4", "E2"), + ("rprime", "Y"), + ("w", "G_w"), + ("x0", "U"), + ("x1", "tU"), + ("y1", "M1"), + ("y2", "M2"), + ], + ); + st + } + + pub fn new( + key_pair: credentials::KeyPair, + request_public_key: profile_key_credential_request::PublicKey, + request: profile_key_credential_request::Ciphertext, + blinded_credential: credentials::BlindedProfileKeyCredentialWithSecretNonce, + uid: uid_struct::UidStruct, + sho: &mut Sho, + ) -> ProfileKeyCredentialIssuanceProof { + let credentials_system = credentials::SystemParams::get_hardcoded(); + + let mut scalar_args = poksho::ScalarArgs::new(); + scalar_args.add("w", key_pair.w); + scalar_args.add("wprime", key_pair.wprime); + scalar_args.add("x0", key_pair.x0); + scalar_args.add("x1", key_pair.x1); + scalar_args.add("y1", key_pair.y1); + scalar_args.add("y2", key_pair.y2); + scalar_args.add("y3", key_pair.y3); + scalar_args.add("y4", key_pair.y4); + scalar_args.add("rprime", blinded_credential.rprime); + + let mut point_args = poksho::PointArgs::new(); + point_args.add("C_W", key_pair.C_W); + point_args.add("G_w", credentials_system.G_w); + point_args.add("G_wprime", credentials_system.G_wprime); + point_args.add("G_V-I", credentials_system.G_V - key_pair.I); + point_args.add("G_x0", credentials_system.G_x0); + point_args.add("G_x1", credentials_system.G_x1); + point_args.add("G_y1", credentials_system.G_y1); + point_args.add("G_y2", credentials_system.G_y2); + point_args.add("G_y3", credentials_system.G_y3); + point_args.add("G_y4", credentials_system.G_y4); + point_args.add("S1", blinded_credential.S1); + point_args.add("D1", request.D1); + point_args.add("E1", request.E1); + point_args.add("S2", blinded_credential.S2); + point_args.add("D2", request.D2); + point_args.add("E2", request.E2); + point_args.add("Y", request_public_key.Y); + point_args.add("U", blinded_credential.U); + point_args.add("tU", blinded_credential.t * blinded_credential.U); + point_args.add("M1", uid.M1); + point_args.add("M2", uid.M2); + + let poksho_proof = Self::get_poksho_statement() + .prove( + &scalar_args, + &point_args, + &[], + &sho.squeeze(RANDOMNESS_LEN)[..], + ) + .unwrap(); + ProfileKeyCredentialIssuanceProof { poksho_proof } + } + + pub fn verify( + &self, + credentials_public_key: credentials::PublicKey, + request_public_key: profile_key_credential_request::PublicKey, + uid_bytes: UidBytes, + request: profile_key_credential_request::Ciphertext, + blinded_credential: credentials::BlindedProfileKeyCredential, + ) -> Result<(), ZkGroupError> { + let credentials_system = credentials::SystemParams::get_hardcoded(); + let uid = uid_struct::UidStruct::new(uid_bytes); + + let mut point_args = poksho::PointArgs::new(); + point_args.add("C_W", credentials_public_key.C_W); + point_args.add("G_w", credentials_system.G_w); + point_args.add("G_wprime", credentials_system.G_wprime); + point_args.add("G_V-I", credentials_system.G_V - credentials_public_key.I); + point_args.add("G_x0", credentials_system.G_x0); + point_args.add("G_x1", credentials_system.G_x1); + point_args.add("G_y1", credentials_system.G_y1); + point_args.add("G_y2", credentials_system.G_y2); + point_args.add("G_y3", credentials_system.G_y3); + point_args.add("G_y4", credentials_system.G_y4); + point_args.add("S1", blinded_credential.S1); + point_args.add("D1", request.D1); + point_args.add("E1", request.E1); + point_args.add("S2", blinded_credential.S2); + point_args.add("D2", request.D2); + point_args.add("E2", request.E2); + point_args.add("Y", request_public_key.Y); + point_args.add("U", blinded_credential.U); + point_args.add("tU", blinded_credential.t * blinded_credential.U); + point_args.add("M1", uid.M1); + point_args.add("M2", uid.M2); + + match Self::get_poksho_statement().verify_proof(&self.poksho_proof, &point_args, &[]) { + Err(_) => Err(ProofVerificationFailure), + Ok(_) => Ok(()), + } + } +} + +impl AuthCredentialPresentationProof { + pub fn get_poksho_statement() -> poksho::Statement { + let mut st = poksho::Statement::new(); + + st.add("Z", &[("z", "I")]); + st.add("C_x1", &[("t", "C_x0"), ("z0", "G_x0"), ("z", "G_x1")]); + st.add("A", &[("a1", "G_a1"), ("a2", "G_a2")]); + st.add("C_y2-E_A2", &[("z", "G_y2"), ("a2", "-E_A1")]); + st.add("E_A1", &[("a1", "C_y1"), ("z1", "G_y1")]); + st.add("C_y3", &[("z", "G_y3")]); + st + } + + pub fn new( + credentials_public_key: credentials::PublicKey, + uid_enc_key_pair: uid_encryption::KeyPair, + credential: credentials::AuthCredential, + uid: uid_struct::UidStruct, + uid_ciphertext: uid_encryption::Ciphertext, + redemption_time: RedemptionTime, + sho: &mut Sho, + ) -> Self { + let credentials_system = credentials::SystemParams::get_hardcoded(); + let uid_system = uid_encryption::SystemParams::get_hardcoded(); + let M = credentials::convert_to_points_uid_struct(uid, redemption_time); + + let z = sho.get_scalar(); + + let C_y1 = z * credentials_system.G_y1 + M[0]; + let C_y2 = z * credentials_system.G_y2 + M[1]; + let C_y3 = z * credentials_system.G_y3; + + let C_x0 = z * credentials_system.G_x0 + credential.U; + let C_V = z * credentials_system.G_V + credential.V; + let C_x1 = z * credentials_system.G_x1 + credential.t * credential.U; + + let z0 = -z * credential.t; + let z1 = -z * uid_enc_key_pair.a1; + + let I = credentials_public_key.I; + let Z = z * I; + + // Scalars listed in order of stmts for debugging + let mut scalar_args = poksho::ScalarArgs::new(); + scalar_args.add("z", z); + scalar_args.add("t", credential.t); + scalar_args.add("z0", z0); + scalar_args.add("a1", uid_enc_key_pair.a1); + scalar_args.add("a2", uid_enc_key_pair.a2); + scalar_args.add("z1", z1); + + // Points listed in order of stmts for debugging + let mut point_args = poksho::PointArgs::new(); + point_args.add("Z", Z); + point_args.add("I", I); + point_args.add("C_x1", C_x1); + point_args.add("C_x0", C_x0); + point_args.add("G_x0", credentials_system.G_x0); + point_args.add("G_x1", credentials_system.G_x1); + point_args.add("A", uid_enc_key_pair.A); + point_args.add("G_a1", uid_system.G_a1); + point_args.add("G_a2", uid_system.G_a2); + point_args.add("C_y2-E_A2", C_y2 - uid_ciphertext.E_A2); + point_args.add("G_y2", credentials_system.G_y2); + point_args.add("-E_A1", -uid_ciphertext.E_A1); + point_args.add("E_A1", uid_ciphertext.E_A1); + point_args.add("C_y1", C_y1); + point_args.add("G_y1", credentials_system.G_y1); + point_args.add("C_y3", C_y3); + point_args.add("G_y3", credentials_system.G_y3); + + let poksho_proof = Self::get_poksho_statement() + .prove( + &scalar_args, + &point_args, + &[], + &sho.squeeze(RANDOMNESS_LEN)[..], + ) + .unwrap(); + + Self { + C_x0, + C_x1, + C_y1, + C_y2, + C_y3, + C_V, + poksho_proof, + } + } + + pub fn verify( + &self, + credentials_key_pair: credentials::KeyPair, + uid_enc_public_key: uid_encryption::PublicKey, + uid_ciphertext: uid_encryption::Ciphertext, + redemption_time: RedemptionTime, + ) -> Result<(), ZkGroupError> { + let enc_system = uid_encryption::SystemParams::get_hardcoded(); + let credentials_system = credentials::SystemParams::get_hardcoded(); + + let Self { + C_x0, + C_x1, + C_y1, + C_y2, + C_y3, + C_V, + poksho_proof, + } = self; + + let (C_x0, C_x1, C_y1, C_y2, C_y3, C_V) = (*C_x0, *C_x1, *C_y1, *C_y2, *C_y3, *C_V); + + let credentials::KeyPair { + W, + x0, + x1, + y1, + y2, + y3, + I, + .. + } = credentials_key_pair; + + let m3 = encode_redemption_time(redemption_time); + let M3 = m3 * credentials_system.G_m3; + let Z = C_V - W - x0 * C_x0 - x1 * C_x1 - y1 * C_y1 - y2 * C_y2 - y3 * (C_y3 + M3); + + // Points listed in order of stmts for debugging + let mut point_args = poksho::PointArgs::new(); + point_args.add("Z", Z); + point_args.add("I", I); + point_args.add("C_x1", C_x1); + point_args.add("C_x0", C_x0); + point_args.add("G_x0", credentials_system.G_x0); + point_args.add("G_x1", credentials_system.G_x1); + point_args.add("A", uid_enc_public_key.A); + point_args.add("G_a1", enc_system.G_a1); + point_args.add("G_a2", enc_system.G_a2); + point_args.add("C_y2-E_A2", C_y2 - uid_ciphertext.E_A2); + point_args.add("G_y2", credentials_system.G_y2); + point_args.add("-E_A1", -uid_ciphertext.E_A1); + point_args.add("E_A1", uid_ciphertext.E_A1); + point_args.add("C_y1", C_y1); + point_args.add("G_y1", credentials_system.G_y1); + point_args.add("C_y3", C_y3); + point_args.add("G_y3", credentials_system.G_y3); + + match Self::get_poksho_statement().verify_proof(poksho_proof, &point_args, &[]) { + Err(_) => Err(ZkGroupError::ProofVerificationFailure), + Ok(_) => Ok(()), + } + } +} + +impl ProfileKeyCredentialPresentationProof { + pub fn get_poksho_statement() -> poksho::Statement { + let mut st = poksho::Statement::new(); + st.add("C_z", &[("z", "G_z")]); + st.add("Z", &[("z", "I")]); + st.add("C_x1", &[("t", "C_x0"), ("z0", "G_x0"), ("z", "G_x1")]); + st.add("A", &[("a1", "G_a1"), ("a2", "G_a2")]); + st.add("B", &[("b1", "G_b1"), ("b2", "G_b2")]); + st.add("C_y2-E_A2", &[("z", "G_y2"), ("a2", "-E_A1")]); + st.add("E_A1", &[("a1", "C_y1"), ("z1", "G_y1")]); + st.add("C_y4-E_B2", &[("z", "G_y4"), ("b2", "-E_B1")]); + st.add("E_B1", &[("b1", "C_y3"), ("z2", "G_y3")]); + st + } + + #[allow(clippy::too_many_arguments)] + pub fn new( + uid_enc_key_pair: uid_encryption::KeyPair, + profile_key_enc_key_pair: profile_key_encryption::KeyPair, + credentials_public_key: credentials::PublicKey, + credential: credentials::ProfileKeyCredential, + uid_ciphertext: uid_encryption::Ciphertext, + profile_key_ciphertext: profile_key_encryption::Ciphertext, + uid_bytes: UidBytes, + profile_key_bytes: ProfileKeyBytes, + sho: &mut Sho, + ) -> Self { + let credentials_system = credentials::SystemParams::get_hardcoded(); + let uid_system = uid_encryption::SystemParams::get_hardcoded(); + let profile_key_system = profile_key_encryption::SystemParams::get_hardcoded(); + let uid = uid_struct::UidStruct::new(uid_bytes); + let profile_key = profile_key_struct::ProfileKeyStruct::new(profile_key_bytes, uid_bytes); + + let z = sho.get_scalar(); + + let C_y1 = z * credentials_system.G_y1 + uid.M1; + let C_y2 = z * credentials_system.G_y2 + uid.M2; + let C_y3 = z * credentials_system.G_y3 + profile_key.M3; + let C_y4 = z * credentials_system.G_y4 + profile_key.M4; + + let C_x0 = z * credentials_system.G_x0 + credential.U; + let C_V = z * credentials_system.G_V + credential.V; + let C_x1 = z * credentials_system.G_x1 + credential.t * credential.U; + let C_z = z * credentials_system.G_z; + + let z0 = -z * credential.t; + let z1 = -z * uid_enc_key_pair.a1; + let z2 = -z * profile_key_enc_key_pair.b1; + + let I = credentials_public_key.I; + let Z = z * I; + + // Scalars listed in order of stmts for debugging + let mut scalar_args = poksho::ScalarArgs::new(); + scalar_args.add("z", z); + scalar_args.add("t", credential.t); + scalar_args.add("z0", z0); + scalar_args.add("a1", uid_enc_key_pair.a1); + scalar_args.add("a2", uid_enc_key_pair.a2); + scalar_args.add("b1", profile_key_enc_key_pair.b1); + scalar_args.add("b2", profile_key_enc_key_pair.b2); + scalar_args.add("z1", z1); + scalar_args.add("z2", z2); + + // Points listed in order of stmts for debugging + let mut point_args = poksho::PointArgs::new(); + point_args.add("C_z", C_z); + point_args.add("G_z", credentials_system.G_z); + point_args.add("Z", Z); + point_args.add("I", I); + + point_args.add("C_x1", C_x1); + point_args.add("C_x0", C_x0); + point_args.add("G_x0", credentials_system.G_x0); + point_args.add("G_x1", credentials_system.G_x1); + + point_args.add("A", uid_enc_key_pair.A); + point_args.add("G_a1", uid_system.G_a1); + point_args.add("G_a2", uid_system.G_a2); + + point_args.add("B", profile_key_enc_key_pair.B); + point_args.add("G_b1", profile_key_system.G_b1); + point_args.add("G_b2", profile_key_system.G_b2); + + point_args.add("C_y2-E_A2", C_y2 - uid_ciphertext.E_A2); + point_args.add("G_y2", credentials_system.G_y2); + point_args.add("-E_A1", -uid_ciphertext.E_A1); + point_args.add("E_A1", uid_ciphertext.E_A1); + point_args.add("C_y1", C_y1); + point_args.add("G_y1", credentials_system.G_y1); + + point_args.add("C_y4-E_B2", C_y4 - profile_key_ciphertext.E_B2); + point_args.add("G_y4", credentials_system.G_y4); + point_args.add("-E_B1", -profile_key_ciphertext.E_B1); + point_args.add("E_B1", profile_key_ciphertext.E_B1); + point_args.add("C_y3", C_y3); + point_args.add("G_y3", credentials_system.G_y3); + + let poksho_proof = Self::get_poksho_statement() + .prove( + &scalar_args, + &point_args, + &[], + &sho.squeeze(RANDOMNESS_LEN)[..], + ) + .unwrap(); + + ProfileKeyCredentialPresentationProof { + C_y1, + C_y2, + C_y3, + C_y4, + C_x0, + C_x1, + C_V, + C_z, + poksho_proof, + } + } + + pub fn verify( + &self, + credentials_key_pair: credentials::KeyPair, + uid_ciphertext: uid_encryption::Ciphertext, + uid_enc_public_key: uid_encryption::PublicKey, + profile_key_ciphertext: profile_key_encryption::Ciphertext, + profile_key_enc_public_key: profile_key_encryption::PublicKey, + ) -> Result<(), ZkGroupError> { + let uid_enc_system = uid_encryption::SystemParams::get_hardcoded(); + let profile_key_enc_system = profile_key_encryption::SystemParams::get_hardcoded(); + let credentials_system = credentials::SystemParams::get_hardcoded(); + + let Self { + C_x0, + C_x1, + C_y1, + C_y2, + C_y3, + C_y4, + C_V, + C_z, + poksho_proof, + } = self; + + let (C_x0, C_x1, C_y1, C_y2, C_y3, C_y4, C_V, C_z) = + (*C_x0, *C_x1, *C_y1, *C_y2, *C_y3, *C_y4, *C_V, *C_z); + + let credentials::KeyPair { + W, + x0, + x1, + y1, + y2, + y3, + y4, + I, + .. + } = credentials_key_pair; + + let Z = + C_V - W - x0 * C_x0 - x1 * C_x1 - (y1 * C_y1) - (y2 * C_y2) - (y3 * C_y3) - (y4 * C_y4); + + // Points listed in order of stmts for debugging + let mut point_args = poksho::PointArgs::new(); + point_args.add("C_z", C_z); + point_args.add("G_z", credentials_system.G_z); + point_args.add("Z", Z); + point_args.add("I", I); + point_args.add("C_x1", C_x1); + point_args.add("C_x0", C_x0); + point_args.add("G_x0", credentials_system.G_x0); + point_args.add("G_x1", credentials_system.G_x1); + + point_args.add("A", uid_enc_public_key.A); + point_args.add("G_a1", uid_enc_system.G_a1); + point_args.add("G_a2", uid_enc_system.G_a2); + + point_args.add("B", profile_key_enc_public_key.B); + point_args.add("G_b1", profile_key_enc_system.G_b1); + point_args.add("G_b2", profile_key_enc_system.G_b2); + + point_args.add("C_y2-E_A2", C_y2 - uid_ciphertext.E_A2); + point_args.add("G_y2", credentials_system.G_y2); + point_args.add("-E_A1", -uid_ciphertext.E_A1); + point_args.add("E_A1", uid_ciphertext.E_A1); + point_args.add("C_y1", C_y1); + point_args.add("G_y1", credentials_system.G_y1); + + point_args.add("C_y4-E_B2", C_y4 - profile_key_ciphertext.E_B2); + point_args.add("G_y4", credentials_system.G_y4); + point_args.add("-E_B1", -profile_key_ciphertext.E_B1); + point_args.add("E_B1", profile_key_ciphertext.E_B1); + point_args.add("C_y3", C_y3); + point_args.add("G_y3", credentials_system.G_y3); + + match Self::get_poksho_statement().verify_proof(poksho_proof, &point_args, &[]) { + Err(_) => Err(ZkGroupError::ProofVerificationFailure), + Ok(_) => Ok(()), + } + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/crypto/signature.rs b/net/gurk-rs/files/vendor/zkgroup/src/crypto/signature.rs new file mode 100644 index 0000000..fb635eb --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/crypto/signature.rs @@ -0,0 +1,120 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::constants::*; +use crate::common::errors::*; +use crate::common::sho::*; +use crate::common::simple_types::*; +use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; +use serde::{Deserialize, Serialize}; + +use ZkGroupError::*; + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct KeyPair { + pub(crate) signing_key: Scalar, + pub(crate) public_key: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct PublicKey { + pub(crate) public_key: RistrettoPoint, +} + +impl KeyPair { + pub fn generate(sho: &mut Sho) -> Self { + let signing_key = sho.get_scalar(); + let public_key = signing_key * RISTRETTO_BASEPOINT_POINT; + KeyPair { + signing_key, + public_key, + } + } + + // Could return SignatureVerificationFailure if public/private key are inconsistent + pub fn sign(&self, message: &[u8], sho: &mut Sho) -> Result { + match poksho::sign( + self.signing_key, + self.public_key, + message, + &sho.squeeze(RANDOMNESS_LEN)[..], + ) { + Ok(vec_bytes) => { + let mut s: SignatureBytes = [0u8; SIGNATURE_LEN]; + s.copy_from_slice(&vec_bytes[..]); + Ok(s) + } + Err(_) => Err(SignatureVerificationFailure), + } + } + + pub fn get_public_key(&self) -> PublicKey { + PublicKey { + public_key: self.public_key, + } + } +} + +impl PublicKey { + // Might return SignatureVerificationFailure + pub fn verify(&self, message: &[u8], signature: SignatureBytes) -> Result<(), ZkGroupError> { + match poksho::verify_signature(&signature, self.public_key, message) { + Err(_) => Err(SignatureVerificationFailure), + Ok(_) => Ok(()), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_signature() { + let group_key = TEST_ARRAY_32; + let mut sho = Sho::new(b"Test_Signature", &group_key); + let key_pair = KeyPair::generate(&mut sho); + + // Test serialize of key_pair + let key_pair_bytes = bincode::serialize(&key_pair).unwrap(); + assert!(key_pair_bytes.len() == 64); + let public_key_bytes = bincode::serialize(&key_pair.get_public_key()).unwrap(); + assert!(public_key_bytes.len() == 32); + let key_pair2: KeyPair = bincode::deserialize(&key_pair_bytes).unwrap(); + assert!(key_pair == key_pair2); + + let mut message = TEST_ARRAY_32_1; + + let signature = key_pair.sign(&message, &mut sho).unwrap(); + key_pair2 + .get_public_key() + .verify(&message, signature) + .unwrap(); + + // test signature falure + message[0] ^= 1; + match key_pair2.get_public_key().verify(&message, signature) { + Err(SignatureVerificationFailure) => (), + _ => unreachable!(), + } + + println!("signature = {:#x?}", &signature[..]); + let signature_result = [ + 0xdb, 0x9b, 0xfb, 0xd6, 0x15, 0x26, 0xc3, 0x50, 0xf9, 0xbe, 0x95, 0x17, 0x11, 0x6, + 0xd0, 0x6, 0x52, 0x88, 0xcb, 0x33, 0x3, 0x1b, 0xe7, 0x17, 0x25, 0x24, 0x37, 0x80, 0x53, + 0x2c, 0xaa, 0x7, 0xcb, 0xda, 0x74, 0xc4, 0x19, 0x3b, 0x6e, 0xe6, 0xe9, 0x5f, 0xae, + 0xcd, 0x41, 0xfb, 0x44, 0x19, 0xce, 0xae, 0x3f, 0x4d, 0x63, 0xb9, 0x47, 0x59, 0x27, + 0xe1, 0x10, 0xee, 0xb7, 0x72, 0xb, 0x6, + ]; + + assert!(signature[..] == signature_result[..]); + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/crypto/uid_encryption.rs b/net/gurk-rs/files/vendor/zkgroup/src/crypto/uid_encryption.rs new file mode 100644 index 0000000..6463644 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/crypto/uid_encryption.rs @@ -0,0 +1,160 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::errors::*; +use crate::common::sho::*; +use crate::crypto::uid_struct; +use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; +use curve25519_dalek::ristretto::RistrettoPoint; +use curve25519_dalek::scalar::Scalar; +use serde::{Deserialize, Serialize}; + +use ZkGroupError::*; + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct SystemParams { + pub(crate) G_a1: RistrettoPoint, + pub(crate) G_a2: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct KeyPair { + pub(crate) a1: Scalar, + pub(crate) a2: Scalar, + pub(crate) A: RistrettoPoint, +} + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct PublicKey { + pub(crate) A: RistrettoPoint, +} + +#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)] +pub struct Ciphertext { + pub(crate) E_A1: RistrettoPoint, + pub(crate) E_A2: RistrettoPoint, +} + +impl SystemParams { + pub fn generate() -> Self { + let mut sho = Sho::new( + b"Signal_ZKGroup_20200424_Constant_UidEncryption_SystemParams_Generate", + b"", + ); + let G_a1 = sho.get_point(); + let G_a2 = sho.get_point(); + SystemParams { G_a1, G_a2 } + } + + pub fn get_hardcoded() -> SystemParams { + bincode::deserialize::(&SystemParams::SYSTEM_HARDCODED).unwrap() + } + + const SYSTEM_HARDCODED: [u8; 64] = [ + 0xa6, 0x32, 0x4c, 0x36, 0x8d, 0xf7, 0x34, 0x69, 0x11, 0x47, 0x98, 0x13, 0x48, 0xb6, 0xe7, + 0xeb, 0x42, 0xc3, 0x30, 0x7e, 0x71, 0x1b, 0x6c, 0x7e, 0xcc, 0xd3, 0x3, 0x2d, 0x45, 0x69, + 0x3f, 0x5a, 0x4, 0x80, 0x13, 0x52, 0x5b, 0x76, 0x12, 0x4b, 0xf2, 0x64, 0xc, 0x5e, 0x93, + 0x69, 0xc7, 0x6e, 0xfb, 0xe8, 0xa, 0xba, 0x2a, 0x24, 0xaa, 0x5d, 0x8e, 0x18, 0xa9, 0x8e, + 0xba, 0x14, 0xf8, 0x37, + ]; +} + +impl KeyPair { + pub fn derive_from(sho: &mut Sho) -> Self { + let system = SystemParams::get_hardcoded(); + + let a1 = sho.get_scalar(); + let a2 = sho.get_scalar(); + + let A = a1 * system.G_a1 + a2 * system.G_a2; + KeyPair { a1, a2, A } + } + + pub fn encrypt(&self, uid: uid_struct::UidStruct) -> Ciphertext { + let E_A1 = self.calc_E_A1(uid); + let E_A2 = (self.a2 * E_A1) + uid.M2; + Ciphertext { E_A1, E_A2 } + } + + // Might return DecryptionFailure + pub fn decrypt(&self, ciphertext: Ciphertext) -> Result { + if ciphertext.E_A1 == RISTRETTO_BASEPOINT_POINT { + return Err(DecryptionFailure); + } + match uid_struct::UidStruct::from_M2(ciphertext.E_A2 - (self.a2 * ciphertext.E_A1)) { + Err(_) => Err(DecryptionFailure), + Ok(decrypted_uid) => { + if ciphertext.E_A1 == self.calc_E_A1(decrypted_uid) { + Ok(decrypted_uid) + } else { + Err(DecryptionFailure) + } + } + } + } + + fn calc_E_A1(&self, uid: uid_struct::UidStruct) -> RistrettoPoint { + self.a1 * uid.M1 + } + + pub fn get_public_key(&self) -> PublicKey { + PublicKey { A: self.A } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::constants::*; + + #[test] + fn test_uid_encryption() { + let master_key = TEST_ARRAY_32; + let mut sho = Sho::new(b"Test_Uid_Encryption", &master_key); + + //let system = SystemParams::generate(); + //println!("PARAMS = {:#x?}", bincode::serialize(&system)); + assert!(SystemParams::generate() == SystemParams::get_hardcoded()); + + let key_pair = KeyPair::derive_from(&mut sho); + + // Test serialize of key_pair + let key_pair_bytes = bincode::serialize(&key_pair).unwrap(); + match bincode::deserialize::(&key_pair_bytes[0..key_pair_bytes.len() - 1]) { + Err(_) => (), + _ => unreachable!(), + }; + let key_pair2: KeyPair = bincode::deserialize(&key_pair_bytes).unwrap(); + assert!(key_pair == key_pair2); + + let uid = uid_struct::UidStruct::new(TEST_ARRAY_16); + let ciphertext = key_pair.encrypt(uid); + + // Test serialize / deserialize of Ciphertext + let ciphertext_bytes = bincode::serialize(&ciphertext).unwrap(); + assert!(ciphertext_bytes.len() == 64); + let ciphertext2: Ciphertext = bincode::deserialize(&ciphertext_bytes).unwrap(); + assert!(ciphertext == ciphertext2); + //println!("ciphertext_bytes = {:#x?}", ciphertext_bytes); + assert!( + ciphertext_bytes + == vec![ + 0xf8, 0x9e, 0xe7, 0x70, 0x5a, 0x66, 0x3, 0x6b, 0x90, 0x8d, 0xb8, 0x84, 0x21, + 0x1b, 0x77, 0x3a, 0xc5, 0x43, 0xee, 0x35, 0xc4, 0xa3, 0x8, 0x62, 0x20, 0xfc, + 0x3e, 0x1e, 0x35, 0xb4, 0x23, 0x4c, 0xfa, 0x1d, 0x2e, 0xea, 0x2c, 0xc2, 0xf4, + 0xb4, 0xc4, 0x2c, 0xff, 0x39, 0xa9, 0xdc, 0xeb, 0x57, 0x29, 0x3b, 0x5f, 0x87, + 0x70, 0xca, 0x60, 0xf9, 0xe9, 0xb7, 0x44, 0x47, 0xbf, 0xd3, 0xbd, 0x3d, + ] + ); + + let plaintext = key_pair.decrypt(ciphertext2).unwrap(); + + assert!(plaintext == uid); + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/crypto/uid_struct.rs b/net/gurk-rs/files/vendor/zkgroup/src/crypto/uid_struct.rs new file mode 100644 index 0000000..e993c53 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/crypto/uid_struct.rs @@ -0,0 +1,49 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +use crate::common::errors::*; +use crate::common::sho::*; +use crate::common::simple_types::*; +use curve25519_dalek::ristretto::RistrettoPoint; +use serde::{Deserialize, Serialize}; +use sha2::Sha256; + +use ZkGroupError::*; + +#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] +pub struct UidStruct { + pub(crate) bytes: UidBytes, + pub(crate) M1: RistrettoPoint, + pub(crate) M2: RistrettoPoint, +} + +impl UidStruct { + pub fn new(uid_bytes: UidBytes) -> Self { + let mut sho = Sho::new(b"Signal_ZKGroup_20200424_UID_CalcM1", &uid_bytes); + let M1 = sho.get_point(); + let M2 = RistrettoPoint::lizard_encode::(&uid_bytes); + UidStruct { + bytes: uid_bytes, + M1, + M2, + } + } + + // Might return PointDecodeFailure + pub fn from_M2(M2: RistrettoPoint) -> Result { + match M2.lizard_decode::() { + None => Err(PointDecodeFailure), + Some(bytes) => Ok(Self::new(bytes)), + } + } + + pub fn to_bytes(&self) -> UidBytes { + self.bytes + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/ffi/constants.rs b/net/gurk-rs/files/vendor/zkgroup/src/ffi/constants.rs new file mode 100644 index 0000000..594edff --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/ffi/constants.rs @@ -0,0 +1,12 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] + +pub const FFI_RETURN_OK: i32 = 0; +pub const FFI_RETURN_INTERNAL_ERROR: i32 = 1; // ZkGroupError +pub const FFI_RETURN_INPUT_ERROR: i32 = 2; diff --git a/net/gurk-rs/files/vendor/zkgroup/src/ffi/ffiapi.rs b/net/gurk-rs/files/vendor/zkgroup/src/ffi/ffiapi.rs new file mode 100644 index 0000000..810afe3 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/ffi/ffiapi.rs @@ -0,0 +1,1324 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +// Generated by zkgroup/codegen/codegen.py - do not edit + +#![allow(non_snake_case)] + +use super::simpleapi; +use crate::ffi::constants::FFI_RETURN_INTERNAL_ERROR; +use std::{panic, slice}; + +#[no_mangle] +pub extern "C" fn FFI_ProfileKey_getCommitment( + profileKey: *const u8, + profileKeyLen: u32, + uuid: *const u8, + uuidLen: u32, + profileKeyCommitmentOut: *mut u8, + profileKeyCommitmentLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key: &[u8] = + unsafe { slice::from_raw_parts(profileKey, profileKeyLen as usize) }; + let uuid: &[u8] = unsafe { slice::from_raw_parts(uuid, uuidLen as usize) }; + let profile_key_commitment: &mut [u8] = unsafe { + slice::from_raw_parts_mut(profileKeyCommitmentOut, profileKeyCommitmentLen as usize) + }; + + simpleapi::ProfileKey_getCommitment(profile_key, uuid, profile_key_commitment) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ProfileKey_getProfileKeyVersion( + profileKey: *const u8, + profileKeyLen: u32, + uuid: *const u8, + uuidLen: u32, + profileKeyVersionOut: *mut u8, + profileKeyVersionLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key: &[u8] = + unsafe { slice::from_raw_parts(profileKey, profileKeyLen as usize) }; + let uuid: &[u8] = unsafe { slice::from_raw_parts(uuid, uuidLen as usize) }; + let profile_key_version: &mut [u8] = unsafe { + slice::from_raw_parts_mut(profileKeyVersionOut, profileKeyVersionLen as usize) + }; + + simpleapi::ProfileKey_getProfileKeyVersion(profile_key, uuid, profile_key_version) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ProfileKeyCommitment_checkValidContents( + profileKeyCommitment: *const u8, + profileKeyCommitmentLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_commitment: &[u8] = unsafe { + slice::from_raw_parts(profileKeyCommitment, profileKeyCommitmentLen as usize) + }; + + simpleapi::ProfileKeyCommitment_checkValidContents(profile_key_commitment) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupSecretParams_generateDeterministic( + randomness: *const u8, + randomnessLen: u32, + groupSecretParamsOut: *mut u8, + groupSecretParamsLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let randomness: &[u8] = + unsafe { slice::from_raw_parts(randomness, randomnessLen as usize) }; + let group_secret_params: &mut [u8] = unsafe { + slice::from_raw_parts_mut(groupSecretParamsOut, groupSecretParamsLen as usize) + }; + + simpleapi::GroupSecretParams_generateDeterministic(randomness, group_secret_params) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupSecretParams_deriveFromMasterKey( + groupMasterKey: *const u8, + groupMasterKeyLen: u32, + groupSecretParamsOut: *mut u8, + groupSecretParamsLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_master_key: &[u8] = + unsafe { slice::from_raw_parts(groupMasterKey, groupMasterKeyLen as usize) }; + let group_secret_params: &mut [u8] = unsafe { + slice::from_raw_parts_mut(groupSecretParamsOut, groupSecretParamsLen as usize) + }; + + simpleapi::GroupSecretParams_deriveFromMasterKey(group_master_key, group_secret_params) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupSecretParams_checkValidContents( + groupSecretParams: *const u8, + groupSecretParamsLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params: &[u8] = + unsafe { slice::from_raw_parts(groupSecretParams, groupSecretParamsLen as usize) }; + + simpleapi::GroupSecretParams_checkValidContents(group_secret_params) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupSecretParams_getMasterKey( + groupSecretParams: *const u8, + groupSecretParamsLen: u32, + groupMasterKeyOut: *mut u8, + groupMasterKeyLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params: &[u8] = + unsafe { slice::from_raw_parts(groupSecretParams, groupSecretParamsLen as usize) }; + let group_master_key: &mut [u8] = + unsafe { slice::from_raw_parts_mut(groupMasterKeyOut, groupMasterKeyLen as usize) }; + + simpleapi::GroupSecretParams_getMasterKey(group_secret_params, group_master_key) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupSecretParams_getPublicParams( + groupSecretParams: *const u8, + groupSecretParamsLen: u32, + groupPublicParamsOut: *mut u8, + groupPublicParamsLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params: &[u8] = + unsafe { slice::from_raw_parts(groupSecretParams, groupSecretParamsLen as usize) }; + let group_public_params: &mut [u8] = unsafe { + slice::from_raw_parts_mut(groupPublicParamsOut, groupPublicParamsLen as usize) + }; + + simpleapi::GroupSecretParams_getPublicParams(group_secret_params, group_public_params) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupSecretParams_encryptUuid( + groupSecretParams: *const u8, + groupSecretParamsLen: u32, + uuid: *const u8, + uuidLen: u32, + uuidCiphertextOut: *mut u8, + uuidCiphertextLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params: &[u8] = + unsafe { slice::from_raw_parts(groupSecretParams, groupSecretParamsLen as usize) }; + let uuid: &[u8] = unsafe { slice::from_raw_parts(uuid, uuidLen as usize) }; + let uuid_ciphertext: &mut [u8] = + unsafe { slice::from_raw_parts_mut(uuidCiphertextOut, uuidCiphertextLen as usize) }; + + simpleapi::GroupSecretParams_encryptUuid(group_secret_params, uuid, uuid_ciphertext) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupSecretParams_decryptUuid( + groupSecretParams: *const u8, + groupSecretParamsLen: u32, + uuidCiphertext: *const u8, + uuidCiphertextLen: u32, + uuidOut: *mut u8, + uuidLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params: &[u8] = + unsafe { slice::from_raw_parts(groupSecretParams, groupSecretParamsLen as usize) }; + let uuid_ciphertext: &[u8] = + unsafe { slice::from_raw_parts(uuidCiphertext, uuidCiphertextLen as usize) }; + let uuid: &mut [u8] = unsafe { slice::from_raw_parts_mut(uuidOut, uuidLen as usize) }; + + simpleapi::GroupSecretParams_decryptUuid(group_secret_params, uuid_ciphertext, uuid) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupSecretParams_encryptProfileKey( + groupSecretParams: *const u8, + groupSecretParamsLen: u32, + profileKey: *const u8, + profileKeyLen: u32, + uuid: *const u8, + uuidLen: u32, + profileKeyCiphertextOut: *mut u8, + profileKeyCiphertextLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params: &[u8] = + unsafe { slice::from_raw_parts(groupSecretParams, groupSecretParamsLen as usize) }; + let profile_key: &[u8] = + unsafe { slice::from_raw_parts(profileKey, profileKeyLen as usize) }; + let uuid: &[u8] = unsafe { slice::from_raw_parts(uuid, uuidLen as usize) }; + let profile_key_ciphertext: &mut [u8] = unsafe { + slice::from_raw_parts_mut(profileKeyCiphertextOut, profileKeyCiphertextLen as usize) + }; + + simpleapi::GroupSecretParams_encryptProfileKey( + group_secret_params, + profile_key, + uuid, + profile_key_ciphertext, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupSecretParams_decryptProfileKey( + groupSecretParams: *const u8, + groupSecretParamsLen: u32, + profileKeyCiphertext: *const u8, + profileKeyCiphertextLen: u32, + uuid: *const u8, + uuidLen: u32, + profileKeyOut: *mut u8, + profileKeyLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params: &[u8] = + unsafe { slice::from_raw_parts(groupSecretParams, groupSecretParamsLen as usize) }; + let profile_key_ciphertext: &[u8] = unsafe { + slice::from_raw_parts(profileKeyCiphertext, profileKeyCiphertextLen as usize) + }; + let uuid: &[u8] = unsafe { slice::from_raw_parts(uuid, uuidLen as usize) }; + let profile_key: &mut [u8] = + unsafe { slice::from_raw_parts_mut(profileKeyOut, profileKeyLen as usize) }; + + simpleapi::GroupSecretParams_decryptProfileKey( + group_secret_params, + profile_key_ciphertext, + uuid, + profile_key, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupSecretParams_encryptBlobDeterministic( + groupSecretParams: *const u8, + groupSecretParamsLen: u32, + randomness: *const u8, + randomnessLen: u32, + plaintext: *const u8, + plaintextLen: u32, + blobCiphertextOut: *mut u8, + blobCiphertextLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params: &[u8] = + unsafe { slice::from_raw_parts(groupSecretParams, groupSecretParamsLen as usize) }; + let randomness: &[u8] = + unsafe { slice::from_raw_parts(randomness, randomnessLen as usize) }; + let plaintext: &[u8] = unsafe { slice::from_raw_parts(plaintext, plaintextLen as usize) }; + let blob_ciphertext: &mut [u8] = + unsafe { slice::from_raw_parts_mut(blobCiphertextOut, blobCiphertextLen as usize) }; + + simpleapi::GroupSecretParams_encryptBlobDeterministic( + group_secret_params, + randomness, + plaintext, + blob_ciphertext, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupSecretParams_decryptBlob( + groupSecretParams: *const u8, + groupSecretParamsLen: u32, + blobCiphertext: *const u8, + blobCiphertextLen: u32, + plaintextOut: *mut u8, + plaintextLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params: &[u8] = + unsafe { slice::from_raw_parts(groupSecretParams, groupSecretParamsLen as usize) }; + let blob_ciphertext: &[u8] = + unsafe { slice::from_raw_parts(blobCiphertext, blobCiphertextLen as usize) }; + let plaintext: &mut [u8] = + unsafe { slice::from_raw_parts_mut(plaintextOut, plaintextLen as usize) }; + + simpleapi::GroupSecretParams_decryptBlob(group_secret_params, blob_ciphertext, plaintext) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerSecretParams_generateDeterministic( + randomness: *const u8, + randomnessLen: u32, + serverSecretParamsOut: *mut u8, + serverSecretParamsLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let randomness: &[u8] = + unsafe { slice::from_raw_parts(randomness, randomnessLen as usize) }; + let server_secret_params: &mut [u8] = unsafe { + slice::from_raw_parts_mut(serverSecretParamsOut, serverSecretParamsLen as usize) + }; + + simpleapi::ServerSecretParams_generateDeterministic(randomness, server_secret_params) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerSecretParams_checkValidContents( + serverSecretParams: *const u8, + serverSecretParamsLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params: &[u8] = + unsafe { slice::from_raw_parts(serverSecretParams, serverSecretParamsLen as usize) }; + + simpleapi::ServerSecretParams_checkValidContents(server_secret_params) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerSecretParams_getPublicParams( + serverSecretParams: *const u8, + serverSecretParamsLen: u32, + serverPublicParamsOut: *mut u8, + serverPublicParamsLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params: &[u8] = + unsafe { slice::from_raw_parts(serverSecretParams, serverSecretParamsLen as usize) }; + let server_public_params: &mut [u8] = unsafe { + slice::from_raw_parts_mut(serverPublicParamsOut, serverPublicParamsLen as usize) + }; + + simpleapi::ServerSecretParams_getPublicParams(server_secret_params, server_public_params) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerSecretParams_signDeterministic( + serverSecretParams: *const u8, + serverSecretParamsLen: u32, + randomness: *const u8, + randomnessLen: u32, + message: *const u8, + messageLen: u32, + notarySignatureOut: *mut u8, + notarySignatureLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params: &[u8] = + unsafe { slice::from_raw_parts(serverSecretParams, serverSecretParamsLen as usize) }; + let randomness: &[u8] = + unsafe { slice::from_raw_parts(randomness, randomnessLen as usize) }; + let message: &[u8] = unsafe { slice::from_raw_parts(message, messageLen as usize) }; + let notary_signature: &mut [u8] = + unsafe { slice::from_raw_parts_mut(notarySignatureOut, notarySignatureLen as usize) }; + + simpleapi::ServerSecretParams_signDeterministic( + server_secret_params, + randomness, + message, + notary_signature, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerPublicParams_receiveAuthCredential( + serverPublicParams: *const u8, + serverPublicParamsLen: u32, + uuid: *const u8, + uuidLen: u32, + redemptionTime: u32, + authCredentialResponse: *const u8, + authCredentialResponseLen: u32, + authCredentialOut: *mut u8, + authCredentialLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params: &[u8] = + unsafe { slice::from_raw_parts(serverPublicParams, serverPublicParamsLen as usize) }; + let uuid: &[u8] = unsafe { slice::from_raw_parts(uuid, uuidLen as usize) }; + let redemption_time = redemptionTime as u32; + let auth_credential_response: &[u8] = unsafe { + slice::from_raw_parts(authCredentialResponse, authCredentialResponseLen as usize) + }; + let auth_credential: &mut [u8] = + unsafe { slice::from_raw_parts_mut(authCredentialOut, authCredentialLen as usize) }; + + simpleapi::ServerPublicParams_receiveAuthCredential( + server_public_params, + uuid, + redemption_time, + auth_credential_response, + auth_credential, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerPublicParams_createAuthCredentialPresentationDeterministic( + serverPublicParams: *const u8, + serverPublicParamsLen: u32, + randomness: *const u8, + randomnessLen: u32, + groupSecretParams: *const u8, + groupSecretParamsLen: u32, + authCredential: *const u8, + authCredentialLen: u32, + authCredentialPresentationOut: *mut u8, + authCredentialPresentationLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params: &[u8] = + unsafe { slice::from_raw_parts(serverPublicParams, serverPublicParamsLen as usize) }; + let randomness: &[u8] = + unsafe { slice::from_raw_parts(randomness, randomnessLen as usize) }; + let group_secret_params: &[u8] = + unsafe { slice::from_raw_parts(groupSecretParams, groupSecretParamsLen as usize) }; + let auth_credential: &[u8] = + unsafe { slice::from_raw_parts(authCredential, authCredentialLen as usize) }; + let auth_credential_presentation: &mut [u8] = unsafe { + slice::from_raw_parts_mut( + authCredentialPresentationOut, + authCredentialPresentationLen as usize, + ) + }; + + simpleapi::ServerPublicParams_createAuthCredentialPresentationDeterministic( + server_public_params, + randomness, + group_secret_params, + auth_credential, + auth_credential_presentation, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerPublicParams_createProfileKeyCredentialRequestContextDeterministic( + serverPublicParams: *const u8, + serverPublicParamsLen: u32, + randomness: *const u8, + randomnessLen: u32, + uuid: *const u8, + uuidLen: u32, + profileKey: *const u8, + profileKeyLen: u32, + profileKeyCredentialRequestContextOut: *mut u8, + profileKeyCredentialRequestContextLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params: &[u8] = + unsafe { slice::from_raw_parts(serverPublicParams, serverPublicParamsLen as usize) }; + let randomness: &[u8] = + unsafe { slice::from_raw_parts(randomness, randomnessLen as usize) }; + let uuid: &[u8] = unsafe { slice::from_raw_parts(uuid, uuidLen as usize) }; + let profile_key: &[u8] = + unsafe { slice::from_raw_parts(profileKey, profileKeyLen as usize) }; + let profile_key_credential_request_context: &mut [u8] = unsafe { + slice::from_raw_parts_mut( + profileKeyCredentialRequestContextOut, + profileKeyCredentialRequestContextLen as usize, + ) + }; + + simpleapi::ServerPublicParams_createProfileKeyCredentialRequestContextDeterministic( + server_public_params, + randomness, + uuid, + profile_key, + profile_key_credential_request_context, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerPublicParams_receiveProfileKeyCredential( + serverPublicParams: *const u8, + serverPublicParamsLen: u32, + profileKeyCredentialRequestContext: *const u8, + profileKeyCredentialRequestContextLen: u32, + profileKeyCredentialResponse: *const u8, + profileKeyCredentialResponseLen: u32, + profileKeyCredentialOut: *mut u8, + profileKeyCredentialLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params: &[u8] = + unsafe { slice::from_raw_parts(serverPublicParams, serverPublicParamsLen as usize) }; + let profile_key_credential_request_context: &[u8] = unsafe { + slice::from_raw_parts( + profileKeyCredentialRequestContext, + profileKeyCredentialRequestContextLen as usize, + ) + }; + let profile_key_credential_response: &[u8] = unsafe { + slice::from_raw_parts( + profileKeyCredentialResponse, + profileKeyCredentialResponseLen as usize, + ) + }; + let profile_key_credential: &mut [u8] = unsafe { + slice::from_raw_parts_mut(profileKeyCredentialOut, profileKeyCredentialLen as usize) + }; + + simpleapi::ServerPublicParams_receiveProfileKeyCredential( + server_public_params, + profile_key_credential_request_context, + profile_key_credential_response, + profile_key_credential, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerPublicParams_createProfileKeyCredentialPresentationDeterministic( + serverPublicParams: *const u8, + serverPublicParamsLen: u32, + randomness: *const u8, + randomnessLen: u32, + groupSecretParams: *const u8, + groupSecretParamsLen: u32, + profileKeyCredential: *const u8, + profileKeyCredentialLen: u32, + profileKeyCredentialPresentationOut: *mut u8, + profileKeyCredentialPresentationLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params: &[u8] = + unsafe { slice::from_raw_parts(serverPublicParams, serverPublicParamsLen as usize) }; + let randomness: &[u8] = + unsafe { slice::from_raw_parts(randomness, randomnessLen as usize) }; + let group_secret_params: &[u8] = + unsafe { slice::from_raw_parts(groupSecretParams, groupSecretParamsLen as usize) }; + let profile_key_credential: &[u8] = unsafe { + slice::from_raw_parts(profileKeyCredential, profileKeyCredentialLen as usize) + }; + let profile_key_credential_presentation: &mut [u8] = unsafe { + slice::from_raw_parts_mut( + profileKeyCredentialPresentationOut, + profileKeyCredentialPresentationLen as usize, + ) + }; + + simpleapi::ServerPublicParams_createProfileKeyCredentialPresentationDeterministic( + server_public_params, + randomness, + group_secret_params, + profile_key_credential, + profile_key_credential_presentation, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerSecretParams_issueAuthCredentialDeterministic( + serverSecretParams: *const u8, + serverSecretParamsLen: u32, + randomness: *const u8, + randomnessLen: u32, + uuid: *const u8, + uuidLen: u32, + redemptionTime: u32, + authCredentialResponseOut: *mut u8, + authCredentialResponseLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params: &[u8] = + unsafe { slice::from_raw_parts(serverSecretParams, serverSecretParamsLen as usize) }; + let randomness: &[u8] = + unsafe { slice::from_raw_parts(randomness, randomnessLen as usize) }; + let uuid: &[u8] = unsafe { slice::from_raw_parts(uuid, uuidLen as usize) }; + let redemption_time = redemptionTime as u32; + let auth_credential_response: &mut [u8] = unsafe { + slice::from_raw_parts_mut( + authCredentialResponseOut, + authCredentialResponseLen as usize, + ) + }; + + simpleapi::ServerSecretParams_issueAuthCredentialDeterministic( + server_secret_params, + randomness, + uuid, + redemption_time, + auth_credential_response, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerSecretParams_verifyAuthCredentialPresentation( + serverSecretParams: *const u8, + serverSecretParamsLen: u32, + groupPublicParams: *const u8, + groupPublicParamsLen: u32, + authCredentialPresentation: *const u8, + authCredentialPresentationLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params: &[u8] = + unsafe { slice::from_raw_parts(serverSecretParams, serverSecretParamsLen as usize) }; + let group_public_params: &[u8] = + unsafe { slice::from_raw_parts(groupPublicParams, groupPublicParamsLen as usize) }; + let auth_credential_presentation: &[u8] = unsafe { + slice::from_raw_parts( + authCredentialPresentation, + authCredentialPresentationLen as usize, + ) + }; + + simpleapi::ServerSecretParams_verifyAuthCredentialPresentation( + server_secret_params, + group_public_params, + auth_credential_presentation, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerSecretParams_issueProfileKeyCredentialDeterministic( + serverSecretParams: *const u8, + serverSecretParamsLen: u32, + randomness: *const u8, + randomnessLen: u32, + profileKeyCredentialRequest: *const u8, + profileKeyCredentialRequestLen: u32, + uuid: *const u8, + uuidLen: u32, + profileKeyCommitment: *const u8, + profileKeyCommitmentLen: u32, + profileKeyCredentialResponseOut: *mut u8, + profileKeyCredentialResponseLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params: &[u8] = + unsafe { slice::from_raw_parts(serverSecretParams, serverSecretParamsLen as usize) }; + let randomness: &[u8] = + unsafe { slice::from_raw_parts(randomness, randomnessLen as usize) }; + let profile_key_credential_request: &[u8] = unsafe { + slice::from_raw_parts( + profileKeyCredentialRequest, + profileKeyCredentialRequestLen as usize, + ) + }; + let uuid: &[u8] = unsafe { slice::from_raw_parts(uuid, uuidLen as usize) }; + let profile_key_commitment: &[u8] = unsafe { + slice::from_raw_parts(profileKeyCommitment, profileKeyCommitmentLen as usize) + }; + let profile_key_credential_response: &mut [u8] = unsafe { + slice::from_raw_parts_mut( + profileKeyCredentialResponseOut, + profileKeyCredentialResponseLen as usize, + ) + }; + + simpleapi::ServerSecretParams_issueProfileKeyCredentialDeterministic( + server_secret_params, + randomness, + profile_key_credential_request, + uuid, + profile_key_commitment, + profile_key_credential_response, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerSecretParams_verifyProfileKeyCredentialPresentation( + serverSecretParams: *const u8, + serverSecretParamsLen: u32, + groupPublicParams: *const u8, + groupPublicParamsLen: u32, + profileKeyCredentialPresentation: *const u8, + profileKeyCredentialPresentationLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params: &[u8] = + unsafe { slice::from_raw_parts(serverSecretParams, serverSecretParamsLen as usize) }; + let group_public_params: &[u8] = + unsafe { slice::from_raw_parts(groupPublicParams, groupPublicParamsLen as usize) }; + let profile_key_credential_presentation: &[u8] = unsafe { + slice::from_raw_parts( + profileKeyCredentialPresentation, + profileKeyCredentialPresentationLen as usize, + ) + }; + + simpleapi::ServerSecretParams_verifyProfileKeyCredentialPresentation( + server_secret_params, + group_public_params, + profile_key_credential_presentation, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupPublicParams_checkValidContents( + groupPublicParams: *const u8, + groupPublicParamsLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_public_params: &[u8] = + unsafe { slice::from_raw_parts(groupPublicParams, groupPublicParamsLen as usize) }; + + simpleapi::GroupPublicParams_checkValidContents(group_public_params) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_GroupPublicParams_getGroupIdentifier( + groupPublicParams: *const u8, + groupPublicParamsLen: u32, + groupIdentifierOut: *mut u8, + groupIdentifierLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_public_params: &[u8] = + unsafe { slice::from_raw_parts(groupPublicParams, groupPublicParamsLen as usize) }; + let group_identifier: &mut [u8] = + unsafe { slice::from_raw_parts_mut(groupIdentifierOut, groupIdentifierLen as usize) }; + + simpleapi::GroupPublicParams_getGroupIdentifier(group_public_params, group_identifier) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerPublicParams_checkValidContents( + serverPublicParams: *const u8, + serverPublicParamsLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params: &[u8] = + unsafe { slice::from_raw_parts(serverPublicParams, serverPublicParamsLen as usize) }; + + simpleapi::ServerPublicParams_checkValidContents(server_public_params) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ServerPublicParams_verifySignature( + serverPublicParams: *const u8, + serverPublicParamsLen: u32, + message: *const u8, + messageLen: u32, + notarySignature: *const u8, + notarySignatureLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params: &[u8] = + unsafe { slice::from_raw_parts(serverPublicParams, serverPublicParamsLen as usize) }; + let message: &[u8] = unsafe { slice::from_raw_parts(message, messageLen as usize) }; + let notary_signature: &[u8] = + unsafe { slice::from_raw_parts(notarySignature, notarySignatureLen as usize) }; + + simpleapi::ServerPublicParams_verifySignature( + server_public_params, + message, + notary_signature, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_AuthCredentialResponse_checkValidContents( + authCredentialResponse: *const u8, + authCredentialResponseLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let auth_credential_response: &[u8] = unsafe { + slice::from_raw_parts(authCredentialResponse, authCredentialResponseLen as usize) + }; + + simpleapi::AuthCredentialResponse_checkValidContents(auth_credential_response) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_AuthCredential_checkValidContents( + authCredential: *const u8, + authCredentialLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let auth_credential: &[u8] = + unsafe { slice::from_raw_parts(authCredential, authCredentialLen as usize) }; + + simpleapi::AuthCredential_checkValidContents(auth_credential) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_AuthCredentialPresentation_checkValidContents( + authCredentialPresentation: *const u8, + authCredentialPresentationLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let auth_credential_presentation: &[u8] = unsafe { + slice::from_raw_parts( + authCredentialPresentation, + authCredentialPresentationLen as usize, + ) + }; + + simpleapi::AuthCredentialPresentation_checkValidContents(auth_credential_presentation) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_AuthCredentialPresentation_getUuidCiphertext( + authCredentialPresentation: *const u8, + authCredentialPresentationLen: u32, + uuidCiphertextOut: *mut u8, + uuidCiphertextLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let auth_credential_presentation: &[u8] = unsafe { + slice::from_raw_parts( + authCredentialPresentation, + authCredentialPresentationLen as usize, + ) + }; + let uuid_ciphertext: &mut [u8] = + unsafe { slice::from_raw_parts_mut(uuidCiphertextOut, uuidCiphertextLen as usize) }; + + simpleapi::AuthCredentialPresentation_getUuidCiphertext( + auth_credential_presentation, + uuid_ciphertext, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_AuthCredentialPresentation_getRedemptionTime( + authCredentialPresentation: *const u8, + authCredentialPresentationLen: u32, + redemptionTimeOut: *mut u8, + redemptionTimeLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let auth_credential_presentation: &[u8] = unsafe { + slice::from_raw_parts( + authCredentialPresentation, + authCredentialPresentationLen as usize, + ) + }; + let redemption_time: &mut [u8] = + unsafe { slice::from_raw_parts_mut(redemptionTimeOut, redemptionTimeLen as usize) }; + + simpleapi::AuthCredentialPresentation_getRedemptionTime( + auth_credential_presentation, + redemption_time, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ProfileKeyCredentialRequestContext_checkValidContents( + profileKeyCredentialRequestContext: *const u8, + profileKeyCredentialRequestContextLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_request_context: &[u8] = unsafe { + slice::from_raw_parts( + profileKeyCredentialRequestContext, + profileKeyCredentialRequestContextLen as usize, + ) + }; + + simpleapi::ProfileKeyCredentialRequestContext_checkValidContents( + profile_key_credential_request_context, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ProfileKeyCredentialRequestContext_getRequest( + profileKeyCredentialRequestContext: *const u8, + profileKeyCredentialRequestContextLen: u32, + profileKeyCredentialRequestOut: *mut u8, + profileKeyCredentialRequestLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_request_context: &[u8] = unsafe { + slice::from_raw_parts( + profileKeyCredentialRequestContext, + profileKeyCredentialRequestContextLen as usize, + ) + }; + let profile_key_credential_request: &mut [u8] = unsafe { + slice::from_raw_parts_mut( + profileKeyCredentialRequestOut, + profileKeyCredentialRequestLen as usize, + ) + }; + + simpleapi::ProfileKeyCredentialRequestContext_getRequest( + profile_key_credential_request_context, + profile_key_credential_request, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ProfileKeyCredentialRequest_checkValidContents( + profileKeyCredentialRequest: *const u8, + profileKeyCredentialRequestLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_request: &[u8] = unsafe { + slice::from_raw_parts( + profileKeyCredentialRequest, + profileKeyCredentialRequestLen as usize, + ) + }; + + simpleapi::ProfileKeyCredentialRequest_checkValidContents(profile_key_credential_request) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ProfileKeyCredentialResponse_checkValidContents( + profileKeyCredentialResponse: *const u8, + profileKeyCredentialResponseLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_response: &[u8] = unsafe { + slice::from_raw_parts( + profileKeyCredentialResponse, + profileKeyCredentialResponseLen as usize, + ) + }; + + simpleapi::ProfileKeyCredentialResponse_checkValidContents(profile_key_credential_response) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ProfileKeyCredential_checkValidContents( + profileKeyCredential: *const u8, + profileKeyCredentialLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential: &[u8] = unsafe { + slice::from_raw_parts(profileKeyCredential, profileKeyCredentialLen as usize) + }; + + simpleapi::ProfileKeyCredential_checkValidContents(profile_key_credential) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ProfileKeyCredentialPresentation_checkValidContents( + profileKeyCredentialPresentation: *const u8, + profileKeyCredentialPresentationLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_presentation: &[u8] = unsafe { + slice::from_raw_parts( + profileKeyCredentialPresentation, + profileKeyCredentialPresentationLen as usize, + ) + }; + + simpleapi::ProfileKeyCredentialPresentation_checkValidContents( + profile_key_credential_presentation, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ProfileKeyCredentialPresentation_getUuidCiphertext( + profileKeyCredentialPresentation: *const u8, + profileKeyCredentialPresentationLen: u32, + uuidCiphertextOut: *mut u8, + uuidCiphertextLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_presentation: &[u8] = unsafe { + slice::from_raw_parts( + profileKeyCredentialPresentation, + profileKeyCredentialPresentationLen as usize, + ) + }; + let uuid_ciphertext: &mut [u8] = + unsafe { slice::from_raw_parts_mut(uuidCiphertextOut, uuidCiphertextLen as usize) }; + + simpleapi::ProfileKeyCredentialPresentation_getUuidCiphertext( + profile_key_credential_presentation, + uuid_ciphertext, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ProfileKeyCredentialPresentation_getProfileKeyCiphertext( + profileKeyCredentialPresentation: *const u8, + profileKeyCredentialPresentationLen: u32, + profileKeyCiphertextOut: *mut u8, + profileKeyCiphertextLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_presentation: &[u8] = unsafe { + slice::from_raw_parts( + profileKeyCredentialPresentation, + profileKeyCredentialPresentationLen as usize, + ) + }; + let profile_key_ciphertext: &mut [u8] = unsafe { + slice::from_raw_parts_mut(profileKeyCiphertextOut, profileKeyCiphertextLen as usize) + }; + + simpleapi::ProfileKeyCredentialPresentation_getProfileKeyCiphertext( + profile_key_credential_presentation, + profile_key_ciphertext, + ) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_UuidCiphertext_checkValidContents( + uuidCiphertext: *const u8, + uuidCiphertextLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let uuid_ciphertext: &[u8] = + unsafe { slice::from_raw_parts(uuidCiphertext, uuidCiphertextLen as usize) }; + + simpleapi::UuidCiphertext_checkValidContents(uuid_ciphertext) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_ProfileKeyCiphertext_checkValidContents( + profileKeyCiphertext: *const u8, + profileKeyCiphertextLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_ciphertext: &[u8] = unsafe { + slice::from_raw_parts(profileKeyCiphertext, profileKeyCiphertextLen as usize) + }; + + simpleapi::ProfileKeyCiphertext_checkValidContents(profile_key_ciphertext) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_Randomness_checkValidContents( + randomness: *const u8, + randomnessLen: u32, +) -> i32 { + let result = panic::catch_unwind(|| { + let randomness: &[u8] = + unsafe { slice::from_raw_parts(randomness, randomnessLen as usize) }; + + simpleapi::Randomness_checkValidContents(randomness) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "C" fn FFI_Uuid_checkValidContents(uuid: *const u8, uuidLen: u32) -> i32 { + let result = panic::catch_unwind(|| { + let uuid: &[u8] = unsafe { slice::from_raw_parts(uuid, uuidLen as usize) }; + + simpleapi::Uuid_checkValidContents(uuid) + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/ffi/ffiapijava.rs b/net/gurk-rs/files/vendor/zkgroup/src/ffi/ffiapijava.rs new file mode 100644 index 0000000..03f0fcd --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/ffi/ffiapijava.rs @@ -0,0 +1,1563 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +// Generated by zkgroup/codegen/codegen.py - do not edit + +#![allow(non_snake_case)] + +use std::panic; + +use crate::ffi::constants::*; + +extern crate jni; + +use super::simpleapi; + +use jni::sys::jint; + +// This is the interface to the JVM that we'll +// call the majority of our methods on. +use jni::JNIEnv; + +// These objects are what you should use as arguments to your native function. +// They carry extra lifetime information to prevent them escaping this context +// and getting used after being GC'd. +use jni::objects::JClass; + +// This is just a pointer. We'll be returning it from our function. +// We can't return one of the objects with lifetime information because the +// lifetime checker won't let us. +use jni::sys::jbyteArray; + +fn u8toi8(input: Vec) -> Vec { + let mut out: Vec = Default::default(); + for &i in &input { + out.push(i as i8); + } + out +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyGetCommitmentJNI( + env: JNIEnv, + _class: JClass, + profileKey: jbyteArray, + uuid: jbyteArray, + profileKeyCommitmentOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key = env.convert_byte_array(profileKey).unwrap(); + let uuid = env.convert_byte_array(uuid).unwrap(); + let mut profile_key_commitment: Vec = + vec![0; env.get_array_length(profileKeyCommitmentOut).unwrap() as usize]; + + let ffi_return = + simpleapi::ProfileKey_getCommitment(&profile_key, &uuid, &mut profile_key_commitment); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region( + profileKeyCommitmentOut, + 0, + &u8toi8(profile_key_commitment)[..], + ) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyGetProfileKeyVersionJNI( + env: JNIEnv, + _class: JClass, + profileKey: jbyteArray, + uuid: jbyteArray, + profileKeyVersionOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key = env.convert_byte_array(profileKey).unwrap(); + let uuid = env.convert_byte_array(uuid).unwrap(); + let mut profile_key_version: Vec = + vec![0; env.get_array_length(profileKeyVersionOut).unwrap() as usize]; + + let ffi_return = simpleapi::ProfileKey_getProfileKeyVersion( + &profile_key, + &uuid, + &mut profile_key_version, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(profileKeyVersionOut, 0, &u8toi8(profile_key_version)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyCommitmentCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + profileKeyCommitment: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_commitment = env.convert_byte_array(profileKeyCommitment).unwrap(); + + let ffi_return = + simpleapi::ProfileKeyCommitment_checkValidContents(&profile_key_commitment); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupSecretParamsGenerateDeterministicJNI( + env: JNIEnv, + _class: JClass, + randomness: jbyteArray, + groupSecretParamsOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let randomness = env.convert_byte_array(randomness).unwrap(); + let mut group_secret_params: Vec = + vec![0; env.get_array_length(groupSecretParamsOut).unwrap() as usize]; + + let ffi_return = simpleapi::GroupSecretParams_generateDeterministic( + &randomness, + &mut group_secret_params, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(groupSecretParamsOut, 0, &u8toi8(group_secret_params)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupSecretParamsDeriveFromMasterKeyJNI( + env: JNIEnv, + _class: JClass, + groupMasterKey: jbyteArray, + groupSecretParamsOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_master_key = env.convert_byte_array(groupMasterKey).unwrap(); + let mut group_secret_params: Vec = + vec![0; env.get_array_length(groupSecretParamsOut).unwrap() as usize]; + + let ffi_return = simpleapi::GroupSecretParams_deriveFromMasterKey( + &group_master_key, + &mut group_secret_params, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(groupSecretParamsOut, 0, &u8toi8(group_secret_params)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupSecretParamsCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + groupSecretParams: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params = env.convert_byte_array(groupSecretParams).unwrap(); + + let ffi_return = simpleapi::GroupSecretParams_checkValidContents(&group_secret_params); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupSecretParamsGetMasterKeyJNI( + env: JNIEnv, + _class: JClass, + groupSecretParams: jbyteArray, + groupMasterKeyOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params = env.convert_byte_array(groupSecretParams).unwrap(); + let mut group_master_key: Vec = + vec![0; env.get_array_length(groupMasterKeyOut).unwrap() as usize]; + + let ffi_return = + simpleapi::GroupSecretParams_getMasterKey(&group_secret_params, &mut group_master_key); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(groupMasterKeyOut, 0, &u8toi8(group_master_key)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupSecretParamsGetPublicParamsJNI( + env: JNIEnv, + _class: JClass, + groupSecretParams: jbyteArray, + groupPublicParamsOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params = env.convert_byte_array(groupSecretParams).unwrap(); + let mut group_public_params: Vec = + vec![0; env.get_array_length(groupPublicParamsOut).unwrap() as usize]; + + let ffi_return = simpleapi::GroupSecretParams_getPublicParams( + &group_secret_params, + &mut group_public_params, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(groupPublicParamsOut, 0, &u8toi8(group_public_params)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupSecretParamsEncryptUuidJNI( + env: JNIEnv, + _class: JClass, + groupSecretParams: jbyteArray, + uuid: jbyteArray, + uuidCiphertextOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params = env.convert_byte_array(groupSecretParams).unwrap(); + let uuid = env.convert_byte_array(uuid).unwrap(); + let mut uuid_ciphertext: Vec = + vec![0; env.get_array_length(uuidCiphertextOut).unwrap() as usize]; + + let ffi_return = simpleapi::GroupSecretParams_encryptUuid( + &group_secret_params, + &uuid, + &mut uuid_ciphertext, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(uuidCiphertextOut, 0, &u8toi8(uuid_ciphertext)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupSecretParamsDecryptUuidJNI( + env: JNIEnv, + _class: JClass, + groupSecretParams: jbyteArray, + uuidCiphertext: jbyteArray, + uuidOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params = env.convert_byte_array(groupSecretParams).unwrap(); + let uuid_ciphertext = env.convert_byte_array(uuidCiphertext).unwrap(); + let mut uuid: Vec = vec![0; env.get_array_length(uuidOut).unwrap() as usize]; + + let ffi_return = simpleapi::GroupSecretParams_decryptUuid( + &group_secret_params, + &uuid_ciphertext, + &mut uuid, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(uuidOut, 0, &u8toi8(uuid)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupSecretParamsEncryptProfileKeyJNI( + env: JNIEnv, + _class: JClass, + groupSecretParams: jbyteArray, + profileKey: jbyteArray, + uuid: jbyteArray, + profileKeyCiphertextOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params = env.convert_byte_array(groupSecretParams).unwrap(); + let profile_key = env.convert_byte_array(profileKey).unwrap(); + let uuid = env.convert_byte_array(uuid).unwrap(); + let mut profile_key_ciphertext: Vec = + vec![0; env.get_array_length(profileKeyCiphertextOut).unwrap() as usize]; + + let ffi_return = simpleapi::GroupSecretParams_encryptProfileKey( + &group_secret_params, + &profile_key, + &uuid, + &mut profile_key_ciphertext, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region( + profileKeyCiphertextOut, + 0, + &u8toi8(profile_key_ciphertext)[..], + ) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupSecretParamsDecryptProfileKeyJNI( + env: JNIEnv, + _class: JClass, + groupSecretParams: jbyteArray, + profileKeyCiphertext: jbyteArray, + uuid: jbyteArray, + profileKeyOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params = env.convert_byte_array(groupSecretParams).unwrap(); + let profile_key_ciphertext = env.convert_byte_array(profileKeyCiphertext).unwrap(); + let uuid = env.convert_byte_array(uuid).unwrap(); + let mut profile_key: Vec = + vec![0; env.get_array_length(profileKeyOut).unwrap() as usize]; + + let ffi_return = simpleapi::GroupSecretParams_decryptProfileKey( + &group_secret_params, + &profile_key_ciphertext, + &uuid, + &mut profile_key, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(profileKeyOut, 0, &u8toi8(profile_key)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupSecretParamsEncryptBlobDeterministicJNI( + env: JNIEnv, + _class: JClass, + groupSecretParams: jbyteArray, + randomness: jbyteArray, + plaintext: jbyteArray, + blobCiphertextOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params = env.convert_byte_array(groupSecretParams).unwrap(); + let randomness = env.convert_byte_array(randomness).unwrap(); + let plaintext = env.convert_byte_array(plaintext).unwrap(); + let mut blob_ciphertext: Vec = + vec![0; env.get_array_length(blobCiphertextOut).unwrap() as usize]; + + let ffi_return = simpleapi::GroupSecretParams_encryptBlobDeterministic( + &group_secret_params, + &randomness, + &plaintext, + &mut blob_ciphertext, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(blobCiphertextOut, 0, &u8toi8(blob_ciphertext)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupSecretParamsDecryptBlobJNI( + env: JNIEnv, + _class: JClass, + groupSecretParams: jbyteArray, + blobCiphertext: jbyteArray, + plaintextOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_secret_params = env.convert_byte_array(groupSecretParams).unwrap(); + let blob_ciphertext = env.convert_byte_array(blobCiphertext).unwrap(); + let mut plaintext: Vec = vec![0; env.get_array_length(plaintextOut).unwrap() as usize]; + + let ffi_return = simpleapi::GroupSecretParams_decryptBlob( + &group_secret_params, + &blob_ciphertext, + &mut plaintext, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(plaintextOut, 0, &u8toi8(plaintext)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverSecretParamsGenerateDeterministicJNI( + env: JNIEnv, + _class: JClass, + randomness: jbyteArray, + serverSecretParamsOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let randomness = env.convert_byte_array(randomness).unwrap(); + let mut server_secret_params: Vec = + vec![0; env.get_array_length(serverSecretParamsOut).unwrap() as usize]; + + let ffi_return = simpleapi::ServerSecretParams_generateDeterministic( + &randomness, + &mut server_secret_params, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(serverSecretParamsOut, 0, &u8toi8(server_secret_params)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverSecretParamsCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + serverSecretParams: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params = env.convert_byte_array(serverSecretParams).unwrap(); + + let ffi_return = simpleapi::ServerSecretParams_checkValidContents(&server_secret_params); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverSecretParamsGetPublicParamsJNI( + env: JNIEnv, + _class: JClass, + serverSecretParams: jbyteArray, + serverPublicParamsOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params = env.convert_byte_array(serverSecretParams).unwrap(); + let mut server_public_params: Vec = + vec![0; env.get_array_length(serverPublicParamsOut).unwrap() as usize]; + + let ffi_return = simpleapi::ServerSecretParams_getPublicParams( + &server_secret_params, + &mut server_public_params, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(serverPublicParamsOut, 0, &u8toi8(server_public_params)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverSecretParamsSignDeterministicJNI( + env: JNIEnv, + _class: JClass, + serverSecretParams: jbyteArray, + randomness: jbyteArray, + message: jbyteArray, + notarySignatureOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params = env.convert_byte_array(serverSecretParams).unwrap(); + let randomness = env.convert_byte_array(randomness).unwrap(); + let message = env.convert_byte_array(message).unwrap(); + let mut notary_signature: Vec = + vec![0; env.get_array_length(notarySignatureOut).unwrap() as usize]; + + let ffi_return = simpleapi::ServerSecretParams_signDeterministic( + &server_secret_params, + &randomness, + &message, + &mut notary_signature, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(notarySignatureOut, 0, &u8toi8(notary_signature)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverPublicParamsReceiveAuthCredentialJNI( + env: JNIEnv, + _class: JClass, + serverPublicParams: jbyteArray, + uuid: jbyteArray, + redemptionTime: jint, + authCredentialResponse: jbyteArray, + authCredentialOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params = env.convert_byte_array(serverPublicParams).unwrap(); + let uuid = env.convert_byte_array(uuid).unwrap(); + let redemption_time = redemptionTime as u32; + let auth_credential_response = env.convert_byte_array(authCredentialResponse).unwrap(); + let mut auth_credential: Vec = + vec![0; env.get_array_length(authCredentialOut).unwrap() as usize]; + + let ffi_return = simpleapi::ServerPublicParams_receiveAuthCredential( + &server_public_params, + &uuid, + redemption_time, + &auth_credential_response, + &mut auth_credential, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(authCredentialOut, 0, &u8toi8(auth_credential)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverPublicParamsCreateAuthCredentialPresentationDeterministicJNI( + env: JNIEnv, + _class: JClass, + serverPublicParams: jbyteArray, + randomness: jbyteArray, + groupSecretParams: jbyteArray, + authCredential: jbyteArray, + authCredentialPresentationOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params = env.convert_byte_array(serverPublicParams).unwrap(); + let randomness = env.convert_byte_array(randomness).unwrap(); + let group_secret_params = env.convert_byte_array(groupSecretParams).unwrap(); + let auth_credential = env.convert_byte_array(authCredential).unwrap(); + let mut auth_credential_presentation: Vec = + vec![0; env.get_array_length(authCredentialPresentationOut).unwrap() as usize]; + + let ffi_return = + simpleapi::ServerPublicParams_createAuthCredentialPresentationDeterministic( + &server_public_params, + &randomness, + &group_secret_params, + &auth_credential, + &mut auth_credential_presentation, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region( + authCredentialPresentationOut, + 0, + &u8toi8(auth_credential_presentation)[..], + ) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverPublicParamsCreateProfileKeyCredentialRequestContextDeterministicJNI( + env: JNIEnv, + _class: JClass, + serverPublicParams: jbyteArray, + randomness: jbyteArray, + uuid: jbyteArray, + profileKey: jbyteArray, + profileKeyCredentialRequestContextOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params = env.convert_byte_array(serverPublicParams).unwrap(); + let randomness = env.convert_byte_array(randomness).unwrap(); + let uuid = env.convert_byte_array(uuid).unwrap(); + let profile_key = env.convert_byte_array(profileKey).unwrap(); + let mut profile_key_credential_request_context: Vec = vec![ + 0; + env.get_array_length(profileKeyCredentialRequestContextOut) + .unwrap() + as usize + ]; + + let ffi_return = + simpleapi::ServerPublicParams_createProfileKeyCredentialRequestContextDeterministic( + &server_public_params, + &randomness, + &uuid, + &profile_key, + &mut profile_key_credential_request_context, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region( + profileKeyCredentialRequestContextOut, + 0, + &u8toi8(profile_key_credential_request_context)[..], + ) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverPublicParamsReceiveProfileKeyCredentialJNI( + env: JNIEnv, + _class: JClass, + serverPublicParams: jbyteArray, + profileKeyCredentialRequestContext: jbyteArray, + profileKeyCredentialResponse: jbyteArray, + profileKeyCredentialOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params = env.convert_byte_array(serverPublicParams).unwrap(); + let profile_key_credential_request_context = env + .convert_byte_array(profileKeyCredentialRequestContext) + .unwrap(); + let profile_key_credential_response = env + .convert_byte_array(profileKeyCredentialResponse) + .unwrap(); + let mut profile_key_credential: Vec = + vec![0; env.get_array_length(profileKeyCredentialOut).unwrap() as usize]; + + let ffi_return = simpleapi::ServerPublicParams_receiveProfileKeyCredential( + &server_public_params, + &profile_key_credential_request_context, + &profile_key_credential_response, + &mut profile_key_credential, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region( + profileKeyCredentialOut, + 0, + &u8toi8(profile_key_credential)[..], + ) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverPublicParamsCreateProfileKeyCredentialPresentationDeterministicJNI( + env: JNIEnv, + _class: JClass, + serverPublicParams: jbyteArray, + randomness: jbyteArray, + groupSecretParams: jbyteArray, + profileKeyCredential: jbyteArray, + profileKeyCredentialPresentationOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params = env.convert_byte_array(serverPublicParams).unwrap(); + let randomness = env.convert_byte_array(randomness).unwrap(); + let group_secret_params = env.convert_byte_array(groupSecretParams).unwrap(); + let profile_key_credential = env.convert_byte_array(profileKeyCredential).unwrap(); + let mut profile_key_credential_presentation: Vec = vec![ + 0; + env.get_array_length(profileKeyCredentialPresentationOut) + .unwrap() + as usize + ]; + + let ffi_return = + simpleapi::ServerPublicParams_createProfileKeyCredentialPresentationDeterministic( + &server_public_params, + &randomness, + &group_secret_params, + &profile_key_credential, + &mut profile_key_credential_presentation, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region( + profileKeyCredentialPresentationOut, + 0, + &u8toi8(profile_key_credential_presentation)[..], + ) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverSecretParamsIssueAuthCredentialDeterministicJNI( + env: JNIEnv, + _class: JClass, + serverSecretParams: jbyteArray, + randomness: jbyteArray, + uuid: jbyteArray, + redemptionTime: jint, + authCredentialResponseOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params = env.convert_byte_array(serverSecretParams).unwrap(); + let randomness = env.convert_byte_array(randomness).unwrap(); + let uuid = env.convert_byte_array(uuid).unwrap(); + let redemption_time = redemptionTime as u32; + let mut auth_credential_response: Vec = + vec![0; env.get_array_length(authCredentialResponseOut).unwrap() as usize]; + + let ffi_return = simpleapi::ServerSecretParams_issueAuthCredentialDeterministic( + &server_secret_params, + &randomness, + &uuid, + redemption_time, + &mut auth_credential_response, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region( + authCredentialResponseOut, + 0, + &u8toi8(auth_credential_response)[..], + ) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverSecretParamsVerifyAuthCredentialPresentationJNI( + env: JNIEnv, + _class: JClass, + serverSecretParams: jbyteArray, + groupPublicParams: jbyteArray, + authCredentialPresentation: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params = env.convert_byte_array(serverSecretParams).unwrap(); + let group_public_params = env.convert_byte_array(groupPublicParams).unwrap(); + let auth_credential_presentation = + env.convert_byte_array(authCredentialPresentation).unwrap(); + + let ffi_return = simpleapi::ServerSecretParams_verifyAuthCredentialPresentation( + &server_secret_params, + &group_public_params, + &auth_credential_presentation, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverSecretParamsIssueProfileKeyCredentialDeterministicJNI( + env: JNIEnv, + _class: JClass, + serverSecretParams: jbyteArray, + randomness: jbyteArray, + profileKeyCredentialRequest: jbyteArray, + uuid: jbyteArray, + profileKeyCommitment: jbyteArray, + profileKeyCredentialResponseOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params = env.convert_byte_array(serverSecretParams).unwrap(); + let randomness = env.convert_byte_array(randomness).unwrap(); + let profile_key_credential_request = + env.convert_byte_array(profileKeyCredentialRequest).unwrap(); + let uuid = env.convert_byte_array(uuid).unwrap(); + let profile_key_commitment = env.convert_byte_array(profileKeyCommitment).unwrap(); + let mut profile_key_credential_response: Vec = vec![ + 0; + env.get_array_length(profileKeyCredentialResponseOut) + .unwrap() as usize + ]; + + let ffi_return = simpleapi::ServerSecretParams_issueProfileKeyCredentialDeterministic( + &server_secret_params, + &randomness, + &profile_key_credential_request, + &uuid, + &profile_key_commitment, + &mut profile_key_credential_response, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region( + profileKeyCredentialResponseOut, + 0, + &u8toi8(profile_key_credential_response)[..], + ) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverSecretParamsVerifyProfileKeyCredentialPresentationJNI( + env: JNIEnv, + _class: JClass, + serverSecretParams: jbyteArray, + groupPublicParams: jbyteArray, + profileKeyCredentialPresentation: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_secret_params = env.convert_byte_array(serverSecretParams).unwrap(); + let group_public_params = env.convert_byte_array(groupPublicParams).unwrap(); + let profile_key_credential_presentation = env + .convert_byte_array(profileKeyCredentialPresentation) + .unwrap(); + + let ffi_return = simpleapi::ServerSecretParams_verifyProfileKeyCredentialPresentation( + &server_secret_params, + &group_public_params, + &profile_key_credential_presentation, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupPublicParamsCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + groupPublicParams: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_public_params = env.convert_byte_array(groupPublicParams).unwrap(); + + let ffi_return = simpleapi::GroupPublicParams_checkValidContents(&group_public_params); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_groupPublicParamsGetGroupIdentifierJNI( + env: JNIEnv, + _class: JClass, + groupPublicParams: jbyteArray, + groupIdentifierOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let group_public_params = env.convert_byte_array(groupPublicParams).unwrap(); + let mut group_identifier: Vec = + vec![0; env.get_array_length(groupIdentifierOut).unwrap() as usize]; + + let ffi_return = simpleapi::GroupPublicParams_getGroupIdentifier( + &group_public_params, + &mut group_identifier, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(groupIdentifierOut, 0, &u8toi8(group_identifier)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverPublicParamsCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + serverPublicParams: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params = env.convert_byte_array(serverPublicParams).unwrap(); + + let ffi_return = simpleapi::ServerPublicParams_checkValidContents(&server_public_params); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_serverPublicParamsVerifySignatureJNI( + env: JNIEnv, + _class: JClass, + serverPublicParams: jbyteArray, + message: jbyteArray, + notarySignature: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let server_public_params = env.convert_byte_array(serverPublicParams).unwrap(); + let message = env.convert_byte_array(message).unwrap(); + let notary_signature = env.convert_byte_array(notarySignature).unwrap(); + + let ffi_return = simpleapi::ServerPublicParams_verifySignature( + &server_public_params, + &message, + ¬ary_signature, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_authCredentialResponseCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + authCredentialResponse: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let auth_credential_response = env.convert_byte_array(authCredentialResponse).unwrap(); + + let ffi_return = + simpleapi::AuthCredentialResponse_checkValidContents(&auth_credential_response); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_authCredentialCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + authCredential: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let auth_credential = env.convert_byte_array(authCredential).unwrap(); + + let ffi_return = simpleapi::AuthCredential_checkValidContents(&auth_credential); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_authCredentialPresentationCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + authCredentialPresentation: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let auth_credential_presentation = + env.convert_byte_array(authCredentialPresentation).unwrap(); + + let ffi_return = + simpleapi::AuthCredentialPresentation_checkValidContents(&auth_credential_presentation); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_authCredentialPresentationGetUuidCiphertextJNI( + env: JNIEnv, + _class: JClass, + authCredentialPresentation: jbyteArray, + uuidCiphertextOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let auth_credential_presentation = + env.convert_byte_array(authCredentialPresentation).unwrap(); + let mut uuid_ciphertext: Vec = + vec![0; env.get_array_length(uuidCiphertextOut).unwrap() as usize]; + + let ffi_return = simpleapi::AuthCredentialPresentation_getUuidCiphertext( + &auth_credential_presentation, + &mut uuid_ciphertext, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(uuidCiphertextOut, 0, &u8toi8(uuid_ciphertext)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_authCredentialPresentationGetRedemptionTimeJNI( + env: JNIEnv, + _class: JClass, + authCredentialPresentation: jbyteArray, + redemptionTimeOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let auth_credential_presentation = + env.convert_byte_array(authCredentialPresentation).unwrap(); + let mut redemption_time: Vec = + vec![0; env.get_array_length(redemptionTimeOut).unwrap() as usize]; + + let ffi_return = simpleapi::AuthCredentialPresentation_getRedemptionTime( + &auth_credential_presentation, + &mut redemption_time, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(redemptionTimeOut, 0, &u8toi8(redemption_time)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyCredentialRequestContextCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + profileKeyCredentialRequestContext: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_request_context = env + .convert_byte_array(profileKeyCredentialRequestContext) + .unwrap(); + + let ffi_return = simpleapi::ProfileKeyCredentialRequestContext_checkValidContents( + &profile_key_credential_request_context, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyCredentialRequestContextGetRequestJNI( + env: JNIEnv, + _class: JClass, + profileKeyCredentialRequestContext: jbyteArray, + profileKeyCredentialRequestOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_request_context = env + .convert_byte_array(profileKeyCredentialRequestContext) + .unwrap(); + let mut profile_key_credential_request: Vec = vec![ + 0; + env.get_array_length(profileKeyCredentialRequestOut) + .unwrap() as usize + ]; + + let ffi_return = simpleapi::ProfileKeyCredentialRequestContext_getRequest( + &profile_key_credential_request_context, + &mut profile_key_credential_request, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region( + profileKeyCredentialRequestOut, + 0, + &u8toi8(profile_key_credential_request)[..], + ) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyCredentialRequestCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + profileKeyCredentialRequest: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_request = + env.convert_byte_array(profileKeyCredentialRequest).unwrap(); + + let ffi_return = simpleapi::ProfileKeyCredentialRequest_checkValidContents( + &profile_key_credential_request, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyCredentialResponseCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + profileKeyCredentialResponse: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_response = env + .convert_byte_array(profileKeyCredentialResponse) + .unwrap(); + + let ffi_return = simpleapi::ProfileKeyCredentialResponse_checkValidContents( + &profile_key_credential_response, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyCredentialCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + profileKeyCredential: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential = env.convert_byte_array(profileKeyCredential).unwrap(); + + let ffi_return = + simpleapi::ProfileKeyCredential_checkValidContents(&profile_key_credential); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyCredentialPresentationCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + profileKeyCredentialPresentation: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_presentation = env + .convert_byte_array(profileKeyCredentialPresentation) + .unwrap(); + + let ffi_return = simpleapi::ProfileKeyCredentialPresentation_checkValidContents( + &profile_key_credential_presentation, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyCredentialPresentationGetUuidCiphertextJNI( + env: JNIEnv, + _class: JClass, + profileKeyCredentialPresentation: jbyteArray, + uuidCiphertextOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_presentation = env + .convert_byte_array(profileKeyCredentialPresentation) + .unwrap(); + let mut uuid_ciphertext: Vec = + vec![0; env.get_array_length(uuidCiphertextOut).unwrap() as usize]; + + let ffi_return = simpleapi::ProfileKeyCredentialPresentation_getUuidCiphertext( + &profile_key_credential_presentation, + &mut uuid_ciphertext, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region(uuidCiphertextOut, 0, &u8toi8(uuid_ciphertext)[..]) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyCredentialPresentationGetProfileKeyCiphertextJNI( + env: JNIEnv, + _class: JClass, + profileKeyCredentialPresentation: jbyteArray, + profileKeyCiphertextOut: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_credential_presentation = env + .convert_byte_array(profileKeyCredentialPresentation) + .unwrap(); + let mut profile_key_ciphertext: Vec = + vec![0; env.get_array_length(profileKeyCiphertextOut).unwrap() as usize]; + + let ffi_return = simpleapi::ProfileKeyCredentialPresentation_getProfileKeyCiphertext( + &profile_key_credential_presentation, + &mut profile_key_ciphertext, + ); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + + env.set_byte_array_region( + profileKeyCiphertextOut, + 0, + &u8toi8(profile_key_ciphertext)[..], + ) + .unwrap(); + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_uuidCiphertextCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + uuidCiphertext: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let uuid_ciphertext = env.convert_byte_array(uuidCiphertext).unwrap(); + + let ffi_return = simpleapi::UuidCiphertext_checkValidContents(&uuid_ciphertext); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_profileKeyCiphertextCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + profileKeyCiphertext: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let profile_key_ciphertext = env.convert_byte_array(profileKeyCiphertext).unwrap(); + + let ffi_return = + simpleapi::ProfileKeyCiphertext_checkValidContents(&profile_key_ciphertext); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_randomnessCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + randomness: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let randomness = env.convert_byte_array(randomness).unwrap(); + + let ffi_return = simpleapi::Randomness_checkValidContents(&randomness); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} + +#[no_mangle] +pub extern "system" fn Java_org_signal_zkgroup_internal_Native_uuidCheckValidContentsJNI( + env: JNIEnv, + _class: JClass, + uuid: jbyteArray, +) -> i32 { + let result = panic::catch_unwind(|| { + let uuid = env.convert_byte_array(uuid).unwrap(); + + let ffi_return = simpleapi::Uuid_checkValidContents(&uuid); + if ffi_return != FFI_RETURN_OK { + return ffi_return; + } + FFI_RETURN_OK + }); + + match result { + Ok(result) => result, + Err(_) => FFI_RETURN_INTERNAL_ERROR, + } +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/ffi/mod.rs b/net/gurk-rs/files/vendor/zkgroup/src/ffi/mod.rs new file mode 100644 index 0000000..aeb4265 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/ffi/mod.rs @@ -0,0 +1,13 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +pub mod constants; + +pub mod ffiapi; + +pub mod ffiapijava; +pub mod simpleapi; diff --git a/net/gurk-rs/files/vendor/zkgroup/src/ffi/simpleapi.rs b/net/gurk-rs/files/vendor/zkgroup/src/ffi/simpleapi.rs new file mode 100644 index 0000000..bd481ab --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/ffi/simpleapi.rs @@ -0,0 +1,901 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +// Generated by zkgroup/codegen/codegen.py - do not edit + +#![allow(non_snake_case)] + +use crate::api; +use crate::common::constants::*; +use crate::common::simple_types; +use crate::ffi::constants::*; + +pub fn ProfileKey_getCommitment( + profileKeyIn: &[u8], + uuidIn: &[u8], + profileKeyCommitmentOut: &mut [u8], +) -> i32 { + let profile_key: api::profiles::ProfileKey = match bincode::deserialize(profileKeyIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let uuid: simple_types::UidBytes = match bincode::deserialize(uuidIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let profile_key_commitment = profile_key.get_commitment(uuid); + profileKeyCommitmentOut.copy_from_slice(&bincode::serialize(&profile_key_commitment).unwrap()); + FFI_RETURN_OK +} + +pub fn ProfileKey_getProfileKeyVersion( + profileKeyIn: &[u8], + uuidIn: &[u8], + profileKeyVersionOut: &mut [u8], +) -> i32 { + let profile_key: api::profiles::ProfileKey = match bincode::deserialize(profileKeyIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let uuid: simple_types::UidBytes = match bincode::deserialize(uuidIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let profile_key_version = profile_key.get_profile_key_version(uuid); + profileKeyVersionOut.copy_from_slice(&bincode::serialize(&profile_key_version).unwrap()); + FFI_RETURN_OK +} + +pub fn ProfileKeyCommitment_checkValidContents(profileKeyCommitmentIn: &[u8]) -> i32 { + let _: api::profiles::ProfileKeyCommitment = match bincode::deserialize(profileKeyCommitmentIn) + { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn GroupSecretParams_generateDeterministic( + randomnessIn: &[u8], + groupSecretParamsOut: &mut [u8], +) -> i32 { + let randomness: simple_types::RandomnessBytes = match bincode::deserialize(randomnessIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let group_secret_params = api::groups::GroupSecretParams::generate(randomness); + groupSecretParamsOut.copy_from_slice(&bincode::serialize(&group_secret_params).unwrap()); + FFI_RETURN_OK +} + +pub fn GroupSecretParams_deriveFromMasterKey( + groupMasterKeyIn: &[u8], + groupSecretParamsOut: &mut [u8], +) -> i32 { + let group_master_key: api::groups::GroupMasterKey = match bincode::deserialize(groupMasterKeyIn) + { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let group_secret_params = + api::groups::GroupSecretParams::derive_from_master_key(group_master_key); + groupSecretParamsOut.copy_from_slice(&bincode::serialize(&group_secret_params).unwrap()); + FFI_RETURN_OK +} + +pub fn GroupSecretParams_checkValidContents(groupSecretParamsIn: &[u8]) -> i32 { + let _: api::groups::GroupSecretParams = match bincode::deserialize(groupSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn GroupSecretParams_getMasterKey( + groupSecretParamsIn: &[u8], + groupMasterKeyOut: &mut [u8], +) -> i32 { + let group_secret_params: api::groups::GroupSecretParams = + match bincode::deserialize(groupSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + let group_master_key = group_secret_params.get_master_key(); + groupMasterKeyOut.copy_from_slice(&bincode::serialize(&group_master_key).unwrap()); + FFI_RETURN_OK +} + +pub fn GroupSecretParams_getPublicParams( + groupSecretParamsIn: &[u8], + groupPublicParamsOut: &mut [u8], +) -> i32 { + let group_secret_params: api::groups::GroupSecretParams = + match bincode::deserialize(groupSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + let group_public_params = group_secret_params.get_public_params(); + groupPublicParamsOut.copy_from_slice(&bincode::serialize(&group_public_params).unwrap()); + FFI_RETURN_OK +} + +pub fn GroupSecretParams_encryptUuid( + groupSecretParamsIn: &[u8], + uuidIn: &[u8], + uuidCiphertextOut: &mut [u8], +) -> i32 { + let group_secret_params: api::groups::GroupSecretParams = + match bincode::deserialize(groupSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let uuid: simple_types::UidBytes = match bincode::deserialize(uuidIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let uuid_ciphertext = group_secret_params.encrypt_uuid(uuid); + uuidCiphertextOut.copy_from_slice(&bincode::serialize(&uuid_ciphertext).unwrap()); + FFI_RETURN_OK +} + +pub fn GroupSecretParams_decryptUuid( + groupSecretParamsIn: &[u8], + uuidCiphertextIn: &[u8], + uuidOut: &mut [u8], +) -> i32 { + let group_secret_params: api::groups::GroupSecretParams = + match bincode::deserialize(groupSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let uuid_ciphertext: api::groups::UuidCiphertext = match bincode::deserialize(uuidCiphertextIn) + { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let uuid = match group_secret_params.decrypt_uuid(uuid_ciphertext) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + uuidOut.copy_from_slice(&bincode::serialize(&uuid).unwrap()); + FFI_RETURN_OK +} + +pub fn GroupSecretParams_encryptProfileKey( + groupSecretParamsIn: &[u8], + profileKeyIn: &[u8], + uuidIn: &[u8], + profileKeyCiphertextOut: &mut [u8], +) -> i32 { + let group_secret_params: api::groups::GroupSecretParams = + match bincode::deserialize(groupSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let profile_key: api::profiles::ProfileKey = match bincode::deserialize(profileKeyIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let uuid: simple_types::UidBytes = match bincode::deserialize(uuidIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let profile_key_ciphertext = group_secret_params.encrypt_profile_key(profile_key, uuid); + profileKeyCiphertextOut.copy_from_slice(&bincode::serialize(&profile_key_ciphertext).unwrap()); + FFI_RETURN_OK +} + +pub fn GroupSecretParams_decryptProfileKey( + groupSecretParamsIn: &[u8], + profileKeyCiphertextIn: &[u8], + uuidIn: &[u8], + profileKeyOut: &mut [u8], +) -> i32 { + let group_secret_params: api::groups::GroupSecretParams = + match bincode::deserialize(groupSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let profile_key_ciphertext: api::groups::ProfileKeyCiphertext = + match bincode::deserialize(profileKeyCiphertextIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let uuid: simple_types::UidBytes = match bincode::deserialize(uuidIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let profile_key = match group_secret_params.decrypt_profile_key(profile_key_ciphertext, uuid) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + profileKeyOut.copy_from_slice(&bincode::serialize(&profile_key).unwrap()); + FFI_RETURN_OK +} + +pub fn GroupSecretParams_encryptBlobDeterministic( + groupSecretParamsIn: &[u8], + randomnessIn: &[u8], + plaintextIn: &[u8], + blobCiphertextOut: &mut [u8], +) -> i32 { + let group_secret_params: api::groups::GroupSecretParams = + match bincode::deserialize(groupSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let randomness: simple_types::RandomnessBytes = match bincode::deserialize(randomnessIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let plaintext = plaintextIn; + let blob_ciphertext = match group_secret_params.encrypt_blob(randomness, plaintext) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + blobCiphertextOut.copy_from_slice(&blob_ciphertext); + FFI_RETURN_OK +} + +pub fn GroupSecretParams_decryptBlob( + groupSecretParamsIn: &[u8], + blobCiphertextIn: &[u8], + plaintextOut: &mut [u8], +) -> i32 { + let group_secret_params: api::groups::GroupSecretParams = + match bincode::deserialize(groupSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + let blob_ciphertext = blobCiphertextIn; + let plaintext = match group_secret_params.decrypt_blob(blob_ciphertext) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + plaintextOut.copy_from_slice(&plaintext); + FFI_RETURN_OK +} + +pub fn ServerSecretParams_generateDeterministic( + randomnessIn: &[u8], + serverSecretParamsOut: &mut [u8], +) -> i32 { + let randomness: simple_types::RandomnessBytes = match bincode::deserialize(randomnessIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let server_secret_params = api::ServerSecretParams::generate(randomness); + serverSecretParamsOut.copy_from_slice(&bincode::serialize(&server_secret_params).unwrap()); + FFI_RETURN_OK +} + +pub fn ServerSecretParams_checkValidContents(serverSecretParamsIn: &[u8]) -> i32 { + let _: api::ServerSecretParams = match bincode::deserialize(serverSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn ServerSecretParams_getPublicParams( + serverSecretParamsIn: &[u8], + serverPublicParamsOut: &mut [u8], +) -> i32 { + let server_secret_params: api::ServerSecretParams = + match bincode::deserialize(serverSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + let server_public_params = server_secret_params.get_public_params(); + serverPublicParamsOut.copy_from_slice(&bincode::serialize(&server_public_params).unwrap()); + FFI_RETURN_OK +} + +pub fn ServerSecretParams_signDeterministic( + serverSecretParamsIn: &[u8], + randomnessIn: &[u8], + messageIn: &[u8], + notarySignatureOut: &mut [u8], +) -> i32 { + let server_secret_params: api::ServerSecretParams = + match bincode::deserialize(serverSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let randomness: simple_types::RandomnessBytes = match bincode::deserialize(randomnessIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let message = messageIn; + let notary_signature = match server_secret_params.sign(randomness, message) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + notarySignatureOut.copy_from_slice(¬ary_signature); + FFI_RETURN_OK +} + +pub fn ServerPublicParams_receiveAuthCredential( + serverPublicParamsIn: &[u8], + uuidIn: &[u8], + redemptionTimeIn: u32, + authCredentialResponseIn: &[u8], + authCredentialOut: &mut [u8], +) -> i32 { + let server_public_params: api::ServerPublicParams = + match bincode::deserialize(serverPublicParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let uuid: simple_types::UidBytes = match bincode::deserialize(uuidIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let redemption_time = redemptionTimeIn; + + let auth_credential_response: api::auth::AuthCredentialResponse = + match bincode::deserialize(authCredentialResponseIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let auth_credential = match server_public_params.receive_auth_credential( + uuid, + redemption_time, + &auth_credential_response, + ) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + authCredentialOut.copy_from_slice(&bincode::serialize(&auth_credential).unwrap()); + FFI_RETURN_OK +} + +pub fn ServerPublicParams_createAuthCredentialPresentationDeterministic( + serverPublicParamsIn: &[u8], + randomnessIn: &[u8], + groupSecretParamsIn: &[u8], + authCredentialIn: &[u8], + authCredentialPresentationOut: &mut [u8], +) -> i32 { + let server_public_params: api::ServerPublicParams = + match bincode::deserialize(serverPublicParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let randomness: simple_types::RandomnessBytes = match bincode::deserialize(randomnessIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let group_secret_params: api::groups::GroupSecretParams = + match bincode::deserialize(groupSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let auth_credential: api::auth::AuthCredential = match bincode::deserialize(authCredentialIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let auth_credential_presentation = server_public_params.create_auth_credential_presentation( + randomness, + group_secret_params, + auth_credential, + ); + authCredentialPresentationOut + .copy_from_slice(&bincode::serialize(&auth_credential_presentation).unwrap()); + FFI_RETURN_OK +} + +pub fn ServerPublicParams_createProfileKeyCredentialRequestContextDeterministic( + serverPublicParamsIn: &[u8], + randomnessIn: &[u8], + uuidIn: &[u8], + profileKeyIn: &[u8], + profileKeyCredentialRequestContextOut: &mut [u8], +) -> i32 { + let server_public_params: api::ServerPublicParams = + match bincode::deserialize(serverPublicParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let randomness: simple_types::RandomnessBytes = match bincode::deserialize(randomnessIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let uuid: simple_types::UidBytes = match bincode::deserialize(uuidIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let profile_key: api::profiles::ProfileKey = match bincode::deserialize(profileKeyIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let profile_key_credential_request_context = server_public_params + .create_profile_key_credential_request_context(randomness, uuid, profile_key); + profileKeyCredentialRequestContextOut + .copy_from_slice(&bincode::serialize(&profile_key_credential_request_context).unwrap()); + FFI_RETURN_OK +} + +pub fn ServerPublicParams_receiveProfileKeyCredential( + serverPublicParamsIn: &[u8], + profileKeyCredentialRequestContextIn: &[u8], + profileKeyCredentialResponseIn: &[u8], + profileKeyCredentialOut: &mut [u8], +) -> i32 { + let server_public_params: api::ServerPublicParams = + match bincode::deserialize(serverPublicParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let profile_key_credential_request_context: api::profiles::ProfileKeyCredentialRequestContext = + match bincode::deserialize(profileKeyCredentialRequestContextIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let profile_key_credential_response: api::profiles::ProfileKeyCredentialResponse = + match bincode::deserialize(profileKeyCredentialResponseIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let profile_key_credential = match server_public_params.receive_profile_key_credential( + &profile_key_credential_request_context, + &profile_key_credential_response, + ) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + profileKeyCredentialOut.copy_from_slice(&bincode::serialize(&profile_key_credential).unwrap()); + FFI_RETURN_OK +} + +pub fn ServerPublicParams_createProfileKeyCredentialPresentationDeterministic( + serverPublicParamsIn: &[u8], + randomnessIn: &[u8], + groupSecretParamsIn: &[u8], + profileKeyCredentialIn: &[u8], + profileKeyCredentialPresentationOut: &mut [u8], +) -> i32 { + let server_public_params: api::ServerPublicParams = + match bincode::deserialize(serverPublicParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let randomness: simple_types::RandomnessBytes = match bincode::deserialize(randomnessIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let group_secret_params: api::groups::GroupSecretParams = + match bincode::deserialize(groupSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let profile_key_credential: api::profiles::ProfileKeyCredential = + match bincode::deserialize(profileKeyCredentialIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let profile_key_credential_presentation = server_public_params + .create_profile_key_credential_presentation( + randomness, + group_secret_params, + profile_key_credential, + ); + profileKeyCredentialPresentationOut + .copy_from_slice(&bincode::serialize(&profile_key_credential_presentation).unwrap()); + FFI_RETURN_OK +} + +pub fn ServerSecretParams_issueAuthCredentialDeterministic( + serverSecretParamsIn: &[u8], + randomnessIn: &[u8], + uuidIn: &[u8], + redemptionTimeIn: u32, + authCredentialResponseOut: &mut [u8], +) -> i32 { + let server_secret_params: api::ServerSecretParams = + match bincode::deserialize(serverSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let randomness: simple_types::RandomnessBytes = match bincode::deserialize(randomnessIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let uuid: simple_types::UidBytes = match bincode::deserialize(uuidIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let redemption_time = redemptionTimeIn; + let auth_credential_response = + server_secret_params.issue_auth_credential(randomness, uuid, redemption_time); + authCredentialResponseOut + .copy_from_slice(&bincode::serialize(&auth_credential_response).unwrap()); + FFI_RETURN_OK +} + +pub fn ServerSecretParams_verifyAuthCredentialPresentation( + serverSecretParamsIn: &[u8], + groupPublicParamsIn: &[u8], + authCredentialPresentationIn: &[u8], +) -> i32 { + let server_secret_params: api::ServerSecretParams = + match bincode::deserialize(serverSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let group_public_params: api::groups::GroupPublicParams = + match bincode::deserialize(groupPublicParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let auth_credential_presentation: api::auth::AuthCredentialPresentation = + match bincode::deserialize(authCredentialPresentationIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + match server_secret_params + .verify_auth_credential_presentation(group_public_params, &auth_credential_presentation) + { + Ok(_) => (), + Err(_) => return FFI_RETURN_INPUT_ERROR, + } + FFI_RETURN_OK +} + +pub fn ServerSecretParams_issueProfileKeyCredentialDeterministic( + serverSecretParamsIn: &[u8], + randomnessIn: &[u8], + profileKeyCredentialRequestIn: &[u8], + uuidIn: &[u8], + profileKeyCommitmentIn: &[u8], + profileKeyCredentialResponseOut: &mut [u8], +) -> i32 { + let server_secret_params: api::ServerSecretParams = + match bincode::deserialize(serverSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let randomness: simple_types::RandomnessBytes = match bincode::deserialize(randomnessIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let profile_key_credential_request: api::profiles::ProfileKeyCredentialRequest = + match bincode::deserialize(profileKeyCredentialRequestIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let uuid: simple_types::UidBytes = match bincode::deserialize(uuidIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let profile_key_commitment: api::profiles::ProfileKeyCommitment = + match bincode::deserialize(profileKeyCommitmentIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + let profile_key_credential_response = match server_secret_params.issue_profile_key_credential( + randomness, + &profile_key_credential_request, + uuid, + profile_key_commitment, + ) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + profileKeyCredentialResponseOut + .copy_from_slice(&bincode::serialize(&profile_key_credential_response).unwrap()); + FFI_RETURN_OK +} + +pub fn ServerSecretParams_verifyProfileKeyCredentialPresentation( + serverSecretParamsIn: &[u8], + groupPublicParamsIn: &[u8], + profileKeyCredentialPresentationIn: &[u8], +) -> i32 { + let server_secret_params: api::ServerSecretParams = + match bincode::deserialize(serverSecretParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + + let group_public_params: api::groups::GroupPublicParams = + match bincode::deserialize(groupPublicParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + let profile_key_credential_presentation: api::profiles::ProfileKeyCredentialPresentation = + match bincode::deserialize(profileKeyCredentialPresentationIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + match server_secret_params.verify_profile_key_credential_presentation( + group_public_params, + &profile_key_credential_presentation, + ) { + Ok(_) => (), + Err(_) => return FFI_RETURN_INPUT_ERROR, + } + FFI_RETURN_OK +} + +pub fn GroupPublicParams_checkValidContents(groupPublicParamsIn: &[u8]) -> i32 { + let _: api::groups::GroupPublicParams = match bincode::deserialize(groupPublicParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn GroupPublicParams_getGroupIdentifier( + groupPublicParamsIn: &[u8], + groupIdentifierOut: &mut [u8], +) -> i32 { + let group_public_params: api::groups::GroupPublicParams = + match bincode::deserialize(groupPublicParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + let group_identifier = group_public_params.get_group_identifier(); + groupIdentifierOut.copy_from_slice(&bincode::serialize(&group_identifier).unwrap()); + FFI_RETURN_OK +} + +pub fn ServerPublicParams_checkValidContents(serverPublicParamsIn: &[u8]) -> i32 { + let _: api::ServerPublicParams = match bincode::deserialize(serverPublicParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn ServerPublicParams_verifySignature( + serverPublicParamsIn: &[u8], + messageIn: &[u8], + notarySignatureIn: &[u8], +) -> i32 { + let server_public_params: api::ServerPublicParams = + match bincode::deserialize(serverPublicParamsIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + let message = messageIn; + let mut notary_signature: simple_types::NotarySignatureBytes = [0u8; SIGNATURE_LEN]; + notary_signature.copy_from_slice(notarySignatureIn); + match server_public_params.verify_signature(message, notary_signature) { + Ok(_) => (), + _ => return FFI_RETURN_INPUT_ERROR, + }; + FFI_RETURN_OK +} + +pub fn AuthCredentialResponse_checkValidContents(authCredentialResponseIn: &[u8]) -> i32 { + let _: api::auth::AuthCredentialResponse = match bincode::deserialize(authCredentialResponseIn) + { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn AuthCredential_checkValidContents(authCredentialIn: &[u8]) -> i32 { + let _: api::auth::AuthCredential = match bincode::deserialize(authCredentialIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn AuthCredentialPresentation_checkValidContents(authCredentialPresentationIn: &[u8]) -> i32 { + let _: api::auth::AuthCredentialPresentation = + match bincode::deserialize(authCredentialPresentationIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn AuthCredentialPresentation_getUuidCiphertext( + authCredentialPresentationIn: &[u8], + uuidCiphertextOut: &mut [u8], +) -> i32 { + let auth_credential_presentation: api::auth::AuthCredentialPresentation = + match bincode::deserialize(authCredentialPresentationIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + let uuid_ciphertext = auth_credential_presentation.get_uuid_ciphertext(); + uuidCiphertextOut.copy_from_slice(&bincode::serialize(&uuid_ciphertext).unwrap()); + FFI_RETURN_OK +} + +pub fn AuthCredentialPresentation_getRedemptionTime( + authCredentialPresentationIn: &[u8], + redemptionTimeOut: &mut [u8], +) -> i32 { + let auth_credential_presentation: api::auth::AuthCredentialPresentation = + match bincode::deserialize(authCredentialPresentationIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + let redemption_time = auth_credential_presentation.get_redemption_time(); + redemptionTimeOut.copy_from_slice(&redemption_time.to_be_bytes()); + FFI_RETURN_OK +} + +pub fn ProfileKeyCredentialRequestContext_checkValidContents( + profileKeyCredentialRequestContextIn: &[u8], +) -> i32 { + let _: api::profiles::ProfileKeyCredentialRequestContext = + match bincode::deserialize(profileKeyCredentialRequestContextIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn ProfileKeyCredentialRequestContext_getRequest( + profileKeyCredentialRequestContextIn: &[u8], + profileKeyCredentialRequestOut: &mut [u8], +) -> i32 { + let profile_key_credential_request_context: api::profiles::ProfileKeyCredentialRequestContext = + match bincode::deserialize(profileKeyCredentialRequestContextIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + let profile_key_credential_request = profile_key_credential_request_context.get_request(); + profileKeyCredentialRequestOut + .copy_from_slice(&bincode::serialize(&profile_key_credential_request).unwrap()); + FFI_RETURN_OK +} + +pub fn ProfileKeyCredentialRequest_checkValidContents(profileKeyCredentialRequestIn: &[u8]) -> i32 { + let _: api::profiles::ProfileKeyCredentialRequest = + match bincode::deserialize(profileKeyCredentialRequestIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn ProfileKeyCredentialResponse_checkValidContents( + profileKeyCredentialResponseIn: &[u8], +) -> i32 { + let _: api::profiles::ProfileKeyCredentialResponse = + match bincode::deserialize(profileKeyCredentialResponseIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn ProfileKeyCredential_checkValidContents(profileKeyCredentialIn: &[u8]) -> i32 { + let _: api::profiles::ProfileKeyCredential = match bincode::deserialize(profileKeyCredentialIn) + { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn ProfileKeyCredentialPresentation_checkValidContents( + profileKeyCredentialPresentationIn: &[u8], +) -> i32 { + let _: api::profiles::ProfileKeyCredentialPresentation = + match bincode::deserialize(profileKeyCredentialPresentationIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn ProfileKeyCredentialPresentation_getUuidCiphertext( + profileKeyCredentialPresentationIn: &[u8], + uuidCiphertextOut: &mut [u8], +) -> i32 { + let profile_key_credential_presentation: api::profiles::ProfileKeyCredentialPresentation = + match bincode::deserialize(profileKeyCredentialPresentationIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + let uuid_ciphertext = profile_key_credential_presentation.get_uuid_ciphertext(); + uuidCiphertextOut.copy_from_slice(&bincode::serialize(&uuid_ciphertext).unwrap()); + FFI_RETURN_OK +} + +pub fn ProfileKeyCredentialPresentation_getProfileKeyCiphertext( + profileKeyCredentialPresentationIn: &[u8], + profileKeyCiphertextOut: &mut [u8], +) -> i32 { + let profile_key_credential_presentation: api::profiles::ProfileKeyCredentialPresentation = + match bincode::deserialize(profileKeyCredentialPresentationIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INTERNAL_ERROR, + }; + let profile_key_ciphertext = profile_key_credential_presentation.get_profile_key_ciphertext(); + profileKeyCiphertextOut.copy_from_slice(&bincode::serialize(&profile_key_ciphertext).unwrap()); + FFI_RETURN_OK +} + +pub fn UuidCiphertext_checkValidContents(uuidCiphertextIn: &[u8]) -> i32 { + let _: api::groups::UuidCiphertext = match bincode::deserialize(uuidCiphertextIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn ProfileKeyCiphertext_checkValidContents(profileKeyCiphertextIn: &[u8]) -> i32 { + let _: api::groups::ProfileKeyCiphertext = match bincode::deserialize(profileKeyCiphertextIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn Randomness_checkValidContents(randomnessIn: &[u8]) -> i32 { + let _: simple_types::RandomnessBytes = match bincode::deserialize(randomnessIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} + +pub fn Uuid_checkValidContents(uuidIn: &[u8]) -> i32 { + let _: simple_types::UidBytes = match bincode::deserialize(uuidIn) { + Ok(result) => result, + Err(_) => return FFI_RETURN_INPUT_ERROR, + }; + + FFI_RETURN_OK +} diff --git a/net/gurk-rs/files/vendor/zkgroup/src/lib.rs b/net/gurk-rs/files/vendor/zkgroup/src/lib.rs new file mode 100644 index 0000000..3ced5d5 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/src/lib.rs @@ -0,0 +1,15 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +pub mod api; +pub mod common; +pub mod crypto; +pub mod ffi; +pub use api::*; +pub use common::constants::*; +pub use common::errors::*; +pub use common::simple_types::*; diff --git a/net/gurk-rs/files/vendor/zkgroup/tests/integration_tests.rs b/net/gurk-rs/files/vendor/zkgroup/tests/integration_tests.rs new file mode 100644 index 0000000..c8632b9 --- /dev/null +++ b/net/gurk-rs/files/vendor/zkgroup/tests/integration_tests.rs @@ -0,0 +1,348 @@ +// +// Copyright (C) 2020 Signal Messenger, LLC. +// All rights reserved. +// +// SPDX-License-Identifier: GPL-3.0-only +// + +#![allow(non_snake_case)] +extern crate zkgroup; + +use curve25519_dalek::ristretto::RistrettoPoint; +use sha2::Sha256; + +#[test] +fn test_lizard() { + let p = RistrettoPoint::lizard_encode::(&zkgroup::common::constants::TEST_ARRAY_16); + let data_out = p.lizard_decode::(); + assert!(data_out.unwrap() == zkgroup::common::constants::TEST_ARRAY_16); +} +pub const AUTH_CREDENTIAL_PRESENTATION_RESULT: [u8; zkgroup::AUTH_CREDENTIAL_PRESENTATION_LEN] = [ + 0x00, 0x0c, 0xde, 0x97, 0x97, 0x37, 0xed, 0x30, 0xbb, 0xeb, 0x16, 0x36, 0x2e, 0x4e, 0x07, 0x69, + 0x45, 0xce, 0x02, 0x06, 0x9f, 0x72, 0x7b, 0x0e, 0xd4, 0xc3, 0xc3, 0x3c, 0x01, 0x1e, 0x82, 0x54, + 0x6e, 0x1c, 0xdf, 0x08, 0x1f, 0xbd, 0xf3, 0x7c, 0x03, 0xa8, 0x51, 0xad, 0x06, 0x0b, 0xdc, 0xbf, + 0x63, 0x78, 0xcb, 0x4c, 0xb1, 0x6d, 0xc3, 0x15, 0x4d, 0x08, 0xde, 0x54, 0x39, 0xb5, 0x32, 0x32, + 0x03, 0x72, 0x9d, 0x18, 0x41, 0xb5, 0x17, 0x03, 0x3a, 0xf2, 0xfd, 0x17, 0x7d, 0x30, 0x49, 0x1c, + 0x13, 0x8a, 0xe7, 0x23, 0x65, 0x57, 0x34, 0xf6, 0xe5, 0xcc, 0x01, 0xc0, 0x06, 0x96, 0xf4, 0xe9, + 0x20, 0x96, 0xd8, 0xc3, 0x3d, 0xf2, 0x6b, 0xa2, 0xa8, 0x20, 0xd4, 0x2e, 0x97, 0x35, 0xd3, 0x0f, + 0x8e, 0xee, 0xf9, 0x6d, 0x39, 0x90, 0x79, 0x07, 0x3c, 0x09, 0x9f, 0x70, 0x35, 0x52, 0x3b, 0xfe, + 0x71, 0x66, 0x38, 0x65, 0x93, 0x19, 0xd3, 0xc3, 0x6a, 0xd3, 0x4c, 0x00, 0xef, 0x88, 0x50, 0xf6, + 0x63, 0xc4, 0xd9, 0x30, 0x30, 0x23, 0x50, 0x74, 0x31, 0x2a, 0x88, 0x78, 0xb6, 0xa5, 0xc5, 0xdf, + 0x4f, 0xbc, 0x7d, 0x32, 0x93, 0x52, 0x78, 0xbf, 0xa5, 0x99, 0x6b, 0x44, 0xab, 0x75, 0xd6, 0xf0, + 0x6f, 0x4c, 0x30, 0xb9, 0x86, 0x40, 0xad, 0x5d, 0xe7, 0x47, 0x42, 0x65, 0x6c, 0x89, 0x77, 0x56, + 0x7d, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xe6, 0x9f, 0x82, 0xad, 0x2d, 0xcb, + 0x49, 0x09, 0x65, 0x0a, 0xc6, 0xb2, 0x57, 0x38, 0x41, 0xaf, 0x56, 0x8f, 0xef, 0x82, 0x2b, 0x32, + 0xb4, 0x5f, 0x62, 0x5a, 0x76, 0x46, 0x91, 0xa7, 0x04, 0xd1, 0x1b, 0x6f, 0x38, 0x52, 0x61, 0x46, + 0x81, 0x17, 0xea, 0xd5, 0x7f, 0xa6, 0x23, 0x33, 0x8e, 0x21, 0xc6, 0x6e, 0xd8, 0x46, 0xab, 0x65, + 0x80, 0x9f, 0xca, 0xc1, 0x58, 0x06, 0x6d, 0x8e, 0x0e, 0x44, 0x40, 0x77, 0xb9, 0x95, 0x40, 0xd8, + 0x86, 0xe7, 0xdc, 0x09, 0x55, 0x5d, 0xd6, 0xfa, 0xea, 0x2c, 0xd3, 0x69, 0x7f, 0x1e, 0x08, 0x9f, + 0x82, 0xd5, 0x4e, 0x5d, 0x0f, 0xe4, 0xa1, 0x85, 0x00, 0x8b, 0x5c, 0xbc, 0x39, 0x79, 0x39, 0x1a, + 0xd7, 0x16, 0x86, 0xbc, 0x03, 0xbe, 0x7b, 0x00, 0xea, 0x7e, 0x42, 0xc0, 0x8d, 0x9f, 0x1d, 0x75, + 0xc3, 0xa5, 0x6c, 0x27, 0xae, 0x24, 0x67, 0xb8, 0x06, 0x36, 0xc0, 0xb5, 0x34, 0x3e, 0xda, 0x7c, + 0xd5, 0x78, 0xba, 0x88, 0xdd, 0xb7, 0xa0, 0x76, 0x65, 0x68, 0x47, 0x7f, 0xed, 0x63, 0xcf, 0x53, + 0x18, 0x62, 0x12, 0x2c, 0x6c, 0x15, 0xb4, 0xa7, 0x07, 0x97, 0x3d, 0x41, 0x78, 0x2c, 0xfc, 0x0e, + 0xf4, 0xfe, 0x6c, 0x31, 0x15, 0x98, 0x8a, 0x2e, 0x33, 0x90, 0x15, 0x93, 0x8d, 0x2d, 0xf0, 0xa5, + 0xd3, 0x02, 0x37, 0xa2, 0x59, 0x2c, 0xc1, 0x0c, 0x05, 0xa9, 0xe4, 0xef, 0x6b, 0x69, 0x5b, 0xca, + 0x99, 0x73, 0x6b, 0x1a, 0x49, 0xea, 0x39, 0x60, 0x6a, 0x38, 0x1e, 0xcf, 0xb0, 0x5e, 0xfe, 0x60, + 0xd2, 0x8b, 0x54, 0x82, 0x3e, 0xc5, 0xa3, 0x68, 0x0c, 0x76, 0x5d, 0xe9, 0xdf, 0x4c, 0xfa, 0x54, + 0x87, 0xf3, 0x60, 0xe2, 0x9e, 0x99, 0x34, 0x3e, 0x91, 0x81, 0x1b, 0xae, 0xc3, 0x31, 0xc4, 0x68, + 0x09, 0x85, 0xe6, 0x08, 0xca, 0x5d, 0x40, 0x8e, 0x21, 0x72, 0x5c, 0x6a, 0xa1, 0xb6, 0x1d, 0x5a, + 0x8b, 0x48, 0xd7, 0x5f, 0x4a, 0xaa, 0x9a, 0x3c, 0xbe, 0x88, 0xd3, 0xe0, 0xf1, 0xa5, 0x43, 0x19, + 0x08, 0x1f, 0x77, 0xc7, 0x2c, 0x8f, 0x52, 0x54, 0x74, 0x40, 0xe2, 0x01, 0x00, +]; + +pub const PROFILE_KEY_CREDENTIAL_PRESENTATION_RESULT: [u8; + zkgroup::PROFILE_KEY_CREDENTIAL_PRESENTATION_LEN] = [ + 0x00, 0xc4, 0xd1, 0x9b, 0xca, 0x1a, 0xe8, 0x44, 0x58, 0x51, 0x68, 0x86, 0x9d, 0xa4, 0x13, 0x3e, + 0x0e, 0x0b, 0xb5, 0x9f, 0x2c, 0xe1, 0x7b, 0x7a, 0xc6, 0x5b, 0xff, 0x5d, 0xa9, 0x61, 0x0e, 0xca, + 0x10, 0x34, 0x29, 0xd8, 0x02, 0x2a, 0x94, 0xba, 0xe2, 0xb5, 0xb1, 0x05, 0x7b, 0x55, 0x95, 0xb8, + 0xad, 0x70, 0xbf, 0xc2, 0xd0, 0xe1, 0xad, 0x66, 0x2c, 0xb7, 0x5e, 0x6b, 0xae, 0x07, 0x82, 0xbe, + 0x6f, 0x00, 0xe3, 0xdb, 0x79, 0x3b, 0xc2, 0x85, 0x61, 0xf0, 0x19, 0x6c, 0x2e, 0x74, 0xda, 0x6f, + 0x30, 0x3f, 0xa8, 0xbc, 0xb7, 0x0c, 0x94, 0x09, 0x66, 0x71, 0xb7, 0x3f, 0x7b, 0x3a, 0x95, 0xfb, + 0x00, 0x22, 0x00, 0xd5, 0xb9, 0x18, 0x0f, 0xa0, 0xef, 0x7d, 0x30, 0x14, 0xd0, 0x13, 0x44, 0x14, + 0x5b, 0x4d, 0x38, 0x48, 0x0d, 0x72, 0xff, 0x25, 0xc2, 0x42, 0x94, 0xe3, 0x05, 0xe5, 0x70, 0x50, + 0x72, 0xe0, 0xd3, 0x2c, 0xc4, 0xe8, 0x4f, 0x5c, 0xaf, 0x31, 0x48, 0x60, 0x89, 0xa4, 0xb9, 0x34, + 0xc8, 0x0c, 0x92, 0xeb, 0xa4, 0x34, 0x72, 0xff, 0x23, 0xa5, 0xaf, 0x93, 0xc3, 0x97, 0x53, 0x5d, + 0x33, 0x80, 0x1f, 0x0e, 0x6f, 0xc6, 0xeb, 0x2e, 0xe0, 0xd1, 0x17, 0xf0, 0x3b, 0xb4, 0xfd, 0x38, + 0xa8, 0xb9, 0xc8, 0x8d, 0x94, 0x70, 0x81, 0x31, 0xf3, 0x87, 0x42, 0xca, 0x80, 0x4a, 0x3c, 0xfc, + 0x4f, 0x94, 0x76, 0xbc, 0x2d, 0x03, 0xf5, 0x3d, 0x17, 0x00, 0x1c, 0x36, 0x47, 0x8a, 0xfb, 0xe9, + 0xcc, 0x53, 0x5a, 0x22, 0x4b, 0x2d, 0xf6, 0xb2, 0xb0, 0x8b, 0xef, 0x06, 0xcb, 0xc7, 0xd4, 0xdc, + 0x42, 0xcc, 0xfc, 0x34, 0x59, 0xf7, 0xac, 0x5c, 0x44, 0x19, 0xae, 0x9f, 0x3c, 0x8a, 0x16, 0x1d, + 0x55, 0x4d, 0x04, 0x77, 0x78, 0x94, 0x32, 0x16, 0x24, 0x08, 0x58, 0xda, 0x3b, 0x11, 0x01, 0x98, + 0x4c, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x01, 0xee, 0xa6, 0xb2, 0xad, 0xad, + 0x14, 0xd7, 0x1a, 0xb8, 0xb8, 0xe4, 0x11, 0xbe, 0xf3, 0xc5, 0x96, 0xe9, 0x54, 0xb7, 0x0e, 0x40, + 0x31, 0x57, 0x0c, 0xb1, 0xab, 0xd7, 0xe9, 0x32, 0x08, 0x32, 0x41, 0xf1, 0xca, 0xca, 0x31, 0x16, + 0x70, 0x8f, 0xa4, 0x31, 0x9f, 0xbb, 0xdf, 0xe3, 0x51, 0x37, 0x6c, 0x23, 0x64, 0x4a, 0xe0, 0x9a, + 0x42, 0xf0, 0x15, 0x5d, 0xb4, 0x99, 0x6c, 0x9d, 0x0c, 0x7f, 0xfc, 0x85, 0x21, 0xc1, 0x91, 0x4c, + 0x0e, 0x1a, 0x20, 0xae, 0x51, 0xe6, 0x5d, 0xf6, 0x4d, 0xd5, 0xe6, 0xe5, 0x98, 0x5b, 0x3d, 0x9d, + 0x31, 0x73, 0x20, 0x46, 0xd2, 0xd7, 0x7f, 0x9c, 0x08, 0xaa, 0xcc, 0xf0, 0x56, 0xb8, 0x40, 0x26, + 0x07, 0x39, 0x76, 0xee, 0xc6, 0x16, 0x4c, 0xbd, 0xae, 0xe5, 0xd9, 0xe7, 0x6e, 0x49, 0x7f, 0x0c, + 0x29, 0x0a, 0xf6, 0x81, 0xca, 0xbd, 0x5c, 0x51, 0x01, 0x28, 0x2a, 0xbb, 0x26, 0xc3, 0x68, 0x0d, + 0x60, 0x87, 0xce, 0x05, 0x33, 0x10, 0xfe, 0x8a, 0x94, 0xf5, 0x9d, 0x8a, 0xe2, 0x3c, 0xaa, 0xc5, + 0xfc, 0x0e, 0xd0, 0xc3, 0x79, 0x88, 0x8a, 0xbf, 0x02, 0x8a, 0x6f, 0x29, 0xf8, 0x9d, 0x4f, 0xe2, + 0xac, 0xc1, 0x70, 0x63, 0x41, 0xb2, 0x24, 0x5b, 0xa1, 0x88, 0x5b, 0xca, 0x57, 0xe1, 0xe2, 0x7c, + 0xcf, 0x7e, 0xd7, 0x93, 0x71, 0x50, 0x09, 0x65, 0x00, 0x9f, 0x96, 0x0c, 0x2b, 0xa0, 0x0f, 0xad, + 0x3e, 0x93, 0x38, 0x3b, 0x87, 0xce, 0x11, 0x9c, 0xac, 0x0b, 0x33, 0x60, 0xeb, 0x99, 0x28, 0x4c, + 0xe7, 0x8e, 0x2c, 0xbe, 0xd6, 0x80, 0xf7, 0x96, 0x03, 0x73, 0xe0, 0xab, 0x75, 0xc1, 0x90, 0x25, + 0x41, 0x60, 0xc2, 0x35, 0x36, 0x14, 0x10, 0x94, 0x89, 0xe6, 0x53, 0xc9, 0xb2, 0xe1, 0xc9, 0x3f, + 0x92, 0xc7, 0xc5, 0xad, 0x58, 0x3d, 0x98, 0x7a, 0x04, 0xbd, 0x35, 0x41, 0xb2, 0x44, 0x85, 0xc3, + 0x3e, 0xa4, 0x9b, 0xac, 0x43, 0xc8, 0x7c, 0x4a, 0xb3, 0xef, 0xde, 0x2e, 0x2d, 0x7e, 0xc1, 0x0a, + 0x40, 0xbe, 0x54, 0x41, 0x99, 0xf9, 0x25, 0xb2, 0x0b, 0x2c, 0x55, 0x54, 0x2b, 0xc5, 0x64, 0x10, + 0x57, 0x1e, 0x41, 0xcd, 0x8e, 0x02, 0x86, 0xf6, 0x09, 0xa6, 0x67, 0x68, 0xb5, 0x06, 0x1c, 0xcb, + 0x47, 0x77, 0xaf, 0x32, 0x30, 0x99, 0x28, 0xdd, 0x09, 0x76, 0x5d, 0xe9, 0xdf, 0x4c, 0xfa, 0x54, + 0x87, 0xf3, 0x60, 0xe2, 0x9e, 0x99, 0x34, 0x3e, 0x91, 0x81, 0x1b, 0xae, 0xc3, 0x31, 0xc4, 0x68, + 0x09, 0x85, 0xe6, 0x08, 0xca, 0x5d, 0x40, 0x8e, 0x21, 0x72, 0x5c, 0x6a, 0xa1, 0xb6, 0x1d, 0x5a, + 0x8b, 0x48, 0xd7, 0x5f, 0x4a, 0xaa, 0x9a, 0x3c, 0xbe, 0x88, 0xd3, 0xe0, 0xf1, 0xa5, 0x43, 0x19, + 0x08, 0x1f, 0x77, 0xc7, 0x2c, 0x8f, 0x52, 0x54, 0x74, 0x48, 0xc0, 0x3a, 0xb4, 0xaf, 0xbf, 0x6b, + 0x8f, 0xb0, 0xe1, 0x26, 0xc0, 0x37, 0xa0, 0xad, 0x40, 0x94, 0x60, 0x0d, 0xd0, 0xe0, 0x63, 0x4d, + 0x76, 0xf8, 0x8c, 0x21, 0x08, 0x7f, 0x3c, 0xfb, 0x48, 0x5a, 0x89, 0xbc, 0x1e, 0x3a, 0xbc, 0x4c, + 0x95, 0x04, 0x1d, 0x1d, 0x17, 0x0e, 0xcc, 0xf0, 0x29, 0x33, 0xec, 0x53, 0x93, 0xd4, 0xbe, 0x1d, + 0xc5, 0x73, 0xf8, 0x3c, 0x33, 0xd3, 0xb9, 0xa7, 0x46, +]; + +#[test] +fn test_integration_auth() { + let server_secret_params = zkgroup::ServerSecretParams::generate(zkgroup::TEST_ARRAY_32); + let server_public_params = server_secret_params.get_public_params(); + + let master_key = zkgroup::groups::GroupMasterKey::new(zkgroup::TEST_ARRAY_32_1); + let group_secret_params = + zkgroup::groups::GroupSecretParams::derive_from_master_key(master_key); + let group_public_params = group_secret_params.get_public_params(); + + // Random UID and issueTime + let uid = zkgroup::TEST_ARRAY_16; + let redemption_time = 123456u32; + + // SERVER + // Issue credential + let randomness = zkgroup::TEST_ARRAY_32_2; + let auth_credential_response = + server_secret_params.issue_auth_credential(randomness, uid, redemption_time); + + // CLIENT + let auth_credential = server_public_params + .receive_auth_credential(uid, redemption_time, &auth_credential_response) + .unwrap(); + + // Create and decrypt user entry + let uuid_ciphertext = group_secret_params.encrypt_uuid(uid); + let plaintext = group_secret_params.decrypt_uuid(uuid_ciphertext).unwrap(); + assert!(plaintext == uid); + + // Create and receive presentation + let randomness = zkgroup::TEST_ARRAY_32_5; + + let presentation = server_public_params.create_auth_credential_presentation( + randomness, + group_secret_params, + auth_credential, + ); + + let presentation_bytes = &bincode::serialize(&presentation).unwrap(); + + //for b in presentation_bytes.iter() { + // print!("0x{:02x}, ", b); + //} + assert!(AUTH_CREDENTIAL_PRESENTATION_RESULT[..] == presentation_bytes[..]); + + server_secret_params + .verify_auth_credential_presentation(group_public_params, &presentation) + .unwrap(); + + // test encoding + // these tests will also discover if the serialized sizes change, + // necessitating an update to the LEN constants + //let mut ccm_bytes = [0u8; zkgroup::common::constants::CLIENT_CREDENTIAL_MANAGER_LEN]; + let mut group_secret_params_bytes = [0u8; zkgroup::common::constants::GROUP_SECRET_PARAMS_LEN]; + let mut server_secret_params_bytes = + [0u8; zkgroup::common::constants::SERVER_SECRET_PARAMS_LEN]; + let mut group_public_params_bytes = [0u8; zkgroup::common::constants::GROUP_PUBLIC_PARAMS_LEN]; + let mut server_public_params_bytes = + [0u8; zkgroup::common::constants::SERVER_PUBLIC_PARAMS_LEN]; + let mut auth_credential_response_bytes = + [0u8; zkgroup::common::constants::AUTH_CREDENTIAL_RESPONSE_LEN]; + let mut auth_credential_bytes = [0u8; zkgroup::common::constants::AUTH_CREDENTIAL_LEN]; + let mut auth_credential_presentation_bytes = + [0u8; zkgroup::common::constants::AUTH_CREDENTIAL_PRESENTATION_LEN]; + let mut uuid_ciphertext_bytes = [0u8; zkgroup::common::constants::UUID_CIPHERTEXT_LEN]; + let mut uid_bytes = [0u8; zkgroup::common::constants::UUID_LEN]; + let mut randomness_bytes = [0u8; zkgroup::common::constants::RANDOMNESS_LEN]; + + //ccm_bytes.copy_from_slice(&bincode::serialize(&client_credential_manager).unwrap()); + group_secret_params_bytes.copy_from_slice(&bincode::serialize(&group_secret_params).unwrap()); + server_secret_params_bytes.copy_from_slice(&bincode::serialize(&server_secret_params).unwrap()); + group_public_params_bytes.copy_from_slice(&bincode::serialize(&group_public_params).unwrap()); + server_public_params_bytes.copy_from_slice(&bincode::serialize(&server_public_params).unwrap()); + auth_credential_response_bytes + .copy_from_slice(&bincode::serialize(&auth_credential_response).unwrap()); + auth_credential_bytes.copy_from_slice(&bincode::serialize(&auth_credential).unwrap()); + auth_credential_presentation_bytes.copy_from_slice(&bincode::serialize(&presentation).unwrap()); + uuid_ciphertext_bytes.copy_from_slice(&bincode::serialize(&uuid_ciphertext).unwrap()); + uid_bytes.copy_from_slice(&bincode::serialize(&uid).unwrap()); + randomness_bytes.copy_from_slice(&bincode::serialize(&randomness).unwrap()); +} + +#[test] +fn test_integration_profile() { + // Random UID and issueTime + let _uid = zkgroup::TEST_ARRAY_16; + + // SERVER + let server_secret_params = zkgroup::ServerSecretParams::generate(zkgroup::TEST_ARRAY_32); + let server_public_params = server_secret_params.get_public_params(); + + // CLIENT + let master_key = zkgroup::groups::GroupMasterKey::new(zkgroup::TEST_ARRAY_32_1); + let group_secret_params = + zkgroup::groups::GroupSecretParams::derive_from_master_key(master_key); + let group_public_params = group_secret_params.get_public_params(); + + let uid = zkgroup::TEST_ARRAY_16; + let profile_key = + zkgroup::profiles::ProfileKey::create(zkgroup::common::constants::TEST_ARRAY_32_1); + let profile_key_commitment = profile_key.get_commitment(uid); + + // Create context and request + let randomness = zkgroup::TEST_ARRAY_32_3; + + let context = server_public_params.create_profile_key_credential_request_context( + randomness, + uid, + profile_key, + ); + let request = context.get_request(); + + // SERVER + + let randomness = zkgroup::TEST_ARRAY_32_4; + let response = server_secret_params + .issue_profile_key_credential(randomness, &request, uid, profile_key_commitment) + .unwrap(); + + // CLIENT + // Gets stored profile credential + let profile_key_credential = server_public_params + .receive_profile_key_credential(&context, &response) + .unwrap(); + + // Create encrypted UID and profile key + let uuid_ciphertext = group_secret_params.encrypt_uuid(uid); + let plaintext = group_secret_params.decrypt_uuid(uuid_ciphertext).unwrap(); + assert!(plaintext == uid); + + let profile_key_ciphertext = group_secret_params.encrypt_profile_key(profile_key, uid); + let decrypted_profile_key = group_secret_params + .decrypt_profile_key(profile_key_ciphertext, uid) + .unwrap(); + + assert!(decrypted_profile_key.get_bytes() == profile_key.get_bytes()); + + // Create presentation + let randomness = zkgroup::TEST_ARRAY_32_5; + + let presentation = server_public_params.create_profile_key_credential_presentation( + randomness, + group_secret_params, + profile_key_credential, + ); + + let presentation_bytes = &bincode::serialize(&presentation).unwrap(); + //for b in presentation_bytes.iter() { + // print!("0x{:02x}, ", b); + //} + assert!(PROFILE_KEY_CREDENTIAL_PRESENTATION_RESULT[..] == presentation_bytes[..]); + + // SERVER + server_secret_params + .verify_profile_key_credential_presentation(group_public_params, &presentation) + .unwrap(); + + // test encoding + // these tests will also discover if the serialized sizes change, + // necessitating an update to the LEN constants + + let mut profile_key_commitment_bytes = + [0u8; zkgroup::common::constants::PROFILE_KEY_COMMITMENT_LEN]; + let mut profile_key_credential_bytes = + [0u8; zkgroup::common::constants::PROFILE_KEY_CREDENTIAL_LEN]; + let mut profile_key_credential_presentation_bytes = + [0u8; zkgroup::common::constants::PROFILE_KEY_CREDENTIAL_PRESENTATION_LEN]; + let mut profile_key_credential_request_bytes = + [0u8; zkgroup::common::constants::PROFILE_KEY_CREDENTIAL_REQUEST_LEN]; + let mut profile_key_credential_request_context_bytes = + [0u8; zkgroup::common::constants::PROFILE_KEY_CREDENTIAL_REQUEST_CONTEXT_LEN]; + let mut profile_key_credential_response_bytes = + [0u8; zkgroup::common::constants::PROFILE_KEY_CREDENTIAL_RESPONSE_LEN]; + + profile_key_commitment_bytes + .copy_from_slice(&bincode::serialize(&profile_key_commitment).unwrap()); + profile_key_credential_bytes + .copy_from_slice(&bincode::serialize(&profile_key_credential).unwrap()); + profile_key_credential_presentation_bytes + .copy_from_slice(&bincode::serialize(&presentation).unwrap()); + profile_key_credential_request_bytes.copy_from_slice(&bincode::serialize(&request).unwrap()); + profile_key_credential_request_context_bytes + .copy_from_slice(&bincode::serialize(&context).unwrap()); + profile_key_credential_response_bytes.copy_from_slice(&bincode::serialize(&response).unwrap()); +} + +#[test] +fn test_server_sigs() { + let server_secret_params = + zkgroup::api::server_params::ServerSecretParams::generate(zkgroup::TEST_ARRAY_32); + let server_public_params = server_secret_params.get_public_params(); + let randomness = zkgroup::TEST_ARRAY_32_2; + let message = zkgroup::TEST_ARRAY_32_1; + let signature = server_secret_params.sign(randomness, &message).unwrap(); + //println!("signature = {:#x?}", &signature[..]); + for b in signature.iter() { + print!("0x{:02x}, ", b); + } + assert!( + signature[..] + == [ + 0x87, 0xd3, 0x54, 0x56, 0x4d, 0x35, 0xef, 0x91, 0xed, 0xba, 0x85, 0x1e, 0x08, 0x15, + 0x61, 0x2e, 0x86, 0x4c, 0x22, 0x7a, 0x04, 0x71, 0xd5, 0x0c, 0x27, 0x06, 0x98, 0x60, + 0x44, 0x06, 0xd0, 0x03, 0xa5, 0x54, 0x73, 0xf5, 0x76, 0xcf, 0x24, 0x1f, 0xc6, 0xb4, + 0x1c, 0x6b, 0x16, 0xe5, 0xe6, 0x3b, 0x33, 0x3c, 0x02, 0xfe, 0x4a, 0x33, 0x85, 0x80, + 0x22, 0xfd, 0xd7, 0xa4, 0xab, 0x36, 0x7b, 0x06, + ][..] + ); + server_public_params + .verify_signature(&message, signature) + .unwrap(); +} + +#[test] +fn test_blob_encryption() { + let master_key = zkgroup::groups::GroupMasterKey::new(zkgroup::TEST_ARRAY_32_1); + let group_secret_params = + zkgroup::groups::GroupSecretParams::derive_from_master_key(master_key); + let randomness = zkgroup::TEST_ARRAY_32_2; + + let plaintext_vec = vec![ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, + ]; + + // WARNING: THIS VECTOR DOES *NOT* MATCH JAVA/SWIFT/NODE AS THEY IMPLEMENT PADDING + let ciphertext_vec = vec![ + 0xe9, 0x58, 0x07, 0xb1, 0x90, 0xd4, 0x78, 0xd7, 0xbe, 0x3a, 0x77, 0xb2, 0x29, 0x27, 0x13, + 0x2e, 0xeb, 0xa5, 0x1c, 0x73, 0x9c, 0xd5, 0x70, 0x73, 0x17, 0xf7, 0x3e, 0x59, 0x1a, 0x91, + 0x5f, 0xff, 0x1f, 0x20, 0xa3, 0x02, 0x69, 0x2a, 0xfd, 0xc7, 0x08, 0x7f, 0x10, 0x19, 0x60, + 0x00, + ]; + + let calc_ciphertext_vec = group_secret_params + .encrypt_blob(randomness, &plaintext_vec) + .unwrap(); + let calc_plaintext_vec = group_secret_params + .decrypt_blob(&calc_ciphertext_vec) + .unwrap(); + assert!(calc_plaintext_vec == plaintext_vec); + for b in calc_ciphertext_vec.iter() { + print!("0x{:02x}, ", b); + } + assert!(calc_ciphertext_vec == ciphertext_vec); +} diff --git a/net/gurk-rs/pkg/DESCR b/net/gurk-rs/pkg/DESCR new file mode 100644 index 0000000..258cd57 --- /dev/null +++ b/net/gurk-rs/pkg/DESCR @@ -0,0 +1 @@ +todo diff --git a/net/gurk-rs/pkg/PLIST b/net/gurk-rs/pkg/PLIST new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/net/gurk-rs/pkg/PLIST @@ -0,0 +1 @@ +