mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-03 20:13:48 +00:00
curve: Remove ff/group features for now (#907)
This commit is contained in:
parent
5b796f38c8
commit
13ac5e66a7
7 changed files with 10 additions and 809 deletions
2
.github/workflows/curve25519-dalek.yml
vendored
2
.github/workflows/curve25519-dalek.yml
vendored
|
|
@ -127,7 +127,7 @@ jobs:
|
||||||
# This should automatically pick up the simd backend in a x86_64 runner
|
# This should automatically pick up the simd backend in a x86_64 runner
|
||||||
# It should pick AVX2 due to stable toolchain used since AVX512 requires nigthly
|
# It should pick AVX2 due to stable toolchain used since AVX512 requires nigthly
|
||||||
RUSTFLAGS: '-C target_feature=+avx2'
|
RUSTFLAGS: '-C target_feature=+avx2'
|
||||||
run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize,group-bits --target x86_64-unknown-linux-gnu
|
run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize --target x86_64-unknown-linux-gnu
|
||||||
|
|
||||||
msrv:
|
msrv:
|
||||||
name: Current MSRV is 1.85.0
|
name: Current MSRV is 1.85.0
|
||||||
|
|
|
||||||
139
Cargo.lock
generated
139
Cargo.lock
generated
|
|
@ -2,17 +2,6 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "addchain"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570"
|
|
||||||
dependencies = [
|
|
||||||
"num-bigint",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.4"
|
version = "1.1.4"
|
||||||
|
|
@ -88,18 +77,6 @@ version = "2.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitvec"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
|
|
||||||
dependencies = [
|
|
||||||
"funty",
|
|
||||||
"radium",
|
|
||||||
"tap",
|
|
||||||
"wyz",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blake2"
|
name = "blake2"
|
||||||
version = "0.11.0-rc.6"
|
version = "0.11.0-rc.6"
|
||||||
|
|
@ -342,8 +319,6 @@ dependencies = [
|
||||||
"proptest",
|
"proptest",
|
||||||
"rand_core 0.10.0",
|
"rand_core 0.10.0",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"rustcrypto-ff",
|
|
||||||
"rustcrypto-group",
|
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
"subtle",
|
"subtle",
|
||||||
|
|
@ -356,7 +331,7 @@ version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.114",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -478,12 +453,6 @@ version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "funty"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
|
|
@ -695,26 +664,6 @@ version = "2.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-bigint"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-integer"
|
|
||||||
version = "0.1.46"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.19"
|
||||||
|
|
@ -812,7 +761,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"syn 2.0.114",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -864,12 +813,6 @@ version = "5.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "radium"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|
@ -972,44 +915,6 @@ dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustcrypto-ff"
|
|
||||||
version = "0.14.0-rc.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fd2a8adb347447693cd2ba0d218c4b66c62da9b0a5672b17b981e4291ec65ff6"
|
|
||||||
dependencies = [
|
|
||||||
"bitvec",
|
|
||||||
"rand_core 0.10.0",
|
|
||||||
"rustcrypto-ff_derive",
|
|
||||||
"subtle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustcrypto-ff_derive"
|
|
||||||
version = "0.14.0-rc.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4cda22ea03582974ab5687fc131eba2dc78e258e7eef4d7e01bcd0522ed79f66"
|
|
||||||
dependencies = [
|
|
||||||
"addchain",
|
|
||||||
"num-bigint",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustcrypto-group"
|
|
||||||
version = "0.14.0-rc.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "369f9b61aa45933c062c9f6b5c3c50ab710687eca83dd3802653b140b43f85ed"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core 0.10.0",
|
|
||||||
"rustcrypto-ff",
|
|
||||||
"subtle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
|
|
@ -1089,7 +994,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.114",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1198,17 +1103,6 @@ version = "2.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "1.0.109"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.114"
|
version = "2.0.114"
|
||||||
|
|
@ -1220,12 +1114,6 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tap"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.24.0"
|
version = "3.24.0"
|
||||||
|
|
@ -1256,7 +1144,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.114",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1401,7 +1289,7 @@ dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.114",
|
"syn",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1518,7 +1406,7 @@ dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"syn 2.0.114",
|
"syn",
|
||||||
"wasm-metadata",
|
"wasm-metadata",
|
||||||
"wit-bindgen-core",
|
"wit-bindgen-core",
|
||||||
"wit-component",
|
"wit-component",
|
||||||
|
|
@ -1534,7 +1422,7 @@ dependencies = [
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.114",
|
"syn",
|
||||||
"wit-bindgen-core",
|
"wit-bindgen-core",
|
||||||
"wit-bindgen-rust",
|
"wit-bindgen-rust",
|
||||||
]
|
]
|
||||||
|
|
@ -1576,15 +1464,6 @@ dependencies = [
|
||||||
"wasmparser",
|
"wasmparser",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wyz"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
|
||||||
dependencies = [
|
|
||||||
"tap",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x25519-dalek"
|
name = "x25519-dalek"
|
||||||
version = "3.0.0-pre.6"
|
version = "3.0.0-pre.6"
|
||||||
|
|
@ -1615,7 +1494,7 @@ checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.114",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1635,7 +1514,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.114",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,6 @@ required-features = ["alloc", "rand_core"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cfg-if = "1"
|
cfg-if = "1"
|
||||||
ff = { version = "0.14.0-rc.1", package = "rustcrypto-ff", default-features = false, optional = true }
|
|
||||||
group = { version = "0.14.0-rc.1", package = "rustcrypto-group", default-features = false, optional = true }
|
|
||||||
rand_core = { version = "0.10", default-features = false, optional = true }
|
rand_core = { version = "0.10", default-features = false, optional = true }
|
||||||
digest = { version = "0.11", default-features = false, optional = true, features = ["block-api"] }
|
digest = { version = "0.11", default-features = false, optional = true, features = ["block-api"] }
|
||||||
subtle = { version = "2.6.0", default-features = false, features = [
|
subtle = { version = "2.6.0", default-features = false, features = [
|
||||||
|
|
@ -70,8 +68,6 @@ default = ["alloc", "precomputed-tables", "zeroize"]
|
||||||
alloc = ["zeroize?/alloc"]
|
alloc = ["zeroize?/alloc"]
|
||||||
precomputed-tables = []
|
precomputed-tables = []
|
||||||
legacy_compatibility = []
|
legacy_compatibility = []
|
||||||
group = ["dep:group", "rand_core"]
|
|
||||||
group-bits = ["group", "ff/bits"]
|
|
||||||
digest = ["dep:digest"]
|
digest = ["dep:digest"]
|
||||||
lizard = ["digest"]
|
lizard = ["digest"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,6 @@ curve25519-dalek = ">= 5.0, < 5.2"
|
||||||
| `digest` | | Enables `RistrettoPoint::{from_hash, hash_from_bytes}` and `Scalar::{from_hash, hash_from_bytes}`. Also enables hash-to-curve methods `EdwardsPoint::{encode_to_curve, hash_to_curve}`. This is an optional dependency whose version is not subject to SemVer. See [below](#public-api-semver-exemptions) for more details. |
|
| `digest` | | Enables `RistrettoPoint::{from_hash, hash_from_bytes}` and `Scalar::{from_hash, hash_from_bytes}`. Also enables hash-to-curve methods `EdwardsPoint::{encode_to_curve, hash_to_curve}`. This is an optional dependency whose version is not subject to SemVer. See [below](#public-api-semver-exemptions) for more details. |
|
||||||
| `serde` | | Enables `serde` serialization/deserialization for all the point and scalar types. |
|
| `serde` | | Enables `serde` serialization/deserialization for all the point and scalar types. |
|
||||||
| `legacy_compatibility`| | Enables `Scalar::from_bits`, which allows the user to build unreduced scalars whose arithmetic is broken. Do not use this unless you know what you're doing. |
|
| `legacy_compatibility`| | Enables `Scalar::from_bits`, which allows the user to build unreduced scalars whose arithmetic is broken. Do not use this unless you know what you're doing. |
|
||||||
| `group` | | Enables external `group` and `ff` crate traits. |
|
|
||||||
| `group-bits` | | Enables `group` and impls `ff::PrimeFieldBits` for `Scalar`. |
|
|
||||||
| `lizard` | | Enables the [Lizard](src/lizard/README.md) bytestring-to-point injection for `RistrettoPoint`. Specifically enables the methods `lizard_encode` and `lizard_decode`. |
|
| `lizard` | | Enables the [Lizard](src/lizard/README.md) bytestring-to-point injection for `RistrettoPoint`. Specifically enables the methods `lizard_encode` and `lizard_decode`. |
|
||||||
|
|
||||||
To disable the default features when using `curve25519-dalek` as a dependency,
|
To disable the default features when using `curve25519-dalek` as a dependency,
|
||||||
|
|
|
||||||
|
|
@ -110,13 +110,6 @@ use digest::{
|
||||||
typenum::IsGreater,
|
typenum::IsGreater,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
use {
|
|
||||||
group::{GroupEncoding, cofactor::CofactorGroup, prime::PrimeGroup},
|
|
||||||
rand_core::TryRng,
|
|
||||||
subtle::CtOption,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "rand_core")]
|
#[cfg(feature = "rand_core")]
|
||||||
use rand_core::Rng;
|
use rand_core::Rng;
|
||||||
|
|
||||||
|
|
@ -1451,338 +1444,6 @@ impl Debug for EdwardsPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// group traits
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Use the full trait path to avoid Group::identity overlapping Identity::identity in the
|
|
||||||
// rest of the module (e.g. tests).
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl group::Group for EdwardsPoint {
|
|
||||||
type Scalar = Scalar;
|
|
||||||
|
|
||||||
fn try_from_rng<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
|
|
||||||
let mut repr = CompressedEdwardsY([0u8; 32]);
|
|
||||||
loop {
|
|
||||||
rng.try_fill_bytes(&mut repr.0)?;
|
|
||||||
if let Some(p) = repr.decompress() {
|
|
||||||
if !IsIdentity::is_identity(&p) {
|
|
||||||
break Ok(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn identity() -> Self {
|
|
||||||
Identity::identity()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generator() -> Self {
|
|
||||||
constants::ED25519_BASEPOINT_POINT
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_identity(&self) -> Choice {
|
|
||||||
self.ct_eq(&Identity::identity())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn double(&self) -> Self {
|
|
||||||
self.double()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl GroupEncoding for EdwardsPoint {
|
|
||||||
type Repr = [u8; 32];
|
|
||||||
|
|
||||||
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
|
|
||||||
let repr = CompressedEdwardsY(*bytes);
|
|
||||||
let (is_valid_y_coord, X, Y, Z) = decompress::step_1(&repr);
|
|
||||||
CtOption::new(decompress::step_2(&repr, X, Y, Z), is_valid_y_coord)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
|
|
||||||
// Just use the checked API; there are no checks we can skip.
|
|
||||||
Self::from_bytes(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_bytes(&self) -> Self::Repr {
|
|
||||||
self.compress().to_bytes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A `SubgroupPoint` represents a point on the Edwards form of Curve25519, that is
|
|
||||||
/// guaranteed to be in the prime-order subgroup.
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
|
||||||
pub struct SubgroupPoint(EdwardsPoint);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl From<SubgroupPoint> for EdwardsPoint {
|
|
||||||
fn from(p: SubgroupPoint) -> Self {
|
|
||||||
p.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl Neg for SubgroupPoint {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn neg(self) -> Self::Output {
|
|
||||||
SubgroupPoint(-self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl Add<&SubgroupPoint> for &SubgroupPoint {
|
|
||||||
type Output = SubgroupPoint;
|
|
||||||
fn add(self, other: &SubgroupPoint) -> SubgroupPoint {
|
|
||||||
SubgroupPoint(self.0 + other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
define_add_variants!(
|
|
||||||
LHS = SubgroupPoint,
|
|
||||||
RHS = SubgroupPoint,
|
|
||||||
Output = SubgroupPoint
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl Add<&SubgroupPoint> for &EdwardsPoint {
|
|
||||||
type Output = EdwardsPoint;
|
|
||||||
fn add(self, other: &SubgroupPoint) -> EdwardsPoint {
|
|
||||||
self + other.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
define_add_variants!(
|
|
||||||
LHS = EdwardsPoint,
|
|
||||||
RHS = SubgroupPoint,
|
|
||||||
Output = EdwardsPoint
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl AddAssign<&SubgroupPoint> for SubgroupPoint {
|
|
||||||
fn add_assign(&mut self, rhs: &SubgroupPoint) {
|
|
||||||
self.0 += rhs.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
define_add_assign_variants!(LHS = SubgroupPoint, RHS = SubgroupPoint);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl AddAssign<&SubgroupPoint> for EdwardsPoint {
|
|
||||||
fn add_assign(&mut self, rhs: &SubgroupPoint) {
|
|
||||||
*self += rhs.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
define_add_assign_variants!(LHS = EdwardsPoint, RHS = SubgroupPoint);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl Sub<&SubgroupPoint> for &SubgroupPoint {
|
|
||||||
type Output = SubgroupPoint;
|
|
||||||
fn sub(self, other: &SubgroupPoint) -> SubgroupPoint {
|
|
||||||
SubgroupPoint(self.0 - other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
define_sub_variants!(
|
|
||||||
LHS = SubgroupPoint,
|
|
||||||
RHS = SubgroupPoint,
|
|
||||||
Output = SubgroupPoint
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl Sub<&SubgroupPoint> for &EdwardsPoint {
|
|
||||||
type Output = EdwardsPoint;
|
|
||||||
fn sub(self, other: &SubgroupPoint) -> EdwardsPoint {
|
|
||||||
self - other.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
define_sub_variants!(
|
|
||||||
LHS = EdwardsPoint,
|
|
||||||
RHS = SubgroupPoint,
|
|
||||||
Output = EdwardsPoint
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl SubAssign<&SubgroupPoint> for SubgroupPoint {
|
|
||||||
fn sub_assign(&mut self, rhs: &SubgroupPoint) {
|
|
||||||
self.0 -= rhs.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
define_sub_assign_variants!(LHS = SubgroupPoint, RHS = SubgroupPoint);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl SubAssign<&SubgroupPoint> for EdwardsPoint {
|
|
||||||
fn sub_assign(&mut self, rhs: &SubgroupPoint) {
|
|
||||||
*self -= rhs.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
define_sub_assign_variants!(LHS = EdwardsPoint, RHS = SubgroupPoint);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl<T> Sum<T> for SubgroupPoint
|
|
||||||
where
|
|
||||||
T: Borrow<SubgroupPoint>,
|
|
||||||
{
|
|
||||||
fn sum<I>(iter: I) -> Self
|
|
||||||
where
|
|
||||||
I: Iterator<Item = T>,
|
|
||||||
{
|
|
||||||
use group::Group;
|
|
||||||
iter.fold(SubgroupPoint::identity(), |acc, item| acc + item.borrow())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl Mul<&Scalar> for &SubgroupPoint {
|
|
||||||
type Output = SubgroupPoint;
|
|
||||||
|
|
||||||
/// Scalar multiplication: compute `scalar * self`.
|
|
||||||
///
|
|
||||||
/// For scalar multiplication of a basepoint,
|
|
||||||
/// `EdwardsBasepointTable` is approximately 4x faster.
|
|
||||||
fn mul(self, scalar: &Scalar) -> SubgroupPoint {
|
|
||||||
SubgroupPoint(self.0 * scalar)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
define_mul_variants!(LHS = Scalar, RHS = SubgroupPoint, Output = SubgroupPoint);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl Mul<&SubgroupPoint> for &Scalar {
|
|
||||||
type Output = SubgroupPoint;
|
|
||||||
|
|
||||||
/// Scalar multiplication: compute `scalar * self`.
|
|
||||||
///
|
|
||||||
/// For scalar multiplication of a basepoint,
|
|
||||||
/// `EdwardsBasepointTable` is approximately 4x faster.
|
|
||||||
fn mul(self, point: &SubgroupPoint) -> SubgroupPoint {
|
|
||||||
point * self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
define_mul_variants!(LHS = SubgroupPoint, RHS = Scalar, Output = SubgroupPoint);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl MulAssign<&Scalar> for SubgroupPoint {
|
|
||||||
fn mul_assign(&mut self, scalar: &Scalar) {
|
|
||||||
self.0 *= scalar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
define_mul_assign_variants!(LHS = SubgroupPoint, RHS = Scalar);
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl ConstantTimeEq for SubgroupPoint {
|
|
||||||
fn ct_eq(&self, other: &SubgroupPoint) -> Choice {
|
|
||||||
self.0.ct_eq(&other.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl ConditionallySelectable for SubgroupPoint {
|
|
||||||
fn conditional_select(a: &SubgroupPoint, b: &SubgroupPoint, choice: Choice) -> SubgroupPoint {
|
|
||||||
SubgroupPoint(EdwardsPoint::conditional_select(&a.0, &b.0, choice))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(feature = "group", feature = "zeroize"))]
|
|
||||||
impl Zeroize for SubgroupPoint {
|
|
||||||
fn zeroize(&mut self) {
|
|
||||||
self.0.zeroize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl group::Group for SubgroupPoint {
|
|
||||||
type Scalar = Scalar;
|
|
||||||
|
|
||||||
fn try_from_rng<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
|
|
||||||
use group::ff::Field;
|
|
||||||
|
|
||||||
// This will almost never loop, but `Group::random` is documented as returning a
|
|
||||||
// non-identity element.
|
|
||||||
let s = loop {
|
|
||||||
let s: Scalar = Field::try_from_rng(rng)?;
|
|
||||||
if !s.is_zero_vartime() {
|
|
||||||
break s;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// This gives an element of the prime-order subgroup.
|
|
||||||
Ok(Self::generator() * s)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn identity() -> Self {
|
|
||||||
SubgroupPoint(Identity::identity())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generator() -> Self {
|
|
||||||
SubgroupPoint(EdwardsPoint::generator())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_identity(&self) -> Choice {
|
|
||||||
self.0.ct_eq(&Identity::identity())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn double(&self) -> Self {
|
|
||||||
SubgroupPoint(self.0.double())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl GroupEncoding for SubgroupPoint {
|
|
||||||
type Repr = <EdwardsPoint as GroupEncoding>::Repr;
|
|
||||||
|
|
||||||
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
|
|
||||||
EdwardsPoint::from_bytes(bytes).and_then(|p| p.into_subgroup())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
|
|
||||||
EdwardsPoint::from_bytes_unchecked(bytes).and_then(|p| p.into_subgroup())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_bytes(&self) -> Self::Repr {
|
|
||||||
self.0.compress().to_bytes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl PrimeGroup for SubgroupPoint {}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl CofactorGroup for EdwardsPoint {
|
|
||||||
type Subgroup = SubgroupPoint;
|
|
||||||
|
|
||||||
fn clear_cofactor(&self) -> Self::Subgroup {
|
|
||||||
SubgroupPoint(self.mul_by_cofactor())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_subgroup(self) -> CtOption<Self::Subgroup> {
|
|
||||||
CtOption::new(SubgroupPoint(self), CofactorGroup::is_torsion_free(&self))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_torsion_free(&self) -> Choice {
|
|
||||||
(self * constants::BASEPOINT_ORDER).ct_eq(&Self::identity())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Tests
|
// Tests
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -177,13 +177,6 @@ use digest::array::typenum::U64;
|
||||||
use crate::constants;
|
use crate::constants;
|
||||||
use crate::field::FieldElement;
|
use crate::field::FieldElement;
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
use {
|
|
||||||
group::{GroupEncoding, cofactor::CofactorGroup, prime::PrimeGroup},
|
|
||||||
rand_core::TryRng,
|
|
||||||
subtle::CtOption,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "rand_core")]
|
#[cfg(feature = "rand_core")]
|
||||||
use {
|
use {
|
||||||
core::convert::Infallible,
|
core::convert::Infallible,
|
||||||
|
|
@ -1169,86 +1162,6 @@ impl Debug for RistrettoPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
// group traits
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Use the full trait path to avoid Group::identity overlapping Identity::identity in the
|
|
||||||
// rest of the module (e.g. tests).
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl group::Group for RistrettoPoint {
|
|
||||||
type Scalar = Scalar;
|
|
||||||
|
|
||||||
fn try_from_rng<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
|
|
||||||
// NOTE: this is duplicated due to different `rng` bounds
|
|
||||||
let mut uniform_bytes = [0u8; 64];
|
|
||||||
rng.try_fill_bytes(&mut uniform_bytes)?;
|
|
||||||
Ok(RistrettoPoint::from_uniform_bytes(&uniform_bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn identity() -> Self {
|
|
||||||
Identity::identity()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generator() -> Self {
|
|
||||||
constants::RISTRETTO_BASEPOINT_POINT
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_identity(&self) -> Choice {
|
|
||||||
self.ct_eq(&Identity::identity())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn double(&self) -> Self {
|
|
||||||
self + self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl GroupEncoding for RistrettoPoint {
|
|
||||||
type Repr = [u8; 32];
|
|
||||||
|
|
||||||
fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
|
|
||||||
let (s_encoding_is_canonical, s_is_negative, s) =
|
|
||||||
decompress::step_1(&CompressedRistretto(*bytes));
|
|
||||||
|
|
||||||
let s_is_valid = s_encoding_is_canonical & !s_is_negative;
|
|
||||||
|
|
||||||
let (ok, t_is_negative, y_is_zero, res) = decompress::step_2(s);
|
|
||||||
|
|
||||||
CtOption::new(res, s_is_valid & ok & !t_is_negative & !y_is_zero)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
|
|
||||||
// Just use the checked API; the checks we could skip aren't expensive.
|
|
||||||
Self::from_bytes(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_bytes(&self) -> Self::Repr {
|
|
||||||
self.compress().to_bytes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl PrimeGroup for RistrettoPoint {}
|
|
||||||
|
|
||||||
/// Ristretto has a cofactor of 1.
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl CofactorGroup for RistrettoPoint {
|
|
||||||
type Subgroup = Self;
|
|
||||||
|
|
||||||
fn clear_cofactor(&self) -> Self::Subgroup {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_subgroup(self) -> CtOption<Self::Subgroup> {
|
|
||||||
CtOption::new(self, Choice::from(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_torsion_free(&self) -> Choice {
|
|
||||||
Choice::from(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Zeroize traits
|
// Zeroize traits
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
@ -1277,8 +1190,6 @@ mod test {
|
||||||
use crate::edwards::CompressedEdwardsY;
|
use crate::edwards::CompressedEdwardsY;
|
||||||
#[cfg(feature = "rand_core")]
|
#[cfg(feature = "rand_core")]
|
||||||
use getrandom::{SysRng, rand_core::UnwrapErr};
|
use getrandom::{SysRng, rand_core::UnwrapErr};
|
||||||
#[cfg(feature = "group")]
|
|
||||||
use proptest::prelude::*;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
|
@ -1492,57 +1403,6 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[cfg(all(feature = "alloc", feature = "rand_core", feature = "group"))]
|
|
||||||
fn double_and_compress_1024_random_points() {
|
|
||||||
use group::Group;
|
|
||||||
let mut rng = SysRng;
|
|
||||||
|
|
||||||
let mut points: Vec<RistrettoPoint> = (0..1024)
|
|
||||||
.map(|_| RistrettoPoint::try_from_rng(&mut rng).unwrap())
|
|
||||||
.collect();
|
|
||||||
points[500] = <RistrettoPoint as Group>::identity();
|
|
||||||
|
|
||||||
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 = "group")]
|
|
||||||
proptest! {
|
|
||||||
#[test]
|
|
||||||
fn multiply_double_and_compress_random_points(
|
|
||||||
p1 in any::<[u8; 64]>(),
|
|
||||||
p2 in any::<[u8; 64]>(),
|
|
||||||
s1 in any::<[u8; 32]>(),
|
|
||||||
s2 in any::<[u8; 32]>(),
|
|
||||||
) {
|
|
||||||
use group::Group;
|
|
||||||
|
|
||||||
let scalars = [
|
|
||||||
Scalar::from_bytes_mod_order(s1),
|
|
||||||
Scalar::ZERO,
|
|
||||||
Scalar::from_bytes_mod_order(s2),
|
|
||||||
];
|
|
||||||
|
|
||||||
let points = [
|
|
||||||
RistrettoPoint::from_uniform_bytes(&p1),
|
|
||||||
<RistrettoPoint as Group>::identity(),
|
|
||||||
RistrettoPoint::from_uniform_bytes(&p2),
|
|
||||||
];
|
|
||||||
|
|
||||||
let multiplied_points: [_; 3] =
|
|
||||||
core::array::from_fn(|i| scalars[i].div_by_2() * points[i]);
|
|
||||||
let compressed = RistrettoPoint::double_and_compress_batch(&multiplied_points);
|
|
||||||
|
|
||||||
for ((s, P), P2_compressed) in scalars.iter().zip(points).zip(compressed) {
|
|
||||||
prop_assert_eq!(P2_compressed, (s * P).compress());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(all(feature = "alloc", feature = "rand_core"))]
|
#[cfg(all(feature = "alloc", feature = "rand_core"))]
|
||||||
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
|
fn vartime_precomputed_vs_nonprecomputed_multiscalar() {
|
||||||
|
|
|
||||||
|
|
@ -122,14 +122,6 @@ use core::ops::{Sub, SubAssign};
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
use group::ff::{Field, FromUniformBytes, PrimeField};
|
|
||||||
#[cfg(feature = "group-bits")]
|
|
||||||
use group::ff::{FieldBits, PrimeFieldBits};
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
use rand_core::TryRng;
|
|
||||||
|
|
||||||
#[cfg(feature = "rand_core")]
|
#[cfg(feature = "rand_core")]
|
||||||
use rand_core::CryptoRng;
|
use rand_core::CryptoRng;
|
||||||
|
|
||||||
|
|
@ -1244,141 +1236,6 @@ impl UnpackedScalar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl Field for Scalar {
|
|
||||||
const ZERO: Self = Self::ZERO;
|
|
||||||
const ONE: Self = Self::ONE;
|
|
||||||
|
|
||||||
fn try_from_rng<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
|
|
||||||
// NOTE: this is duplicated due to different `rng` bounds
|
|
||||||
let mut scalar_bytes = [0u8; 64];
|
|
||||||
rng.try_fill_bytes(&mut scalar_bytes)?;
|
|
||||||
Ok(Self::from_bytes_mod_order_wide(&scalar_bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn square(&self) -> Self {
|
|
||||||
self * self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn double(&self) -> Self {
|
|
||||||
self + self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invert(&self) -> CtOption<Self> {
|
|
||||||
CtOption::new(self.invert(), !self.is_zero())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
|
|
||||||
#[allow(unused_qualifications)]
|
|
||||||
group::ff::helpers::sqrt_ratio_generic(num, div)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sqrt(&self) -> CtOption<Self> {
|
|
||||||
#[allow(unused_qualifications)]
|
|
||||||
group::ff::helpers::sqrt_tonelli_shanks(
|
|
||||||
self,
|
|
||||||
[
|
|
||||||
0xcb02_4c63_4b9e_ba7d,
|
|
||||||
0x029b_df3b_d45e_f39a,
|
|
||||||
0x0000_0000_0000_0000,
|
|
||||||
0x0200_0000_0000_0000,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl PrimeField for Scalar {
|
|
||||||
type Repr = [u8; 32];
|
|
||||||
|
|
||||||
fn from_repr(repr: Self::Repr) -> CtOption<Self> {
|
|
||||||
Self::from_canonical_bytes(repr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_repr_vartime(repr: Self::Repr) -> Option<Self> {
|
|
||||||
// Check that the high bit is not set
|
|
||||||
if (repr[31] >> 7) != 0u8 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let candidate = Scalar { bytes: repr };
|
|
||||||
|
|
||||||
if candidate == candidate.reduce() {
|
|
||||||
Some(candidate)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_repr(&self) -> Self::Repr {
|
|
||||||
self.to_bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_odd(&self) -> Choice {
|
|
||||||
Choice::from(self.as_bytes()[0] & 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
const MODULUS: &'static str =
|
|
||||||
"0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed";
|
|
||||||
const NUM_BITS: u32 = 253;
|
|
||||||
const CAPACITY: u32 = 252;
|
|
||||||
|
|
||||||
const TWO_INV: Self = Self {
|
|
||||||
bytes: [
|
|
||||||
0xf7, 0xe9, 0x7a, 0x2e, 0x8d, 0x31, 0x09, 0x2c, 0x6b, 0xce, 0x7b, 0x51, 0xef, 0x7c,
|
|
||||||
0x6f, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x08,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const MULTIPLICATIVE_GENERATOR: Self = Self {
|
|
||||||
bytes: [
|
|
||||||
2, 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,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const S: u32 = 2;
|
|
||||||
const ROOT_OF_UNITY: Self = Self {
|
|
||||||
bytes: [
|
|
||||||
0xd4, 0x07, 0xbe, 0xeb, 0xdf, 0x75, 0x87, 0xbe, 0xfe, 0x83, 0xce, 0x42, 0x53, 0x56,
|
|
||||||
0xf0, 0x0e, 0x7a, 0xc2, 0xc1, 0xab, 0x60, 0x6d, 0x3d, 0x7d, 0xe7, 0x81, 0x79, 0xe0,
|
|
||||||
0x10, 0x73, 0x4a, 0x09,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const ROOT_OF_UNITY_INV: Self = Self {
|
|
||||||
bytes: [
|
|
||||||
0x19, 0xcc, 0x37, 0x71, 0x3a, 0xed, 0x8a, 0x99, 0xd7, 0x18, 0x29, 0x60, 0x8b, 0xa3,
|
|
||||||
0xee, 0x05, 0x86, 0x3d, 0x3e, 0x54, 0x9f, 0x92, 0xc2, 0x82, 0x18, 0x7e, 0x86, 0x1f,
|
|
||||||
0xef, 0x8c, 0xb5, 0x06,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const DELTA: Self = Self {
|
|
||||||
bytes: [
|
|
||||||
16, 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,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group-bits")]
|
|
||||||
impl PrimeFieldBits for Scalar {
|
|
||||||
type ReprBits = [u8; 32];
|
|
||||||
|
|
||||||
fn to_le_bits(&self) -> FieldBits<Self::ReprBits> {
|
|
||||||
self.to_repr().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn char_le_bits() -> FieldBits<Self::ReprBits> {
|
|
||||||
constants::BASEPOINT_ORDER.to_bytes().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
impl FromUniformBytes<64> for Scalar {
|
|
||||||
fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
|
|
||||||
Scalar::from_bytes_mod_order_wide(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read one or more u64s stored as little endian bytes.
|
/// Read one or more u64s stored as little endian bytes.
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// ## Panics
|
||||||
|
|
@ -2031,56 +1888,6 @@ pub(crate) mod test {
|
||||||
assert_eq!(sx + s1, Scalar::from(x + 1));
|
assert_eq!(sx + s1, Scalar::from(x + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
#[test]
|
|
||||||
fn ff_constants() {
|
|
||||||
assert_eq!(Scalar::from(2u64) * Scalar::TWO_INV, Scalar::ONE);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
Scalar::ROOT_OF_UNITY * Scalar::ROOT_OF_UNITY_INV,
|
|
||||||
Scalar::ONE,
|
|
||||||
);
|
|
||||||
|
|
||||||
// ROOT_OF_UNITY^{2^s} mod m == 1
|
|
||||||
assert_eq!(
|
|
||||||
Scalar::ROOT_OF_UNITY.pow(&[1u64 << Scalar::S, 0, 0, 0]),
|
|
||||||
Scalar::ONE,
|
|
||||||
);
|
|
||||||
|
|
||||||
// DELTA^{t} mod m == 1
|
|
||||||
assert_eq!(
|
|
||||||
Scalar::DELTA.pow(&[
|
|
||||||
0x9604_98c6_973d_74fb,
|
|
||||||
0x0537_be77_a8bd_e735,
|
|
||||||
0x0000_0000_0000_0000,
|
|
||||||
0x0400_0000_0000_0000,
|
|
||||||
]),
|
|
||||||
Scalar::ONE,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "group")]
|
|
||||||
#[test]
|
|
||||||
fn ff_impls() {
|
|
||||||
assert!(bool::from(Scalar::ZERO.is_even()));
|
|
||||||
assert!(bool::from(Scalar::ONE.is_odd()));
|
|
||||||
assert!(bool::from(Scalar::from(2u64).is_even()));
|
|
||||||
assert!(bool::from(Scalar::DELTA.is_even()));
|
|
||||||
|
|
||||||
assert!(bool::from(Field::invert(&Scalar::ZERO).is_none()));
|
|
||||||
assert_eq!(Field::invert(&X).unwrap(), XINV);
|
|
||||||
|
|
||||||
let x_sq = X.square();
|
|
||||||
// We should get back either the positive or negative root.
|
|
||||||
assert!([X, -X].contains(&x_sq.sqrt().unwrap()));
|
|
||||||
|
|
||||||
assert_eq!(Scalar::from_repr_vartime(X.to_repr()), Some(X));
|
|
||||||
assert_eq!(Scalar::from_repr_vartime([0xff; 32]), None);
|
|
||||||
|
|
||||||
assert_eq!(Scalar::from_repr(X.to_repr()).unwrap(), X);
|
|
||||||
assert!(bool::from(Scalar::from_repr([0xff; 32]).is_none()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn test_read_le_u64_into_should_panic_on_bad_input() {
|
fn test_read_le_u64_into_should_panic_on_bad_input() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue